mirror of
https://github.com/garrytan/gstack.git
synced 2026-10-31 22:14:25 +01:00
* security: isolate every gstack Bun entry point from the audited checkout's .env and bunfig.toml Bun auto-loads .env, .env.local and .env.<NODE_ENV> from its cwd and runs a cwd bunfig.toml preload before the program starts. gstack runs inside the repo it audits, so a committed .env could steer state roots, the claude binary or spend caps, and a bunfig preload ran arbitrary code in every bin and hook. Every bun shebang, shell and skill caller, TypeScript spawn and compiled build now disables both (--no-env-file --config=/dev/null, bunIsolationArgs(), --no-compile-autoload-dotenv/bunfig), with a ratchet and hostile-fixture regressions. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * test: name the directly executed scripts in the isolation ratchet Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * test: follow the isolation flags in touchfiles, copy lists, recipe assertions and the harness pin Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix: keep browse/src/bun-child-config.ts unchanged so the native cookie qualification still binds Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix(windows): the empty bunfig outlives its process so the timeline hook's detached repair child can read it Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * v1.91.159.0 security: gstack's Bun entry points ignore the audited repo's .env and bunfig.toml (S1) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * test: plan-mode render pattern accepts the isolation flags Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --------- Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
30 lines
2.1 KiB
TypeScript
30 lines
2.1 KiB
TypeScript
#!/usr/bin/env -S bun --no-env-file --config=/dev/null
|
|
/** Bind cryptographically verified `gh attestation verify --format json` output to reviewed statements. */
|
|
import * as fs from 'node:fs';
|
|
import { resolve } from 'node:path';
|
|
import { canonical, sha256 } from '../lib/cso/contracts';
|
|
|
|
const HASH=/^[a-f0-9]{64}$/,MAX_BYTES=4*1024*1024;
|
|
|
|
export function verifiedStatementSetDigest(value:unknown,predicateType:string,subjectSha256:string):string{
|
|
if(!Array.isArray(value)||!value.length||typeof predicateType!=='string'||!/^https:\/\/[A-Za-z0-9./_-]+$/.test(predicateType)||!HASH.test(subjectSha256))throw new Error('INVALID_VERIFIED_ATTESTATION_SET');
|
|
const statements:string[]=[];
|
|
for(const item of value){
|
|
if(!item||typeof item!=='object'||Array.isArray(item))throw new Error('INVALID_VERIFIED_ATTESTATION_SET');
|
|
const result=(item as any).verificationResult,statement=result?.statement;
|
|
if(!statement||typeof statement!=='object'||Array.isArray(statement)||statement.predicateType!==predicateType||!Array.isArray(statement.subject)||
|
|
!statement.subject.some((subject:any)=>subject&&typeof subject==='object'&&subject.digest?.sha256===subjectSha256))throw new Error('VERIFIED_ATTESTATION_IDENTITY_MISMATCH');
|
|
statements.push(canonical(statement));
|
|
}
|
|
statements.sort();return`sha256:${sha256(canonical(statements))}`;
|
|
}
|
|
|
|
if(import.meta.main){
|
|
try{
|
|
const args=process.argv.slice(2),command=args.shift(),file=args.shift(),predicate=args.shift(),subject=args.shift();
|
|
if(command!=='digest'||!file||!predicate||!subject||args.length)throw new Error('Usage: cso-attestation-evidence digest VERIFIED.json PREDICATE SUBJECT_SHA256');
|
|
const path=resolve(file),stat=fs.lstatSync(path);if(!stat.isFile()||stat.isSymbolicLink()||stat.nlink!==1||stat.size<=0||stat.size>MAX_BYTES)throw new Error('UNSAFE_VERIFIED_ATTESTATION_FILE');
|
|
process.stdout.write(verifiedStatementSetDigest(JSON.parse(fs.readFileSync(path,'utf8')),predicate,subject)+'\n');
|
|
}catch(error){process.stderr.write((error instanceof Error?error.message:'ATTESTATION_EVIDENCE_ERROR')+'\n');process.exitCode=1;}
|
|
}
|