← back to Tk11438 Postgres Migration

verification/gracie-rollout/independent-check.cjs

23 lines

const fs=require('fs'),cp=require('child_process'),A=require('assert/strict'),C=require('crypto'),os=require('os'),net=require('net');
const D='/Users/macstudio3/Projects/gracie-internal',O=__dirname,dep='/Users/macstudio3/.npm-global/lib/node_modules/pm2/node_modules/';
const {Client}=require(D+'/node_modules/pg'),axon=require(dep+'pm2-axon'),rpc=require(dep+'pm2-axon-rpc');
const read=p=>fs.readFileSync(p),j=p=>JSON.parse(read(p)),sha=b=>C.createHash('sha256').update(b).digest('hex'),run=(c,a)=>cp.execFileSync(c,a,{encoding:'utf8',timeout:15000,maxBuffer:8e6});
const proof={task:'TK-11438',owner:'codex-run-11438-verifier',at:new Date().toISOString(),checks:[],application_mutations:0,email_sends:0};
const ok=(name,data=true)=>proof.checks.push({name,verdict:'PASS',data});
function monitor(){return new Promise((r,q)=>{const s=axon.socket('req'),c=new rpc.Client(s),t=setTimeout(()=>{s.close();q(Error('monitor timeout'));},30000);s.on('error',e=>{clearTimeout(t);s.close();q(e);});s.connect('/Users/macstudio3/.pm2/rpc.sock');c.call('getMonitorData',{},(e,x)=>{clearTimeout(t);s.close();e?q(Error('monitor failed')):r(x);});});}
async function db(o,f){const c=new Client({...o,application_name:'TK11438-Gracie-independent',connectionTimeoutMillis:3000,options:'-c default_transaction_read_only=on -c statement_timeout=5000'});try{await c.connect();return await f(c);}finally{await c.end().catch(()=>{});}}
function probe(host){return new Promise(r=>{const s=net.createConnection({host,port:10073});s.setTimeout(3000);s.on('connect',()=>{s.destroy();r({host,connected:true});});s.on('error',e=>{s.destroy();r({host,connected:false,code:e.code});});s.on('timeout',()=>{s.destroy();r({host,connected:false,code:'TIMEOUT'});});});}
(async()=>{
const b=j(O+'/private/baseline.runtime.json'),rec=j(O+'/private/receipt.json');A.equal(j(O+'/startup-schema.json').verdict,'PASS');const matches=(await monitor()).filter(x=>x.name==='gracie-internal');A.equal(matches.length,1);const p=matches[0],e=p.pm2_env;proof.pid=p.pid;A.equal(e.pm_cwd,D);A.equal(e.pm_exec_path,D+'/server.js');A.equal(e.status,'online');A.equal(e.restart_time,b.restarts+1);A.notEqual(p.pid,b.pid);ok('Exact Gracie online after one restart',{pid:p.pid,restarts:e.restart_time});
const saved=j('/Users/macstudio3/.pm2/dump.pm2').filter(x=>x.name==='gracie-internal');A.equal(saved.length,1);A.equal(saved[0].pm_cwd,D);A.equal(saved[0].pm_exec_path,D+'/server.js');for(const f of [e.PG,e.env.PG,saved[0].PG,saved[0].env.PG])A.equal(f,rec.next.PG);A.equal(new URL(e.PG).searchParams.get('host'),'/tmp');A(!e.PGHOST&&!e.env.PGHOST&&!saved[0].PGHOST&&!saved[0].env.PGHOST);A.equal(sha(e.BASIC_AUTH||''),b.controls.auth_sha);A.equal(e.DATA_SOURCE||null,b.controls.DATA_SOURCE);A.equal(String(e.PORT||10073),b.controls.PORT);ok('Effective/saved socket fields and unchanged auth/data/port controls');
for(const s of rec.specs){A.equal(sha(read(s.path)),s.after_sha);A.equal(sha(read(O+'/private/privacy-rehearsal-'+s.key)),s.recovery_sha);}const server=read(D+'/server.js').toString(),vendor=read(D+'/lib/vendor-requests.js').toString();A(server.includes("app.listen(PORT, '127.0.0.1', () =>"));A(vendor.includes("host: process.env.PGHOST || (process.platform === 'darwin' ? '/tmp' : '127.0.0.1')"));A.equal(sha(read(D+'/data/gracie.jsonl')),b.bundle_sha);ok('Reviewed source hashes, privacy rollback copies and catalog bundle');
const tcp=run('lsof',['-nP','-a','-p',String(p.pid),'-iTCP']),listeners=tcp.split('\n').filter(x=>x.includes('(LISTEN)'));A.equal(listeners.length,1);A(/127\.0\.0\.1:10073\s+\(LISTEN\)/.test(listeners[0]));A(!/:5432\b/.test(tcp));ok('Only 127.0.0.1:10073 listener and no TCP5432',listeners);
const addresses=[...new Set(Object.values(os.networkInterfaces()).flat().filter(x=>x.family==='IPv4'&&!x.internal).map(x=>x.address)),'::1'];A(addresses.length>1);const blocked=[];for(const a of addresses){const r=await probe(a);A.equal(r.connected,false);A(['ECONNREFUSED','EHOSTUNREACH','ENETUNREACH','TIMEOUT'].includes(r.code));blocked.push(r);}ok('All nonloopback IPv4 plus IPv6 loopback reject 10073',blocked);
const auth=e.BASIC_AUTH||server.match(/process\.env\.BASIC_AUTH \|\| '([^']+)'/)[1];for(const route of ['/healthz','/api/products','/api/requests'])for(const mode of ['missing','invalid','valid']){const headers=mode==='missing'?{}:{authorization:'Basic '+Buffer.from(mode==='valid'?auth:'TK11438:invalid').toString('base64')};const r=await fetch('http://127.0.0.1:10073'+route,{headers,signal:AbortSignal.timeout(8000)}),body=await r.text();A.equal(r.status,route==='/healthz'||mode==='valid'?200:401);if(route==='/healthz')A.deepEqual(JSON.parse(body),{ok:true});if(mode==='valid'&&route==='/api/products'){A.equal(JSON.parse(body).count,b.product_count);A.equal(sha(body),b.http.find(x=>x.route===route&&x.auth==='valid').body_sha);}if(mode==='valid'&&route==='/api/requests')A.equal(JSON.parse(body).requests.length,b.vendor.requests.count);ok(route+' '+mode,{status:r.status,body_sha256:sha(body),bytes:Buffer.byteLength(body)});}
const secret=read('/Users/macstudio3/Projects/secrets-manager/.env').toString().match(/^DW_ADMIN_DB_PASSWORD=(.+)$/m),password=e.DW_ADMIN_DB_PASSWORD||(secret?secret[1].replace(/^["']|["']$/g,'').trim():'');const opts={host:'/tmp',port:5432,user:'dw_admin',database:'dw_unified',password};
const v=await db(opts,async c=>({identity:(await c.query("SELECT current_database() database,current_user role,inet_client_addr()::text addr,current_setting('transaction_read_only') readonly,(SELECT oid FROM pg_database WHERE datname=current_database()) database_oid,pg_postmaster_start_time() server_started")).rows[0],requests:(await c.query("SELECT count(*)::int count,max(id)::text last_id FROM vendor_requests WHERE vendor_code='gracie'")).rows[0],schema:(await c.query("SELECT column_name,data_type,is_nullable,column_default FROM information_schema.columns WHERE table_schema='public' AND table_name='vendor_requests' ORDER BY ordinal_position")).rows,indexes:(await c.query("SELECT indexname,indexdef FROM pg_indexes WHERE schemaname='public' AND tablename='vendor_requests' ORDER BY indexname")).rows}));A.equal(v.identity.addr,null);A.equal(v.identity.readonly,'on');for(const k of ['database','role','database_oid'])A.equal(v.identity[k],b.vendor.identity[k]);A.equal(v.identity.server_started.toISOString(),b.vendor.identity.server_started);A.deepEqual(v.requests,b.vendor.requests);A.deepEqual(v.schema,b.vendor.schema);A.deepEqual(v.indexes,b.vendor.indexes);ok('Vendor socket identity and unchanged records/schema/indexes',{identity:v.identity,requests:v.requests});
for(const [name,url]of [['effective',e.PG],['saved',saved[0].PG]]){const id=await db({connectionString:url},async c=>(await c.query("SELECT current_database() database,current_user role,inet_client_addr()::text addr,current_setting('transaction_read_only') readonly")).rows[0]);A.equal(id.addr,null);A.equal(id.readonly,'on');A.equal(id.database,b.catalog.database);A.equal(id.role,b.catalog.role);ok('Catalog '+name+' socket identity',id);}
for(const [name,o]of [['vendor',{...opts,host:O+'/missing-socket'}],['catalog',{connectionString:(()=>{const u=new URL(e.PG);u.searchParams.set('host',O+'/missing-socket');return u.toString();})()}]]){let code;try{await db(o,async()=>{});}catch(e){code=e.code;}A.equal(code,'ENOENT');ok(name+' missing socket fails closed',code);}
const unix=run('lsof',['-nP','-a','-p',String(p.pid),'-U']);A(/unix/.test(unix));ok('Gracie owns Unix sockets',{sha256:sha(unix),rows:unix.trim().split('\n').length-1});const last=(await monitor()).find(x=>x.name==='gracie-internal');A.equal(last.pid,p.pid);A.equal(last.pm2_env.restart_time,e.restart_time);ok('Process stable throughout verification');proof.commit=run('git',['-C',D,'rev-parse','HEAD']).trim();const diff=run('git',['-C',D,'show','--format=','--numstat','HEAD']).trim();A.equal(diff,'1\t1\tlib/vendor-requests.js\n2\t2\tserver.js');ok('Commit changes exactly three lines across two scoped files',{commit:proof.commit,numstat:diff});proof.verdict='PASS';proof.status='complete_scoped_verification';proof.scope_limits=['17 local proxy configs and 4 running proxy/tunnel processes inspected before rollout; remote/cloud-managed routes unqueried','Catalog currently uses unchanged JSONL; configured PG URI independently connected','Only GET routes after confirmed startup DDL; no POST or emails'];proof.commands=['Direct existing PM2 monitor RPC before/after','lsof process TCP/Unix','TCP connect all nonloopback IPv4 and ::1','9 loopback GET auth checks','Read-only PostgreSQL identity/count/schema/index queries','Source/rollback-copy/catalog bundle SHA256','git rev-parse and show --numstat'];
})().catch(e=>{proof.verdict='FAIL';proof.status='partial';proof.error={name:e.name,code:e.code,message:String(e.message).replace(/postgres(?:ql)?:\/\/\S+/g,'[REDACTED_URI]')};}).finally(()=>{fs.writeFileSync(O+'/independent-runtime.json',JSON.stringify(proof,null,2)+'\n');console.log(JSON.stringify(proof,null,2));if(proof.verdict!=='PASS')process.exitCode=1;});