feat: add reviewed official Drupal registry operator

This commit is contained in:
Forge
2026-09-22 12:29:38 +00:00
parent 55fb9796f9
commit 5d40696905
12 changed files with 275 additions and 3 deletions
+2 -1
View File
@@ -2,6 +2,7 @@
// No administrative HTTP endpoint is shipped. Remote export/restore steps are in cloudflare-hosting.md.
import fs from 'node:fs/promises';
import path from 'node:path';
import {validateOfficialListing} from './official.mjs';
import {createHash} from 'node:crypto';
import {createRequire} from 'node:module';
const require=createRequire(import.meta.url),{parsePackage}=require('../../dist/plugins/package');
@@ -12,7 +13,7 @@ function check(snapshot,objects){
const owners=new Map(snapshot.tables.extensions.map(r=>[r.id,r.publisher]));
for(const row of snapshot.tables.releases){
const listing=JSON.parse(row.listing),bytes=objects.get(row.integrity),p=parsePackage(bytes).package;
if(hash(bytes)!==row.integrity||bytes.length!==row.size||row.object_key!=='packages/sha256/'+row.integrity||p.codegraph.id!==row.id||p.version!==row.version||owners.get(row.id)!==row.publisher||listing.publisherId!==row.publisher||listing.integrity!==row.integrity||listing.id!==row.id||listing.version!==row.version||listing.official!==false||listing.apiVersion!==p.codegraph.apiVersion||listing.engines!==(p.codegraph.engines??'*')||JSON.stringify(listing.capabilities)!==JSON.stringify(p.codegraph.capabilities))throw Error('Backup artifact, ownership or listing mismatch');
if(hash(bytes)!==row.integrity||bytes.length!==row.size||row.object_key!=='packages/sha256/'+row.integrity||p.codegraph.id!==row.id||p.version!==row.version||owners.get(row.id)!==row.publisher||listing.publisherId!==row.publisher||listing.integrity!==row.integrity||listing.id!==row.id||listing.version!==row.version||(listing.official!==false&&!validateOfficialListing(listing,bytes))||listing.apiVersion!==p.codegraph.apiVersion||listing.engines!==(p.codegraph.engines??'*')||JSON.stringify(listing.capabilities)!==JSON.stringify(p.codegraph.capabilities))throw Error('Backup artifact, ownership or listing mismatch');
}
for(const id of owners.keys())if(!snapshot.tables.releases.some(r=>r.id===id))throw Error('Backup has orphan ownership');
}
+1
View File
@@ -14,5 +14,6 @@ export async function startLocal({state,testing=false,boundary,port=0,publishing
const exists=await db.prepare("SELECT name FROM sqlite_master WHERE name='registry_meta'").first();
if(!exists&&!initialize){await mf.dispose();throw Error('Source registry is not initialized; verify the source state path before backup');}
if(!exists)for(const line of fs.readFileSync(path.join(root,'migrations/0001_registry.sql'),'utf8').split('\n').filter(Boolean))await db.exec(line);
if(initialize&&!await db.prepare("SELECT value FROM registry_meta WHERE key='official_operator'").first())await db.batch(fs.readFileSync(path.join(root,'migrations/0002_official_operator.sql'),'utf8').split('\n').filter(Boolean).map(sql=>db.prepare(sql)));
return {mf,db,bucket:await mf.getR2Bucket('PACKAGES'),port:Number((await mf.ready).port),close:()=>mf.dispose()};
}
@@ -0,0 +1,3 @@
DROP TRIGGER release_owner;
CREATE TRIGGER release_owner BEFORE INSERT ON releases BEGIN INSERT OR IGNORE INTO extensions(id,publisher) VALUES(NEW.id,NEW.publisher); SELECT CASE WHEN (SELECT publisher FROM extensions WHERE id=NEW.id) != NEW.publisher THEN RAISE(ABORT,'Extension id belongs to another publisher') END; END;
INSERT INTO registry_meta(key,value) VALUES('official_operator','1');
+34
View File
@@ -0,0 +1,34 @@
import fs from 'node:fs';
import path from 'node:path';
import {createRequire} from 'node:module';
import {makePlan,validatePlan,validateTarget,importOfficial,hash} from './official.mjs';
const require=createRequire(import.meta.url),engineVersion=require('../../package.json').version;
const [action,...args]=process.argv.slice(2);
async function main() {
if(action==='inspect-local'&&args.length===1) {
const state=path.resolve(args[0]);if(!fs.existsSync(state))throw Error('Local state does not exist');
const {startLocal}=await import('./local.mjs');const server=await startLocal({state,initialize:false});
try {console.log(JSON.stringify({mode:'local',state,registryId:await server.db.prepare("SELECT value FROM registry_meta WHERE key='id'").first('value'),engineVersion},null,2));}finally{await server.close();}return;
}
if(action==='plan'&&args.length===3) {
const [targetPath,artifactPath,out]=args,artifact=path.resolve(artifactPath);
const plan=makePlan(fs.readFileSync(artifact),JSON.parse(fs.readFileSync(targetPath,'utf8')),artifact);
fs.writeFileSync(out,JSON.stringify(plan,null,2)+'\n',{flag:'wx'});
console.log(JSON.stringify({action:'review-plan',path:path.resolve(out),sha256:hash(fs.readFileSync(out)),target:plan.target,id:plan.listing.id,version:plan.listing.version,integrity:plan.listing.integrity}));return;
}
if(action==='apply'&&args.length===3&&args[1]==='--confirm-plan-sha256') {
const raw=fs.readFileSync(args[0]);if(!/^[a-f0-9]{64}$/.test(args[2])||hash(raw)!==args[2])throw Error('Review the exact plan and confirm its SHA-256 before applying');
const plan=JSON.parse(raw),bytes=fs.readFileSync(plan.artifact);validatePlan(plan,bytes);validateTarget(plan.target);
if(plan.target.mode==='local') {
const {startLocal}=await import('./local.mjs');const server=await startLocal({state:plan.target.state,initialize:false});
try {console.log(JSON.stringify(await importOfficial(server.db,server.bucket,plan,bytes)));}finally{await server.close();}
} else {
const {remoteBindings}=await import('./official-remote.mjs');
const bindings=remoteBindings(plan.target,{d1Token:process.env.CLOUDFLARE_API_TOKEN,r2AccessKeyId:process.env.CODEGRAPH_R2_ACCESS_KEY_ID,r2SecretAccessKey:process.env.CODEGRAPH_R2_SECRET_ACCESS_KEY});
console.log(JSON.stringify(await importOfficial(bindings.db,bindings.bucket,plan,bytes)));
}
return;
}
throw Error('Usage: official-cli.mjs inspect-local STATE | plan TARGET.json ARTIFACT.cgext NEW_PLAN.json | apply PLAN.json --confirm-plan-sha256 HASH');
}
main().catch(error=>{console.error(error.message);process.exitCode=1;});
@@ -0,0 +1,20 @@
{
"format": "codegraph-official-policy-1",
"publisherId": "codegraph",
"publisher": "CodeGraph",
"releases": [{
"id": "drupal",
"version": "0.1.0",
"packageName": "@colbymchenry/codegraph-drupal",
"sha256": "e5015747d02fe50d6af607b6c44f1db9cf7969a0070866ed03c7643377a459c8",
"bytes": 289167,
"repository": "https://github.com/colbymchenry/codegraph",
"sourceRevision": "37d4dd837120c1d56316c3cc65b6587b743a9112",
"sourcePath": "extensions/drupal/index.cjs",
"sourceSha256": "eb7688957a14edd36efd8c109283a7355ceb7dd8199987fe3264c3f37489e841",
"entrySha256": "0e6d117bab017fd4b0a6f09fe2289bf42c4b597548228be244b5729f7a022dd8",
"name": "Drupal",
"description": "Follow Drupal routes, services, hooks, plugins and events through your codebase.",
"readme": "Official CodeGraph Drupal extension preview. Routes and forms connect to their handlers; services connect to implementations and explicit injections; literal hooks and events connect to declared implementations.\n\nInstalling replaces the built-in Drupal resolver for this project. Requires CodeGraph >=1.6.0 <2 with extension support.\n\nComputed identifiers, missing external dependencies, ambiguous classes and unknown entity handlers remain unresolved. Broader Drupal coverage and performance review remain open."
}]
}
@@ -0,0 +1,38 @@
// Authenticated operator-only adapter; never included in the public Worker.
// Credentials are consumed only by an explicitly confirmed remote apply command.
import {AwsClient} from 'aws4fetch';
export function remoteBindings(target,credentials,transport=fetch) {
if(!credentials.d1Token||!credentials.r2AccessKeyId||!credentials.r2SecretAccessKey)throw Error('Remote apply requires privately configured D1 API and bucket-scoped R2 credentials');
const queryUrl=`https://api.cloudflare.com/client/v4/accounts/${target.accountId}/d1/database/${target.databaseId}/query`;
let verified;
async function verifyBindings() {
verified??=(async()=>{
const response=await transport(`https://api.cloudflare.com/client/v4/accounts/${target.accountId}/workers/scripts/${target.workerName}/settings`,{headers:{Authorization:'Bearer '+credentials.d1Token},signal:AbortSignal.timeout(30000)});
if(!response.ok)throw Error('Cannot verify deployed Worker bindings; no import performed');
const data=await response.json(),bindings=data.result?.bindings;
if(!data.success||!Array.isArray(bindings)||!bindings.some(b=>b.name==='DB'&&b.type==='d1'&&b.id===target.databaseId)||!bindings.some(b=>b.name==='PACKAGES'&&b.type==='r2_bucket'&&b.bucket_name===target.bucket))throw Error('Reviewed target does not match deployed Worker D1/R2 bindings; no import performed');
})();
return verified;
}
async function query(sql,params=[]) {
await verifyBindings();
const response=await transport(queryUrl,{method:'POST',headers:{Authorization:'Bearer '+credentials.d1Token,'Content-Type':'application/json'},body:JSON.stringify({sql,params}),signal:AbortSignal.timeout(30000)});
if(!response.ok)throw Error('Authenticated D1 query failed (HTTP '+response.status+'); inspect target/permissions');
const data=await response.json();
if(!data.success||data.result?.length!==1||!data.result[0].success)throw Error('D1 statement rejected; inspect registry conflicts/schema before retrying');
return data.result[0];
}
function prepare(sql,params=[]) {return {bind:(...values)=>prepare(sql,values),all:()=>query(sql,params),run:()=>query(sql,params),first:async column=>{const row=(await query(sql,params)).results[0];return row?(column?row[column]:row):null;}};}
const signer=new AwsClient({accessKeyId:credentials.r2AccessKeyId,secretAccessKey:credentials.r2SecretAccessKey,service:'s3',region:'auto',retries:0});
async function object(method,key,body) {
await verifyBindings();
if(!/^packages\/sha256\/[a-f0-9]{64}$/.test(key))throw Error('Unexpected official object key');
const url=`https://${target.accountId}.r2.cloudflarestorage.com/${target.bucket}/${key}`;
const signed=await signer.sign(url,{method,body,headers:method==='PUT'?{'If-None-Match':'*','Content-Type':'application/vnd.codegraph.extension+json'}:{}});
return transport(signed,{signal:AbortSignal.timeout(30000)});
}
return {db:{prepare},bucket:{
async get(key){const response=await object('GET',key);if(response.status===404)return null;if(!response.ok)throw Error('Authenticated R2 read failed (HTTP '+response.status+')');return {arrayBuffer:()=>response.arrayBuffer()};},
async put(key,bytes,options){if(options?.onlyIf?.etagDoesNotMatch!=='*')throw Error('R2 official import requires conditional creation');const response=await object('PUT',key,bytes);if(response.status===412)return null;if(!response.ok)throw Error('Authenticated R2 conditional upload failed (HTTP '+response.status+')');return {};}
}};
}
+47
View File
@@ -0,0 +1,47 @@
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import assert from 'node:assert/strict';
import {spawn,execFileSync} from 'node:child_process';
import {generateKeyPairSync,sign,randomUUID} from 'node:crypto';
import {startLocal} from './local.mjs';
import {makePlan,importOfficial,hash} from './official.mjs';
import {backupRegistry,restoreRegistry} from './backup.mjs';
import {remoteBindings} from './official-remote.mjs';
const root=path.resolve('../..'),out=path.resolve(process.env.OFFICIAL_OUTPUT||root+'/.qa/official/operator');fs.mkdirSync(out,{recursive:true});
const lab=fs.mkdtempSync(path.join(os.tmpdir(),'cg-official-')),checks=[],commands=[],services=[];
const artifact=path.join(root,'dist/extensions/drupal.cgext'),bytes=fs.readFileSync(artifact);
const keys=generateKeyPairSync('ec',{namedCurve:'prime256v1'});
const servicesStart=async name=>{const state=path.join(lab,name),s=await startLocal({state});services.push(s);s.state=state;s.target={mode:'local',state,registryId:await s.db.prepare("SELECT value FROM registry_meta WHERE key='id'").first('value'),engineVersion:'1.6.0'};return s;};
function pass(name){checks.push(name);fs.writeFileSync(path.join(out,'progress.json'),JSON.stringify({checks,commands},null,2));console.log('PASS',name);}
function signed(artifact,extra={}){const payload=JSON.stringify({name:'Community',description:'Test',publisher:'Community',readme:'Test',source:'https://example.com/source',artifact:artifact.toString('base64'),timestamp:Date.now(),nonce:randomUUID(),...extra});return {payload,publicKey:keys.publicKey.export({format:'jwk'}),signature:sign('sha256',Buffer.from(payload),{key:keys.privateKey,dsaEncoding:'ieee-p1363'}).toString('base64')};}
async function submit(s,body,status){const r=await fetch('http://127.0.0.1:'+s.port+'/api/publish',{method:'POST',body:JSON.stringify(body)});assert.equal(r.status,status,await r.clone().text());return r.json();}
async function cli(args,exit=0){const r=await new Promise((resolve,reject)=>{const c=spawn(process.execPath,['official-cli.mjs',...args],{timeout:30000});let stdout='',stderr='';c.stdout.on('data',b=>stdout+=b);c.stderr.on('data',b=>stderr+=b);c.on('error',reject);c.on('close',code=>resolve({exit:code,stdout,stderr}));});const log='command-'+(commands.length+1)+'.log';fs.writeFileSync(path.join(out,log),r.stdout+r.stderr);commands.push({command:[process.execPath,'official-cli.mjs',...args],exit:r.exit,sha256:hash(r.stdout+r.stderr),log});assert.equal(r.exit,exit,r.stderr);return r.stdout;}
try{
const s=await servicesStart('main'),plan=makePlan(bytes,s.target,artifact);
const unsupported=JSON.parse(bytes);unsupported.package.codegraph.apiVersion=9;assert.throws(()=>makePlan(Buffer.from(JSON.stringify(unsupported)),s.target,artifact),/unsupported API/);pass('unsupported extension API rejected before writes');
assert.throws(()=>makePlan(Buffer.from('{}'),s.target,artifact),/Invalid/);pass('malformed package rejected before writes');
assert.throws(()=>makePlan(bytes,{...s.target,engineVersion:'9.0.0'},artifact),/requires CodeGraph/);pass('incompatible target engine rejected before writes');
assert.throws(()=>makePlan(Buffer.concat([bytes,Buffer.from(' ')]),s.target,artifact),/integrity/);pass('tampered but valid JSON package rejected by reviewed provenance pin');
await assert.rejects(()=>importOfficial(s.db,s.bucket,{...plan,listing:{...plan.listing,name:'forged'}},bytes),/plan changed/);pass('edited publication plan rejected');
const wrong=makePlan(bytes,{...s.target,registryId:'0'.repeat(32)},artifact);await assert.rejects(()=>importOfficial(s.db,s.bucket,wrong,bytes),/identity/);pass('wrong registry identity rejected');
const result=await importOfficial(s.db,s.bucket,plan,bytes);assert.equal(result.status,'imported');assert.equal(result.listing.publisherId,'codegraph');assert.equal(result.listing.official,true);assert.deepEqual(Buffer.from(await(await s.bucket.get('packages/sha256/'+plan.listing.integrity)).arrayBuffer()),bytes);pass('official identity provenance and exact bytes published through real D1/R2');
assert.equal((await importOfficial(s.db,s.bucket,makePlan(bytes,s.target,artifact),bytes)).status,'unchanged');pass('safe repeated plan is idempotent and retains original listing');
const other=JSON.parse(bytes);other.package.codegraph.id='unofficial';other.package.name='unofficial';const community=Buffer.from(JSON.stringify(other));
for(const extra of [{official:true},{publisherId:'codegraph'},{provenance:{revision:'fake'}}])await submit(s,signed(community,extra),400);
const normal=await submit(s,signed(community),201);assert.equal(normal.official,false);assert.notEqual(normal.publisherId,'codegraph');pass('public API rejects official identity spoof while preserving community publication');
await submit(s,signed(bytes),400);pass('community cannot replace reserved official Drupal ownership');
const owner=await servicesStart('owner-conflict');await submit(owner,signed(bytes),201);await assert.rejects(()=>importOfficial(owner.db,owner.bucket,makePlan(bytes,owner.target,artifact),bytes),/ownership conflict/);pass('prior community ownership is not stolen by operator import');await owner.close();
const version=await servicesStart('version-conflict'),vp=makePlan(bytes,version.target,artifact);await version.db.prepare('INSERT INTO releases VALUES(?,?,?,?,?,?,?)').bind('drupal','0.1.0','codegraph',JSON.stringify({...vp.listing,name:'existing immutable listing'}),'packages/sha256/'+vp.listing.integrity,vp.listing.integrity,bytes.length).run();await assert.rejects(()=>importOfficial(version.db,version.bucket,vp,bytes),/version conflict/);pass('existing immutable version metadata conflict is not overwritten');await version.close();
const race=await servicesStart('race'),rp=makePlan(bytes,race.target,artifact);const results=await Promise.all([importOfficial(race.db,race.bucket,rp,bytes),importOfficial(race.db,race.bucket,rp,bytes)]);assert.deepEqual(results.map(r=>r.status).sort(),['imported','unchanged']);pass('concurrent identical official imports converge to one release');await race.close();
const failure=await servicesStart('failure'),fp=makePlan(bytes,failure.target,artifact);await assert.rejects(()=>importOfficial(failure.db,{put:async()=>{throw Error('R2 failure');}},fp,bytes),/R2 failure/);assert.equal(await failure.db.prepare('SELECT count(*) n FROM extensions').first('n'),0);
await failure.db.exec("CREATE TRIGGER reject_official AFTER INSERT ON releases BEGIN SELECT RAISE(ABORT,'fixture D1 failure'); END;");await assert.rejects(()=>importOfficial(failure.db,failure.bucket,fp,bytes));assert.equal(await failure.db.prepare('SELECT count(*) n FROM extensions').first('n'),0);assert.equal(await failure.db.prepare('SELECT count(*) n FROM releases').first('n'),0);await failure.db.exec('DROP TRIGGER reject_official');assert.equal((await importOfficial(failure.db,failure.bucket,fp,bytes)).status,'imported');pass('R2 and D1 failures expose no release or orphan owner; exact retry succeeds');await failure.close();
const key='packages/sha256/'+plan.listing.integrity;await s.bucket.put(key,Buffer.from('tampered'));await assert.rejects(()=>importOfficial(s.db,s.bucket,plan,bytes),/corrupt/);assert.equal(Buffer.from(await(await s.bucket.get(key)).arrayBuffer()).toString(),'tampered');await s.bucket.put(key,bytes);pass('idempotent repeat detects corrupt object and never repairs by silent overwrite');
await backupRegistry(s.db,s.bucket,path.join(lab,'backup'));const restore=await servicesStart('restore');await restoreRegistry(restore.db,restore.bucket,path.join(lab,'backup'));assert.equal((await importOfficial(restore.db,restore.bucket,{...plan,target:{...restore.target,registryId:s.target.registryId}},bytes)).status,'unchanged');pass('official provenance ownership and bytes survive isolated backup restore');await restore.close();
const state=s.state;await s.close();const targetFile=path.join(lab,'target.json');fs.writeFileSync(targetFile,await cli(['inspect-local',state]));const planFile=path.join(lab,'plan.json');await cli(['plan',targetFile,artifact,planFile]);await cli(['apply',planFile,'--confirm-plan-sha256','0'.repeat(64)],1);const digest=hash(fs.readFileSync(planFile));assert.equal(JSON.parse(await cli(['apply',planFile,'--confirm-plan-sha256',digest])).status,'unchanged');pass('explicit CLI target plan hash confirmation and repeat operation work');
// Contract-only transport verification: dummy test credentials, no external requests.
const seen=[];const transport=async(input,init)=>{const request=input instanceof Request?input:new Request(input,init);seen.push({url:request.url,method:request.method,conditional:request.headers.get('If-None-Match')});if(request.url.endsWith('/settings'))return Response.json({success:true,result:{bindings:[{name:'DB',type:'d1',id:'11111111-1111-1111-1111-111111111111'},{name:'PACKAGES',type:'r2_bucket',bucket_name:'fixture'}]}});if(request.url.includes('api.cloudflare.com'))return Response.json({success:true,result:[{success:true,results:[{value:'registry'}],meta:{changes:1}}]});return new Response(bytes);};
const remote=remoteBindings({accountId:'a'.repeat(32),databaseId:'11111111-1111-1111-1111-111111111111',bucket:'fixture',workerName:'fixture-worker'},{d1Token:'dummy',r2AccessKeyId:'dummy',r2SecretAccessKey:'dummy'},transport);assert.equal(await remote.db.prepare('SELECT ? value').bind('registry').first('value'),'registry');await remote.bucket.put(key,bytes,{onlyIf:{etagDoesNotMatch:'*'}});assert.deepEqual(Buffer.from(await(await remote.bucket.get(key)).arrayBuffer()),bytes);assert.equal(seen[2].conditional,'*');pass('remote adapter uses fixed account endpoints and conditional S3 creation (contract only)');
const badRemote=remoteBindings({accountId:'a'.repeat(32),databaseId:'11111111-1111-1111-1111-111111111111',bucket:'wrong-bucket',workerName:'fixture-worker'},{d1Token:'dummy',r2AccessKeyId:'dummy',r2SecretAccessKey:'dummy'},transport);await assert.rejects(()=>badRemote.db.prepare('SELECT 1').first(),/does not match/);pass('remote binding mismatch stops before database or object writes (contract only)');
fs.writeFileSync(path.join(out,'result.json'),JSON.stringify({revision:execFileSync('git',['rev-parse','HEAD'],{encoding:'utf8'}).trim(),dirty:!!execFileSync('git',['status','--porcelain'],{encoding:'utf8'}).trim(),checks,commands,artifactSHA:hash(bytes),artifactBytes:bytes.length,success:true},null,2));
}catch(error){fs.writeFileSync(path.join(out,'failure.json'),JSON.stringify({checks,commands,error:String(error.stack)},null,2));throw error;}finally{await Promise.allSettled(services.map(s=>s.close()));fs.rmSync(lab,{recursive:true,force:true});}
+83
View File
@@ -0,0 +1,83 @@
// Trusted operator domain logic. This module is never imported by the public Worker.
import fs from 'node:fs';
import path from 'node:path';
import {createHash} from 'node:crypto';
import {createRequire} from 'node:module';
const require=createRequire(import.meta.url);
const {parsePackage}=require('../../dist/plugins/package');
const semver=require('semver');
const policy=JSON.parse(fs.readFileSync(new URL('./official-policy.json',import.meta.url),'utf8'));
export const hash=bytes=>createHash('sha256').update(bytes).digest('hex');
export function validateTarget(target) {
if(!target||!['local','remote'].includes(target.mode)||!/^[a-f0-9]{32}$/.test(target.registryId)||!semver.valid(target.engineVersion))throw Error('Target needs mode, exact registryId and valid engineVersion');
if(target.mode==='local'&&(!path.isAbsolute(target.state||'')||!fs.existsSync(target.state)))throw Error('Local target needs an existing absolute state path');
if(target.mode==='remote'&&(!/^[a-f0-9]{32}$/.test(target.accountId)||!/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(target.databaseId)||!/^[-a-z0-9]{3,63}$/.test(target.bucket)||!/^[-a-z0-9]{3,63}$/.test(target.workerName)||/^0[-0]*$/.test(target.databaseId)))throw Error('Remote target needs verified accountId, databaseId, workerName and private bucket');
return target;
}
function approved(bytes,engineVersion) {
const pkg=parsePackage(bytes,engineVersion).package;
const release=policy.releases.find(r=>r.id===pkg.codegraph.id&&r.version===pkg.version);
if(!release)throw Error('No reviewed official policy for this id/version');
if(hash(bytes)!==release.sha256||bytes.length!==release.bytes||pkg.name!==release.packageName)throw Error('Official artifact integrity/provenance does not match reviewed policy');
const entry=JSON.parse(bytes).files[pkg.main];
if(hash(entry)!==release.entrySha256)throw Error('Official entry point provenance mismatch');
return {pkg,release};
}
function listingFor(bytes,engineVersion,publishedAt) {
const {pkg,release:r}=approved(bytes,engineVersion);
return {id:r.id,version:r.version,name:r.name,description:r.description,publisher:policy.publisher,publisherId:policy.publisherId,official:true,
readme:r.readme,source:r.repository+'/tree/'+r.sourceRevision+'/extensions/drupal',apiVersion:pkg.codegraph.apiVersion,engines:pkg.codegraph.engines??'*',capabilities:pkg.codegraph.capabilities,
integrity:r.sha256,publishedAt,provenance:{repository:r.repository,revision:r.sourceRevision,path:r.sourcePath,sourceSha256:r.sourceSha256,entrySha256:r.entrySha256}};
}
export function validateOfficialListing(listing,bytes) {
try {return JSON.stringify(listing)===JSON.stringify(listingFor(bytes,undefined,listing.publishedAt))&&Number.isFinite(Date.parse(listing.publishedAt));}catch{return false;}
}
export function makePlan(bytes,target,artifact,publishedAt=new Date().toISOString()) {
validateTarget(target);
if(!path.isAbsolute(artifact)||!Number.isFinite(Date.parse(publishedAt)))throw Error('Plan needs an absolute artifact path and timestamp');
return {format:'codegraph-official-import-1',target,artifact,bytes:bytes.length,listing:listingFor(bytes,target.engineVersion,publishedAt)};
}
export function validatePlan(plan,bytes) {
const expected=makePlan(bytes,plan.target,plan.artifact,plan.listing?.publishedAt);
if(JSON.stringify(plan)!==JSON.stringify(expected))throw Error('Official import plan changed; regenerate and review it');
return expected;
}
async function verifiedObject(bucket,key,bytes) {
const stored=await bucket.get(key);
if(!stored)throw Error('Official package object missing; no metadata written');
const actual=new Uint8Array(await stored.arrayBuffer());
if(actual.length!==bytes.length||hash(actual)!==hash(bytes))throw Error('Official package object is corrupt; operator repair required, no overwrite');
}
// Remove only server-chosen timestamp when comparing safe repeat requests.
const identity=listing=>JSON.stringify({...listing,publishedAt:undefined});
export async function importOfficial(db,bucket,plan,bytes) {
validatePlan(plan,bytes);
const target=await db.prepare("SELECT key,value FROM registry_meta WHERE key IN ('id','schema','official_operator')").all();
const values=Object.fromEntries(target.results.map(r=>[r.key,r.value]));
if(values.id!==plan.target.registryId||values.schema!=='1'||values.official_operator!=='1')throw Error('Registry identity/schema mismatch; inspect target and apply migration 0002 explicitly');
const l=plan.listing,key='packages/sha256/'+l.integrity;
async function existing() {
const owner=await db.prepare('SELECT publisher FROM extensions WHERE id=?').bind(l.id).first('publisher');
if(owner&&owner!==l.publisherId)throw Error('Official import ownership conflict; existing publisher is never replaced');
const row=await db.prepare('SELECT * FROM releases WHERE id=? AND version=?').bind(l.id,l.version).first();
if(!row)return null;
const actual=JSON.parse(row.listing);
if(row.publisher!==l.publisherId||row.integrity!==l.integrity||row.object_key!==key||row.size!==bytes.length||identity(actual)!==identity(l))throw Error('Official immutable version conflict; no overwrite');
await verifiedObject(bucket,key,bytes);return actual;
}
const prior=await existing();if(prior)return {status:'unchanged',listing:prior};
await bucket.put(key,bytes,{onlyIf:{etagDoesNotMatch:'*'},sha256:l.integrity,httpMetadata:{contentType:'application/vnd.codegraph.extension+json'}});
await verifiedObject(bucket,key,bytes);
try {
// One INSERT and migration-0002's trigger atomically claim ownership + release.
// Expected registry identity is checked again inside the same SQL statement.
const result=await db.prepare("INSERT INTO releases(id,version,publisher,listing,object_key,integrity,size) SELECT ?,?,?,?,?,?,? WHERE (SELECT value FROM registry_meta WHERE key='id')=? AND (SELECT value FROM registry_meta WHERE key='official_operator')='1'")
.bind(l.id,l.version,l.publisherId,JSON.stringify(l),key,l.integrity,bytes.length,plan.target.registryId).run();
if(result.meta.changes===0)throw Error('Registry changed while importing; no metadata written');
}catch(error){
// Includes a concurrent identical import or a lost successful response. Never overwrite.
const completed=await existing();if(completed)return {status:'unchanged',listing:completed};
throw error;
}
return {status:'imported',listing:await existing()};
}
+8
View File
@@ -8,6 +8,7 @@
"name": "codegraph-marketplace-cloudflare",
"version": "0.1.0",
"devDependencies": {
"aws4fetch": "1.0.20",
"esbuild": "0.28.1",
"miniflare": "5.20260921.0-alpha",
"wrangler": "4.136.1"
@@ -1194,6 +1195,13 @@
"dev": true,
"license": "CC0-1.0"
},
"node_modules/aws4fetch": {
"version": "1.0.20",
"resolved": "https://registry.npmjs.org/aws4fetch/-/aws4fetch-1.0.20.tgz",
"integrity": "sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g==",
"dev": true,
"license": "MIT"
},
"node_modules/blake3-wasm": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/blake3-wasm/-/blake3-wasm-2.1.5.tgz",
+3 -2
View File
@@ -10,8 +10,9 @@
"check:access": "wrangler whoami"
},
"devDependencies": {
"wrangler": "4.136.1",
"aws4fetch": "1.0.20",
"esbuild": "0.28.1",
"miniflare": "5.20260921.0-alpha",
"esbuild": "0.28.1"
"wrangler": "4.136.1"
}
}
+1
View File
@@ -30,6 +30,7 @@ export async function validateSubmission(raw:any) {
const key=await crypto.subtle.importKey('jwk',raw.publicKey,{name:'ECDSA',namedCurve:'P-256'},true,['verify']);
if(!await crypto.subtle.verify({name:'ECDSA',hash:'SHA-256'},key,decodeBase64(raw.signature),utf8.encode(raw.payload)))throw Error('Publisher signature is invalid');
const p=JSON.parse(raw.payload);
if(p.official===true||p.publisherId!==undefined||p.provenance!==undefined)throw Error('Official status and publisher identity require the trusted operator path');
if(!Number.isFinite(p.timestamp)||Math.abs(Date.now()-p.timestamp)>600000||typeof p.nonce!=='string'||!p.nonce||p.nonce.length>200)throw Error('Submission expired or invalid nonce');
for(const field of ['name','description','publisher','readme','source','artifact'])if(typeof p[field]!=='string')throw Error('Missing '+field);
if(!p.name.trim()||p.name.length>80||!p.publisher.trim()||p.publisher.length>80||p.description.length>240||p.readme.length>30000)throw Error('Listing fields exceed allowed length');
@@ -0,0 +1,35 @@
// Real local Worker/operator -> browser -> compiled installer -> pinned Drupal corpus.
const fs=require('node:fs'),path=require('node:path'),os=require('node:os'),assert=require('node:assert/strict'),cp=require('node:child_process'),crypto=require('node:crypto');
const {DatabaseSync}=require('node:sqlite');
const {chromium}=require(process.env.PLAYWRIGHT_MODULE||'playwright');
const {CodeGraph}=require('../../dist');
const {ExtensionManager}=require('../../dist/plugins/manager');
const {startExtensionBridge}=require('../../dist/plugins/bridge');
Object.assign(process.env,{CODEGRAPH_TELEMETRY:'0',CODEGRAPH_PARSE_WORKERS:'2',CODEGRAPH_RESOLVE_WORKERS:'0'});
const root=path.resolve(__dirname,'../..'),out=path.resolve(process.env.OFFICIAL_BROWSER_OUTPUT||'.qa/official/browser');fs.mkdirSync(out,{recursive:true});
const lab=fs.mkdtempSync(path.join(os.tmpdir(),'cg-official-browser-')),corpus=path.resolve(process.env.PATHAUTO_CORPUS||'../validation/pathauto'),pin='b97aadf47a37cff25f7d6105c3dade6778fccb47';
const project=path.join(lab,'pathauto'),other=path.join(lab,'untouched'),state=path.join(lab,'registry'),artifact=path.join(root,'dist/extensions/drupal.cgext'),bytes=fs.readFileSync(artifact),checks=[],commands=[];
fs.mkdirSync(project);fs.mkdirSync(other);fs.writeFileSync(path.join(other,'example.php'),'<?php function untouched() {}');
cp.execFileSync('tar',['-x','-C',project],{input:cp.execFileSync('git',['-C',corpus,'archive',pin],{maxBuffer:64*1024*1024})});
const hash=b=>crypto.createHash('sha256').update(b).digest('hex');
function snapshot(){const db=new DatabaseSync(path.join(project,'.codegraph/codegraph.db'),{readOnly:true});try{const nodes=db.prepare('SELECT * FROM nodes ORDER BY id').all().map(({updated_at,...n})=>n),edges=db.prepare('SELECT source,target,kind,metadata,line,col,provenance FROM edges ORDER BY source,target,kind,line,col,metadata').all();return {nodes,edges,pluginEdges:edges.filter(e=>JSON.parse(e.metadata||'{}').synthesizedBy==='drupal'),hash:hash(JSON.stringify({nodes,edges})),config:fs.existsSync(path.join(project,'codegraph.json'))?fs.readFileSync(path.join(project,'codegraph.json'),'utf8'):null};}finally{db.close();}}
function verify(data){const definitions=[['/admin/config/search/path/settings','pathauto.routing.yml','buildForm','src/Form/PathautoSettingsForm.php','Drupal route handler'],['/admin/config/search/path/update_bulk','pathauto.routing.yml','buildForm','src/Form/PathautoBulkUpdateForm.php','Drupal route handler'],['getPunctuationCharacters','src/AliasCleaner.php','pathautoPunctuationCharsAlter','tests/modules/pathauto_custom_punctuation_test/src/Hook/PathautoCustomPunctuationTestHooks.php','Drupal hook pathauto_punctuation_chars_alter'],['PathautoGenerator','src/PathautoGenerator.php','AliasCleaner','src/AliasCleaner.php','Drupal service injection']];for(const [from,file,to,target,label]of definitions){const sources=new Set(data.nodes.filter(n=>n.name===from&&n.file_path===file).map(n=>n.id)),targets=new Set(data.nodes.filter(n=>n.name===to&&n.file_path===target).map(n=>n.id));assert.ok(data.pluginEdges.some(e=>sources.has(e.source)&&targets.has(e.target)&&JSON.parse(e.metadata).label===label),'Missing '+label+': '+from);}return definitions;}
function pass(name){checks.push(name);fs.writeFileSync(path.join(out,'progress.json'),JSON.stringify({checks,commands},null,2));console.log('PASS',name);}
async function cli(args){const command=[path.join(root,'marketplace/cloudflare/official-cli.mjs'),...args];const r=await new Promise((resolve,reject)=>{const c=cp.spawn(process.execPath,command,{timeout:60000});let log='';c.stdout.on('data',b=>log+=b);c.stderr.on('data',b=>log+=b);c.on('error',reject);c.on('close',exit=>resolve({exit,log}));});const log='operator-'+(commands.length+1)+'.log';fs.writeFileSync(path.join(out,log),r.log);commands.push({command:[process.execPath,...command],exit:r.exit,log,sha256:hash(r.log)});assert.equal(r.exit,0,r.log);return r.log;}
let server,bridge,browser,page;
(async()=>{try{
const {startLocal}=await import('../../marketplace/cloudflare/local.mjs');server=await startLocal({state});await server.close();server=null;
const target=path.join(lab,'target.json'),plan=path.join(lab,'plan.json');fs.writeFileSync(target,await cli(['inspect-local',state]));await cli(['plan',target,artifact,plan]);await cli(['apply',plan,'--confirm-plan-sha256',hash(fs.readFileSync(plan))]);
server=await startLocal({state});const origin='http://127.0.0.1:'+server.port;const catalog=await(await fetch(origin+'/api/extensions')).json();assert.equal(catalog.length,1);assert.equal(catalog[0].official,true);assert.equal(catalog[0].publisherId,'codegraph');assert.equal(catalog[0].integrity,hash(bytes));pass('reviewed operator CLI imports actual team Drupal artifact into real Worker D1/R2');
const g=await CodeGraph.init(project);try{const r=await g.indexAll();assert.equal(r.filesErrored,0);}finally{g.close();}assert.equal(snapshot().pluginEdges.length,0);
bridge=await startExtensionBridge([other,project],origin);browser=await chromium.launch({executablePath:process.env.CHROME_PATH||'/opt/google/chrome/chrome',headless:true,args:['--no-sandbox']});page=await browser.newPage({viewport:{width:1440,height:1000}});page.setDefaultTimeout(60000);let popups=0;page.on('popup',()=>popups++);const pageErrors=[];page.on('pageerror',e=>pageErrors.push(e.message));
await page.goto(bridge.connectionUrl);await page.getByRole('button',{name:'Official',exact:true}).click();await page.locator('.extension-card .official').waitFor();assert.equal(await page.locator('.extension-card').count(),1);assert.match(await page.locator('.extension-card .byline').innerText(),/CodeGraph.*OFFICIAL/s);pass('official catalog filter displays trusted CodeGraph Drupal identity');
const popupReady=page.waitForEvent('popup');await page.locator('#connect').click();const popup=await popupReady;await popup.getByRole('button',{name:'Allow connection'}).click();await page.getByText('CodeGraph connected',{exact:true}).waitFor();await page.locator('#project').selectOption('1');await page.getByRole('link',{name:'Drupal',exact:true}).click();await page.locator('.compatibility').filter({hasText:'Selected 0.1.0'}).waitFor();assert.equal(await page.locator('.metadata dd.integrity').first().innerText(),'codegraph');await page.getByRole('button',{name:'Install extension'}).click();await page.waitForFunction(()=>state.snapshot?.jobId===1&&!state.snapshot.busy);assert.equal(await page.evaluate(()=>state.snapshot.error),undefined);assert.equal(popups,1);const installed=snapshot(),flows=verify(installed);assert.ok(!CodeGraph.isInitialized(other));pass('one connection and one Install refresh only selected pinned Drupal project; four real route hook and DI edges verified');
fs.writeFileSync(path.join(out,'graph-proof.json'),JSON.stringify({corpus:'pathauto',revision:pin,artifactSHA:hash(bytes),nodes:installed.nodes.length,edges:installed.edges.length,pluginEdges:installed.pluginEdges.length,hash:installed.hash,expected:flows},null,2));await page.screenshot({path:path.join(out,'desktop-installed.png'),fullPage:true});
const manager=new ExtensionManager(project),key='packages/sha256/'+hash(bytes);await server.bucket.put(key,Buffer.from('tampered'));await assert.rejects(()=>manager.installFromRegistry({registry:origin,id:'drupal',version:'0.1.0',replaces:['drupal']}));assert.equal(snapshot().hash,installed.hash);assert.equal(snapshot().config,installed.config);await server.bucket.put(key,bytes);pass('tampered registry artifact fails installation without changing existing graph or config');
const incompatible=JSON.parse(bytes);incompatible.package.codegraph.engines='>=9';await assert.rejects(()=>manager.install({bytes:Buffer.from(JSON.stringify(incompatible)),replaces:['drupal']}),/requires/);await assert.rejects(()=>manager.install({bytes:Buffer.from('{}'),replaces:['drupal']}));assert.equal(snapshot().hash,installed.hash);assert.equal(snapshot().config,installed.config);pass('incompatible and malformed installs preserve previously working Drupal graph');
await page.getByRole('button',{name:'Disable',exact:true}).click();await page.getByRole('button',{name:'Enable',exact:true}).waitFor();assert.equal(snapshot().pluginEdges.length,0);pass('browser disable removes actual extension contributions');
await page.getByRole('button',{name:'Enable',exact:true}).click();await page.getByRole('button',{name:'Disable',exact:true}).waitFor();verify(snapshot());await page.setViewportSize({width:390,height:844});await page.screenshot({path:path.join(out,'mobile-official.png'),fullPage:true});pass('browser enable restores expected graph and mobile official details');
await page.getByRole('button',{name:'Remove',exact:true}).click();await page.getByText('Extension removed and graph refreshed',{exact:true}).first().waitFor();assert.equal(snapshot().pluginEdges.length,0);assert.equal(new ExtensionManager(project).list().length,0);assert.ok(!CodeGraph.isInitialized(other));assert.deepEqual(pageErrors,[]);pass('browser removal clears extension config and SQLite contributions; no page errors');
fs.writeFileSync(path.join(out,'result.json'),JSON.stringify({revision:cp.execFileSync('git',['rev-parse','HEAD'],{encoding:'utf8'}).trim(),dirty:!!cp.execFileSync('git',['status','--porcelain'],{encoding:'utf8'}).trim(),platform:process.platform,browser:browser.version(),corpus:{name:'pathauto',revision:pin},checks,commands,success:true},null,2));
}catch(error){if(page)await page.screenshot({path:path.join(out,'failure.png'),fullPage:true}).catch(()=>{});fs.writeFileSync(path.join(out,'failure.json'),JSON.stringify({checks,commands,error:String(error.stack)},null,2));throw error;}finally{await browser?.close();await bridge?.close();await server?.close();fs.rmSync(lab,{recursive:true,force:true});}})().catch(e=>{console.error(e);process.exitCode=1;});