fix: verify latest deployed bindings before hosted operator writes [skip ci]

This commit is contained in:
Forge
2026-09-22 21:24:42 +00:00
parent 2b9ec85df6
commit c9b63f5610
3 changed files with 28 additions and 2 deletions
+4 -1
View File
@@ -1,5 +1,5 @@
import fs from 'node:fs';import os from 'node:os';import path from 'node:path';import assert from 'node:assert/strict';
import {reviewedConfig,checkVersion} from './hosted-ops.mjs';import {hash} from './official.mjs';
import {reviewedConfig,checkVersion,latestDeployment} from './hosted-ops.mjs';import {hash} from './official.mjs';
const dir=fs.mkdtempSync(path.join(os.tmpdir(),'hosted-ops-')),file=path.join(dir,'config.json');
const c={account_id:'a'.repeat(32),name:'codegraph-marketplace-preview-test',routes:[],vars:{PUBLISHING_ENABLED:'false'},d1_databases:[{binding:'DB',database_name:'codegraph-marketplace-preview-test',database_id:'11111111-1111-1111-1111-111111111111',remote:true}],r2_buckets:[{binding:'PACKAGES',bucket_name:'codegraph-marketplace-preview-test',remote:true}]};
let count=0;function saved(v){const raw=JSON.stringify(v);fs.writeFileSync(file,raw);return hash(raw);}
@@ -7,4 +7,7 @@ try{assert.equal(reviewedConfig(file,saved(c)).account_id,c.account_id);count++;
for(const change of [x=>x.vars.PUBLISHING_ENABLED='true',x=>x.d1_databases[0].remote=false,x=>x.r2_buckets[0].remote=false,x=>x.d1_databases[0].database_name='codegraph-telemetry',x=>x.d1_databases[0].database_id='00000000-0000-0000-0000-000000000000',x=>x.routes.push('example.com/*')]){const v=structuredClone(c);change(v);assert.throws(()=>reviewedConfig(file,saved(v)));count++;}
const version={resources:{bindings:[{name:'DB',type:'d1',id:c.d1_databases[0].database_id},{name:'PACKAGES',type:'r2_bucket',bucket_name:c.r2_buckets[0].bucket_name},{name:'PUBLISHING_ENABLED',type:'plain_text',text:'false'},{name:'ASSETS',type:'assets'}]}};checkVersion(c,version);count++;
for(const change of [x=>x.resources.bindings[0].id='other',x=>x.resources.bindings[1].bucket_name='other',x=>x.resources.bindings[2].text='true',x=>x.resources.bindings.push({name:'OTHER',type:'service'})]){const v=structuredClone(version);change(v);assert.throws(()=>checkVersion(c,v));count++;}
const old={id:'old',created_on:'2026-09-22T17:00:00Z'},current={id:'new',created_on:'2026-09-22T21:00:00Z'};
for(const order of [[old,current],[current,old]]){assert.equal(latestDeployment(order).id,'new');count++;}
for(const invalid of [[],[{}],[old,{...old,id:'tie'}]]){assert.throws(()=>latestDeployment(invalid));count++;}
console.log(JSON.stringify({passed:count,scope:'operator admission/config/live-binding guards; no remote calls'}));}finally{fs.rmSync(dir,{recursive:true,force:true});}
+7 -1
View File
@@ -17,6 +17,12 @@ export function checkVersion(c,version) {
const b=version.resources?.bindings||[];
if(!b.some(x=>x.name==='DB'&&x.type==='d1'&&(x.id||x.database_id)===c.d1_databases[0].database_id)||!b.some(x=>x.name==='PACKAGES'&&x.type==='r2_bucket'&&x.bucket_name===c.r2_buckets[0].bucket_name)||!b.some(x=>x.name==='PUBLISHING_ENABLED'&&x.text==='false')||b.some(x=>!['DB','PACKAGES','PUBLISHING_ENABLED','ASSETS'].includes(x.name)))throw Error('Live deployment bindings/publication state differ from reviewed target');
}
export function latestDeployment(deployments) {
if(!Array.isArray(deployments)||!deployments.length||deployments.some(x=>!Number.isFinite(Date.parse(x.created_on))))throw Error('Cannot establish current deployment timestamp');
const ordered=[...deployments].sort((a,b)=>Date.parse(b.created_on)-Date.parse(a.created_on));
if(ordered[1]&&Date.parse(ordered[0].created_on)===Date.parse(ordered[1].created_on))throw Error('Ambiguous current deployment');
return ordered[0];
}
export async function connect(configPath,configHash,{detached=false}={}) {
const c=reviewedConfig(configPath,configHash);
const cli=path.join(here,'node_modules/wrangler/bin/wrangler.js');
@@ -26,7 +32,7 @@ export async function connect(configPath,configHash,{detached=false}={}) {
try{deployments=command('deployments','list');}catch(e){if(!detached||!String(e.stderr).includes('10007'))throw Error('Cannot verify live deployment; no binding operation started');deployments=[];}
let version;
if(detached){if(!/-restore(?:-|$)/.test(c.name)||deployments.length)throw Error('Restore must use a new detached restore Worker name');}
else {const current=deployments[0];if(current?.versions?.length!==1||current.versions[0].percentage!==100)throw Error('Require one fully deployed version');version=command('versions','view',current.versions[0].version_id);checkVersion(c,version);}
else {const current=latestDeployment(deployments);if(current?.versions?.length!==1||current.versions[0].percentage!==100)throw Error('Require one fully deployed version');version=command('versions','view',current.versions[0].version_id);checkVersion(c,version);}
const proxy=await getPlatformProxy({configPath,remoteBindings:true,persist:false});
return {c,db:proxy.env.DB,bucket:proxy.env.PACKAGES,version,close:()=>proxy.dispose()};
}
@@ -0,0 +1,17 @@
// Finish only the interrupted race/final-read checks; verify earlier receipts without republishing 8 MiB.
const fs=require('node:fs'),path=require('node:path'),assert=require('node:assert/strict');
const {generateKeyPairSync,sign,randomUUID,createHash}=require('node:crypto');
const [source,destination]=process.argv.slice(2),raw=fs.readFileSync(source),prior=JSON.parse(raw),origin=process.env.HOSTED_REGISTRY;
assert.equal(origin,prior.origin);assert.match(origin||'',/^https:\/\/[a-z0-9.-]+\.workers\.dev$/);
const hash=b=>createHash('sha256').update(b).digest('hex');
(async()=>{
assert.equal(prior.requests.length,11);for(const r of prior.requests)assert.equal(r.status,r.expected??200);
const listing=prior.requests[0].result;assert.equal(prior.requests[0].status,201);
for(const r of prior.requests.slice(1,4)){assert.equal(r.bytes,8388608);assert.equal(r.sha256,listing.integrity);}
assert.match(prior.requests[4].result.error,/exceeds 8 MiB/);assert.match(prior.requests[5].result.error,/Official/);assert.match(prior.requests[6].result.error,/signature/);assert.match(prior.requests[7].result.error,/Invalid extension package/);assert.match(prior.requests[8].result.error,/another publisher/);assert.match(prior.requests[9].result.error,/immutable/);assert.equal(prior.requests[10].status,403);
const id='race-resume-'+Date.now().toString(36),bytes=Buffer.from(JSON.stringify({format:'codegraph-extension-1',package:{name:'@preview/'+id,version:'1.0.0',main:'index.cjs',codegraph:{id,apiVersion:1,capabilities:['frameworks']}},files:{'index.cjs':'module.exports=()=>({frameworks:[]});'}}));
const requests=await Promise.all([1,2].map(async()=>{const key=generateKeyPairSync('ec',{namedCurve:'prime256v1'}),payload=JSON.stringify({name:'Hosted race fixture',description:'Disposable concurrency acceptance',publisher:'Preview validation',readme:'Test fixture. Not a recommended extension.',source:'https://github.com/colbymchenry/codegraph',artifact:bytes.toString('base64'),timestamp:Date.now(),nonce:randomUUID()}),body={payload,publicKey:key.publicKey.export({format:'jwk'}),signature:sign('sha256',Buffer.from(payload),{key:key.privateKey,dsaEncoding:'ieee-p1363'}).toString('base64')},start=new Date().toISOString(),r=await fetch(origin+'/api/publish',{method:'POST',body:JSON.stringify(body)});return{start,status:r.status,result:await r.json()};}));assert.deepEqual(requests.map(r=>r.status).sort(),[201,400]);
const race=await(await fetch(origin+'/api/extensions/'+id)).json();assert.equal(race.length,1);assert.equal(race[0].publisherId,requests.find(r=>r.status===201).result.publisherId);assert.equal(hash(Buffer.from(await(await fetch(origin+'/api/download/'+id+'/1.0.0')).arrayBuffer())),hash(bytes));
const versions=await(await fetch(origin+'/api/extensions/'+listing.id)).json();assert.deepEqual(versions,[listing]);const r=await fetch(origin+'/api/download/'+listing.id+'/1.0.0');assert.equal(r.status,200);const downloaded=Buffer.from(await r.arrayBuffer());assert.equal(downloaded.length,8388608);assert.equal(hash(downloaded),listing.integrity);
const result={origin,source,sourceSha256:hash(raw),reusedRequestCount:prior.requests.length,requests,large:{id:listing.id,bytes:downloaded.length,sha256:listing.integrity},checks:['all 11 interrupted-attempt response receipts verified','actual concurrent provider ownership/version claim has exactly one winner','all rejected requests retained original catalog and 8 MiB bytes'],success:true};fs.mkdirSync(path.dirname(destination),{recursive:true});fs.writeFileSync(destination,JSON.stringify(result,null,2));console.log(JSON.stringify(result));
})().catch(e=>{console.error(e);process.exitCode=1;});