Files
codegraph/scripts/validation/release-security.cjs
T

38 lines
3.7 KiB
JavaScript

// Harmless disposable installer and upgrade probes. No injected shell code executes.
const fs=require('node:fs'),path=require('node:path'),os=require('node:os'),vm=require('node:vm'),assert=require('node:assert/strict'),cp=require('node:child_process');
const repo=path.resolve(process.argv[2]||'.');
const dist=path.resolve(process.argv[3]||path.join(repo,'dist'));
const up=require(path.join(dist,'upgrade/index.js'));
const rows=[];
async function check(name,f){try{await f();rows.push({name,pass:true});}catch(e){rows.push({name,pass:false,error:String(e)});}console.log(JSON.stringify(rows.at(-1)));}
(async()=>{
await check('1367-invalid-upgrade-suffix-rejected-before-dispatch',async()=>{
const commands=[];let errors=[];
const code=await up.runUpgrade({version:'1.6.1 INVALID_SUFFIX'}, {currentVersion:'1.6.0',method:{kind:'npm',scope:'local'},platform:'win32',resolveLatest:async()=>'',run:(...a)=>{commands.push(a);return 19;},capture:()=>null,hasCommand:()=>false,log:()=>{},warn:()=>{},error:s=>errors.push(s)});
assert.equal(code,1);assert.equal(commands.length,0,'unvalidated suffix reached cmd.exe via stub');assert(errors.length);
});
await check('1367-windows-helper-rejects-invalid-version',()=>{
assert.throws(()=>up.buildWindowsUpgradeScript("C:\\Test O'Brien\\current",'1.6.1 INVALID_SUFFIX','x64'));
});
if(fs.existsSync(path.join(repo,'install.sh')) && process.platform!=='win32') await check('1367-shell-installer-mismatched-checksum-preserves-install',()=>{
const dir=fs.mkdtempSync(path.join(os.tmpdir(),'cg-security-'));
try {
const bin=path.join(dir,'stubs');fs.mkdirSync(bin);const tree=path.join(dir,'codegraph-linux-x64');fs.mkdirSync(path.join(tree,'bin'),{recursive:true});fs.writeFileSync(path.join(tree,'bin/codegraph'),'inert replacement');
cp.execFileSync('tar',['-czf',path.join(dir,'bundle.tgz'),'-C',dir,'codegraph-linux-x64']);
const dest=path.join(dir,'install/versions/v1.6.1/bin');fs.mkdirSync(dest,{recursive:true});fs.writeFileSync(path.join(dest,'codegraph'),'original');
fs.writeFileSync(path.join(dir,'sums'),'0'.repeat(64)+' codegraph-linux-x64.tar.gz\n');
fs.writeFileSync(path.join(bin,'curl'),`#!/bin/sh\nout=''\nurl=''\nwhile [ "$#" -gt 0 ]; do case "$1" in -o) shift; out="$1";; https:*) url="$1";; esac; shift; done\ncase "$url" in */SHA256SUMS) cp "$FIXTURE/sums" "$out";; *) cp "$FIXTURE/bundle.tgz" "$out";; esac\n`,{mode:0o755});
fs.writeFileSync(path.join(bin,'uname'),'#!/bin/sh\ncase "$1" in -s) echo Linux;; -m) echo x86_64;; esac\n',{mode:0o755});
const r=cp.spawnSync('sh',[path.join(repo,'install.sh')],{env:{...process.env,PATH:bin+path.delimiter+process.env.PATH,FIXTURE:dir,CODEGRAPH_VERSION:'v1.6.1',CODEGRAPH_INSTALL_DIR:path.join(dir,'install'),CODEGRAPH_BIN_DIR:path.join(dir,'out')},encoding:'utf8',timeout:10000});
assert.notEqual(r.status,0,'installer accepted deliberately mismatched checksum');assert.equal(fs.readFileSync(path.join(dest,'codegraph'),'utf8'),'original');
} finally{fs.rmSync(dir,{recursive:true,force:true});}
});
await check('1367-npm-fallback-missing-checksum-fails-closed',async()=>{
const source=fs.readFileSync(path.join(repo,'scripts/npm-shim.js'),'utf8');const start=source.indexOf('async function verifyChecksum('),end=source.indexOf('// Extract via',start);
const ctx={require,fs,path,process,download:async()=>{throw Error('fixture missing manifest');}};
vm.createContext(ctx);vm.runInContext(source.slice(start,end),ctx);
await assert.rejects(()=>ctx.verifyChecksum('/unused','codegraph-linux-x64.tar.gz','https://example.invalid','1.6.1'));
});
console.log(JSON.stringify({repo,dist,node:process.version,platform:process.platform,rows}));process.exitCode=rows.every(r=>r.pass)?0:1;
})();