From e712120ca996c826446f82ebf75ac4eab37eadeb Mon Sep 17 00:00:00 2001 From: Adrian Webb Date: Tue, 13 Oct 2026 04:59:38 -0400 Subject: [PATCH 1/5] test: reproduce verifier loader and fence loss in production CLI assets --- package.json | 3 ++- tests/acceptance/workday-events.test.ts | 7 ++++--- tests/contract/package/native-loader.test.ts | 17 +++++++++++++++++ tests/support/native-loader.ts | 4 ++++ 4 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 tests/contract/package/native-loader.test.ts create mode 100644 tests/support/native-loader.ts diff --git a/package.json b/package.json index ccc0b19..6c8c3d9 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,8 @@ "treeseed.package.yaml", "guarantees", "tests/acceptance/workday-events.test.ts", - "tests/support/os-custody.ts" + "tests/support/os-custody.ts", + "tests/support/native-loader.ts" ], "publishConfig": { "access": "public" diff --git a/tests/acceptance/workday-events.test.ts b/tests/acceptance/workday-events.test.ts index d186ed6..74be448 100644 --- a/tests/acceptance/workday-events.test.ts +++ b/tests/acceptance/workday-events.test.ts @@ -1,4 +1,5 @@ import '../support/os-custody.ts'; +import { nativePreloadArguments } from '../support/native-loader.ts'; import assert from 'node:assert/strict'; import { spawn } from 'node:child_process'; import { existsSync, mkdtempSync, readFileSync, rmSync } from 'node:fs'; @@ -13,7 +14,7 @@ const packageRoot = resolve(import.meta.dirname, '../..'); const { commandSpecs }: { commandSpecs: Array<{ path: string[]; execution: CommandExecutionBinding }> } = await import(new URL('../../dist/cli/registry.js', import.meta.url).href); const { saveServerSession } = await import(new URL('../../dist/cli/support/server-custody.js', import.meta.url).href); -const loader = import.meta.resolve('tsx'); +const preloads = nativePreloadArguments(process.execArgv); const custody = new URL('../support/os-custody.ts', import.meta.url).href; test('packaged native workday diagnostic readback preserves exact clock bytes and denied history through unchanged retry without execution requests', { timeout: 30_000 }, async context => { const packageBytes = readFileSync(resolve(packageRoot, 'package.json')), manifest = JSON.parse(packageBytes.toString('utf8')); @@ -58,7 +59,7 @@ test('packaged native workday diagnostic readback preserves exact clock bytes an assert.equal(command.length, 1); const argv = [...command[0]!.path, runId, '--team', teamId, '--cursor', cursor, '--limit', '50', ...options, '--server', 'local', '--json']; const before = structuredClone(argv); - child = spawn(process.execPath, ['--import', loader, '--import', custody, entrypoint, ...argv], { cwd: packageRoot, env, signal: context.signal, stdio: ['ignore', 'pipe', 'pipe'] }); + child = spawn(process.execPath, [...preloads, '--import', custody, entrypoint, ...argv], { cwd: packageRoot, env, signal: context.signal, stdio: ['ignore', 'pipe', 'pipe'] }); let stdout = '', stderr = ''; child.stdout!.on('data', bytes => { stdout += String(bytes); }); child.stderr!.on('data', bytes => { stderr += String(bytes); }); const code = await new Promise((accept, reject) => { child!.once('error', reject); child!.once('close', accept); }); assert.deepEqual(argv, before); assert.equal(child.signalCode, null); @@ -121,7 +122,7 @@ test('retrieves a later exact event page through independent native CLI and real assert.ok(bound, 'The existing public event command must be bound.'); const manifest = JSON.parse(readFileSync(resolve(packageRoot, 'package.json'), 'utf8')); assert.equal(manifest.bin.trsd, './dist/cli/main.js'); const entrypoint = resolve(packageRoot, manifest.bin.trsd), bytes = readFileSync(entrypoint); - child = spawn(process.execPath, ['--import', loader, '--import', custody, entrypoint, ...bound.path, runId, + child = spawn(process.execPath, [...preloads, '--import', custody, entrypoint, ...bound.path, runId, '--team', teamId, '--cursor', cursor, '--limit', '50', '--json'], { cwd: packageRoot, env, signal: context.signal, stdio: ['ignore', 'pipe', 'pipe'] }); let stdout = '', stderr = ''; child.stdout!.on('data', chunk => { stdout += String(chunk); }); child.stderr!.on('data', chunk => { stderr += String(chunk); }); diff --git a/tests/contract/package/native-loader.test.ts b/tests/contract/package/native-loader.test.ts new file mode 100644 index 0000000..c6d2c5f --- /dev/null +++ b/tests/contract/package/native-loader.test.ts @@ -0,0 +1,17 @@ +import assert from 'node:assert/strict'; +import test from 'node:test'; +import { nativePreloadArguments } from '../../support/native-loader.ts'; + +test('retains the original owning loader and import fence without importing CLI development dependencies or child test flags',()=>{ + const args=Object.freeze(['--import','data:text/javascript,original-fence','--import','/installed/reviewer/node_modules/tsx/dist/loader.mjs','--test','--test-reporter=json']); + assert.deepEqual(nativePreloadArguments(args),args.slice(0,4)); + assert.deepEqual(args,['--import','data:text/javascript,original-fence','--import','/installed/reviewer/node_modules/tsx/dist/loader.mjs','--test','--test-reporter=json']); +}); +test('retains combined import syntax and order through the same original loader without mutating native arguments',()=>{ + assert.deepEqual(nativePreloadArguments(['--test','--import=data:text/javascript,fence','--import=tsx','--test-concurrency=2']), + ['--import=data:text/javascript,fence','--import=tsx']); +}); +test('denies missing malformed or unrelated owning loaders instead of falling back to checkout dependencies',()=>{ + for(const args of [[],['--test'],['--import'],['--import',''],['--import','--test'],['--import='],['--import','data:text/javascript,fence'],['--import','unrelated-loader']]) + assert.throws(()=>nativePreloadArguments(args)); +}); diff --git a/tests/support/native-loader.ts b/tests/support/native-loader.ts new file mode 100644 index 0000000..9780e26 --- /dev/null +++ b/tests/support/native-loader.ts @@ -0,0 +1,4 @@ +/** Existing native verifier preload selection, extracted before its regression. */ +export function nativePreloadArguments(_args:readonly string[]):string[] { + return ['--import',import.meta.resolve('tsx')]; +} From ef9fb4f2512b903fed7bd493482f75c744ef072b Mon Sep 17 00:00:00 2001 From: Adrian Webb Date: Tue, 13 Oct 2026 05:33:30 -0400 Subject: [PATCH 2/5] fix: retain the production verifier loader and fence in CLI native assets --- .../command-boundary/observation}/native-loader.test.ts | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/{contract/package => unit/command-boundary/observation}/native-loader.test.ts (100%) diff --git a/tests/contract/package/native-loader.test.ts b/tests/unit/command-boundary/observation/native-loader.test.ts similarity index 100% rename from tests/contract/package/native-loader.test.ts rename to tests/unit/command-boundary/observation/native-loader.test.ts From 5f83eb561cebc9f7daceccde08de9e8320e61d60 Mon Sep 17 00:00:00 2001 From: Adrian Webb Date: Tue, 13 Oct 2026 05:34:30 -0400 Subject: [PATCH 3/5] fix: complete inherited CLI verifier loading and production archive proof --- .github/workflows/verify.yml | 11 +++++ README.md | 7 +++ .../scenes/component-boundaries.scene.yaml | 9 ++++ guarantees/verifiers/golden.verifiers.yaml | 15 +++++++ .../contract/package/installed-assets.test.ts | 45 ++++++++++++++----- tests/support/native-loader.ts | 21 +++++++-- .../observation/native-loader.test.ts | 4 +- 7 files changed, 97 insertions(+), 15 deletions(-) diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index 207e2be..f400c23 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -18,6 +18,8 @@ jobs: TREESEED_AGENT_DISABLE_GIT: "true" TREESEED_TOOL_CLOSURE_OUTPUT: artifacts TREESEED_DEVELOPMENT_WORKSPACE_ROOT: ${{ github.workspace }}/.treeseed/platform-authority + TREESEED_TEST_REVIEWER_ARCHIVE: ${{ github.workspace }}/.treeseed/verified-reviewer/treeseed-reviewer-0.1.0-rc.13.tgz + TREESEED_TEST_REVIEWER_ARCHIVE_SHA256: 063ef40142eaf603a37c14082aad7a34d326aefeae40026cf684af8bdc4bc274 steps: - name: Checkout uses: actions/checkout@v4 @@ -58,6 +60,15 @@ jobs: echo "ff7a7af40bfce7398f137eabcbf9212f2e8d8f3ddb18c9f152df8b76fdb8c9e3 ${archives[0]}" | sha256sum --check --strict npm install --no-save --package-lock=false --ignore-scripts --no-audit --no-fund "${archives[0]}" + - name: Obtain exact production verifier archive + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 + with: + github-token: ${{ github.token }} + repository: treeseed-ai/reviewer + run-id: 38348410425 + name: reviewer-c04f1b295780d4758cbeee16a456d25272ec4b50 + path: .treeseed/verified-reviewer + - name: Verify package with exact SDK run: npm run verify:direct - name: Execute coded golden component scenes diff --git a/README.md b/README.md index f600528..4240f1d 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,13 @@ The package exposes only the `trsd` executable. It has no JavaScript library exp ## Development +The complete package suite also verifies native acceptance assets with an actual +production Reviewer archive. Set `TREESEED_TEST_REVIEWER_ARCHIVE` to its absolute +tarball path and `TREESEED_TEST_REVIEWER_ARCHIVE_SHA256` to its verified digest. +The Verify workflow obtains its pinned archive from Reviewer Actions. The fixture +installs it with production dependencies and scripts disabled; CLI adds no loader +runtime dependency and retains the owning verifier's loader and import fence. + ```sh npm ci npm run lint diff --git a/guarantees/agent/golden/scenes/component-boundaries.scene.yaml b/guarantees/agent/golden/scenes/component-boundaries.scene.yaml index 4ac5207..308ca76 100644 --- a/guarantees/agent/golden/scenes/component-boundaries.scene.yaml +++ b/guarantees/agent/golden/scenes/component-boundaries.scene.yaml @@ -3,6 +3,15 @@ id: cli.golden.component-boundaries title: Golden operator component boundaries scope: local-component-tests workflow: + - id: native-preloads-unit + action: { verifier: cli.golden.native-preloads-unit } + expect: { status: passed } + - id: native-preloads-syntax-unit + action: { verifier: cli.golden.native-preloads-syntax-unit } + expect: { status: passed } + - id: native-preloads-denial-unit + action: { verifier: cli.golden.native-preloads-denial-unit } + expect: { status: passed } - id: restart-current-custody-unit action: { verifier: cli.golden.restart-current-custody-unit } expect: { status: passed } diff --git a/guarantees/verifiers/golden.verifiers.yaml b/guarantees/verifiers/golden.verifiers.yaml index 9ecfff5..d1aa987 100644 --- a/guarantees/verifiers/golden.verifiers.yaml +++ b/guarantees/verifiers/golden.verifiers.yaml @@ -1,6 +1,21 @@ schemaVersion: treeseed.guarantee-verifiers/v1 ownerPackage: "@treeseed/cli" verifiers: + cli.golden.native-preloads-unit: + kind: nodeTestCase + ownerPackage: '@treeseed/cli' + testFile: tests/unit/command-boundary/observation/native-loader.test.ts + testName: retains the original owning loader and import fence without importing CLI development dependencies or child test flags + cli.golden.native-preloads-syntax-unit: + kind: nodeTestCase + ownerPackage: '@treeseed/cli' + testFile: tests/unit/command-boundary/observation/native-loader.test.ts + testName: retains combined import syntax and order through the same original loader without mutating native arguments + cli.golden.native-preloads-denial-unit: + kind: nodeTestCase + ownerPackage: '@treeseed/cli' + testFile: tests/unit/command-boundary/observation/native-loader.test.ts + testName: denies missing malformed or unrelated owning loaders instead of falling back to checkout dependencies cli.golden.execution-diagnostics-read-unit: kind: nodeTestCase ownerPackage: "@treeseed/cli" diff --git a/tests/contract/package/installed-assets.test.ts b/tests/contract/package/installed-assets.test.ts index 6ac52bb..2c769bf 100644 --- a/tests/contract/package/installed-assets.test.ts +++ b/tests/contract/package/installed-assets.test.ts @@ -1,16 +1,16 @@ import assert from 'node:assert/strict'; import { execFile } from 'node:child_process'; import { createHash } from 'node:crypto'; -import { existsSync, lstatSync, mkdtempSync, readFileSync, realpathSync, rmSync, symlinkSync, writeFileSync } from 'node:fs'; +import { copyFileSync, existsSync, lstatSync, mkdtempSync, readFileSync, realpathSync, rmSync, symlinkSync, writeFileSync } from 'node:fs'; import { tmpdir } from 'node:os'; -import { resolve } from 'node:path'; +import { basename, isAbsolute, resolve } from 'node:path'; import test from 'node:test'; import { promisify } from 'node:util'; import ts from 'typescript'; const assets = ['treeseed.package.yaml', 'guarantees/verifiers/golden.verifiers.yaml', - 'tests/acceptance/workday-events.test.ts', 'tests/support/os-custody.ts']; -type Packed = { filename: string; integrity: string; files: Array<{ path: string }> }; + 'tests/acceptance/workday-events.test.ts', 'tests/support/os-custody.ts', 'tests/support/native-loader.ts']; +type Packed = { name:string; filename: string; integrity: string; files: Array<{ path: string }> }; const execute = async (command: string, args: string[], cwd = process.cwd()) => (await promisify(execFile)(command, args, { cwd, encoding: 'utf8', maxBuffer: 8 * 1024 * 1024 })).stdout; @@ -36,17 +36,18 @@ test('ships the selected CLI native observation assets without checkout source e test('native production CLI archive retains exact observation assets and executes its public binary without source or development dependencies', { timeout: 30_000 }, async () => { const root = mkdtempSync(resolve(tmpdir(), 'cli-installed-assets-')); try { - const packed: Packed[] = []; - for (const owner of ['./node_modules/@treeseed/sdk', './node_modules/@treeseed/identity', '.']) { - const [archive] = JSON.parse(await execute('npm', ['pack', owner, '--ignore-scripts', '--json', '--pack-destination', root])) as Packed[]; - assert.ok(archive); packed.push(archive); + const names = ['@treeseed/sdk', '@treeseed/identity', '@treeseed/cli']; + const records=JSON.parse(await execute('npm',['pack','./node_modules/@treeseed/sdk','./node_modules/@treeseed/identity','.', + '--ignore-scripts','--json','--pack-destination',root])) as Packed[]; + assert.equal(records.length,names.length); + const packed=names.map(name=>{const matches=records.filter(record=>record.name===name);assert.equal(matches.length,1);return matches[0]!;}); + for (const archive of packed) { assert.equal(`sha512-${createHash('sha512').update(readFileSync(resolve(root, archive.filename))).digest('base64')}`, archive.integrity); } - const names = ['@treeseed/sdk', '@treeseed/identity', '@treeseed/cli']; const dependencies = Object.fromEntries(packed.map((archive, index) => [names[index]!, `file:${resolve(root, archive.filename)}`])); writeFileSync(resolve(root, 'package.json'), JSON.stringify({ private: true, type: 'module', dependencies, overrides: { '@treeseed/sdk': '$@treeseed/sdk', '@treeseed/identity': '$@treeseed/identity' } })); - await execute('npm', ['install', '--prefix', root, '--omit=dev', '--ignore-scripts', '--package-lock=false', '--no-save', '--no-audit', '--no-fund', + await execute('npm', ['install', '--prefix', root, '--omit=dev', '--ignore-scripts', '--package-lock=false', '--no-save', '--no-audit', '--no-fund','--prefer-offline', ...packed.map(archive => resolve(root, archive.filename))], root); await execute('npm', ['ls', '--all', '--omit=dev', '--json'], root); const installed = resolve(root, 'node_modules/@treeseed/cli'); @@ -61,6 +62,30 @@ test('native production CLI archive retains exact observation assets and execute const env: NodeJS.ProcessEnv = { ...process.env, TREESEED_CONFIG_HOME: resolve(root, 'config') }; delete env.NODE_OPTIONS; delete env.NODE_TEST_CONTEXT; const result = await promisify(execFile)(process.execPath, [binary, '--help'], { cwd: root, env, encoding: 'utf8' }); assert.equal(result.stderr, ''); assert.match(result.stdout, /trsd/u); assert.deepEqual(readFileSync(binary), bytes); + const verifierArchive=process.env.TREESEED_TEST_REVIEWER_ARCHIVE,verifierDigest=process.env.TREESEED_TEST_REVIEWER_ARCHIVE_SHA256; + assert.ok(verifierArchive&&verifierDigest,'The exact production Reviewer archive must be supplied for native verifier closure'); + assert.equal(isAbsolute(verifierArchive),true); + assert.equal(lstatSync(verifierArchive).isSymbolicLink(),false); + assert.equal(createHash('sha256').update(readFileSync(verifierArchive)).digest('hex'),verifierDigest); + const verifierInput=resolve(root,basename(verifierArchive));assert.equal(existsSync(verifierInput),false);copyFileSync(verifierArchive,verifierInput); + writeFileSync(resolve(root,'package.json'),JSON.stringify({private:true,type:'module',dependencies:{...dependencies,'@treeseed/reviewer':`file:${verifierInput}`}, + overrides:{'@treeseed/sdk':'$@treeseed/sdk','@treeseed/identity':'$@treeseed/identity'}})); + await execute('npm',['install','--prefix',root,'--omit=dev','--ignore-scripts','--package-lock=false','--no-save','--no-audit','--no-fund','--prefer-offline','--install-strategy=nested', + ...packed.map(archive=>resolve(root,archive.filename)),verifierInput],root); + const verifierRoot=resolve(root,'node_modules/@treeseed/reviewer'); + const verifierManifest=JSON.parse(readFileSync(resolve(verifierRoot,'package.json'),'utf8')); + assert.equal(verifierManifest.name,'@treeseed/reviewer');assert.ok(verifierManifest.dependencies.tsx); + assert.equal(existsSync(resolve(root,'node_modules/tsx')),false,'CLI must not obtain a hoisted undeclared loader'); + const runner=resolve(verifierRoot,'dist/verifiers/guarantees/node-case.js'),asset=resolve(installed,assets[2]!),helper=resolve(installed,assets[4]!); + const helperBytes=readFileSync(helper);rmSync(helper); + const invocation=[runner,asset,'packaged native workday diagnostic readback preserves exact clock bytes and denied history through unchanged retry without execution requests',resolve(root,'node_modules')]; + let denied='';try{await promisify(execFile)(process.execPath,invocation,{cwd:installed,env,encoding:'utf8'});assert.fail('Missing archived loader helper must deny');} + catch(error){denied=String((error as {stdout?:string}).stdout??'');assert.equal(JSON.parse(denied).success,false);} + writeFileSync(helper,helperBytes); + const native=JSON.parse((await promisify(execFile)(process.execPath,invocation,{cwd:installed,env,encoding:'utf8'})).stdout); + assert.equal(native.success,true);assert.equal(native.numPassedTests,1);assert.equal(native.numFailedTests,0); + assert.equal(createHash('sha256').update(readFileSync(verifierInput)).digest('hex'),verifierDigest); + assert.deepEqual(readFileSync(helper),helperBytes);assert.equal(JSON.parse(denied).success,false); const alias = resolve(root, 'trsd'), replacement = resolve(root, 'replacement.ts'), preload = resolve(root, 'switch-entrypoint.mts'); symlinkSync(binary, alias); writeFileSync(replacement, bytes); writeFileSync(preload, `import{registerHooks}from'node:module';import{unlinkSync,symlinkSync,writeFileSync}from'node:fs';import{pathToFileURL}from'node:url'; diff --git a/tests/support/native-loader.ts b/tests/support/native-loader.ts index 9780e26..2cb65b5 100644 --- a/tests/support/native-loader.ts +++ b/tests/support/native-loader.ts @@ -1,4 +1,19 @@ -/** Existing native verifier preload selection, extracted before its regression. */ -export function nativePreloadArguments(_args:readonly string[]):string[] { - return ['--import',import.meta.resolve('tsx')]; +/** Keep the owning native runner's loader and fence; never resolve a CLI loader. */ +export function nativePreloadArguments(args:readonly string[]):string[] { + const imports:string[]=[],specifiers:string[]=[]; + for(let index=0;indexvalue==='tsx'||/[/\\]tsx[/\\]/u.test(value))) + throw new Error('Original owning TypeScript loader is required.'); + return imports; } diff --git a/tests/unit/command-boundary/observation/native-loader.test.ts b/tests/unit/command-boundary/observation/native-loader.test.ts index c6d2c5f..1a2b8bd 100644 --- a/tests/unit/command-boundary/observation/native-loader.test.ts +++ b/tests/unit/command-boundary/observation/native-loader.test.ts @@ -1,6 +1,6 @@ import assert from 'node:assert/strict'; import test from 'node:test'; -import { nativePreloadArguments } from '../../support/native-loader.ts'; +import { nativePreloadArguments } from '../../../support/native-loader.ts'; test('retains the original owning loader and import fence without importing CLI development dependencies or child test flags',()=>{ const args=Object.freeze(['--import','data:text/javascript,original-fence','--import','/installed/reviewer/node_modules/tsx/dist/loader.mjs','--test','--test-reporter=json']); @@ -12,6 +12,6 @@ test('retains combined import syntax and order through the same original loader ['--import=data:text/javascript,fence','--import=tsx']); }); test('denies missing malformed or unrelated owning loaders instead of falling back to checkout dependencies',()=>{ - for(const args of [[],['--test'],['--import'],['--import',''],['--import','--test'],['--import='],['--import','data:text/javascript,fence'],['--import','unrelated-loader']]) + for(const args of [[],['--test'],['--import'],['--import',''],['--import','--test'],['--import='],['--import=--test','--import=tsx'],['--import','data:text/javascript,fence'],['--import','unrelated-loader']]) assert.throws(()=>nativePreloadArguments(args)); }); From e99998bd3dd92706688a91a0e4f77fc832ec04ac Mon Sep 17 00:00:00 2001 From: Adrian Webb Date: Tue, 13 Oct 2026 06:00:32 -0400 Subject: [PATCH 4/5] test: reuse held archives in one native production installation --- .github/workflows/verify.yml | 5 ++- README.md | 2 ++ .../contract/package/installed-assets.test.ts | 34 ++++++++++--------- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index f400c23..f97a583 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -18,6 +18,8 @@ jobs: TREESEED_AGENT_DISABLE_GIT: "true" TREESEED_TOOL_CLOSURE_OUTPUT: artifacts TREESEED_DEVELOPMENT_WORKSPACE_ROOT: ${{ github.workspace }}/.treeseed/platform-authority + TREESEED_TEST_SDK_ARCHIVE: ${{ github.workspace }}/.treeseed/verified-sdk/treeseed-sdk-0.13.0-rc.122.tgz + TREESEED_TEST_SDK_ARCHIVE_SHA256: ff7a7af40bfce7398f137eabcbf9212f2e8d8f3ddb18c9f152df8b76fdb8c9e3 TREESEED_TEST_REVIEWER_ARCHIVE: ${{ github.workspace }}/.treeseed/verified-reviewer/treeseed-reviewer-0.1.0-rc.13.tgz TREESEED_TEST_REVIEWER_ARCHIVE_SHA256: 063ef40142eaf603a37c14082aad7a34d326aefeae40026cf684af8bdc4bc274 steps: @@ -57,7 +59,8 @@ jobs: set -euo pipefail mapfile -t archives < <(find .treeseed/verified-sdk -maxdepth 1 -type f -name '*.tgz') test "${#archives[@]}" -eq 1 - echo "ff7a7af40bfce7398f137eabcbf9212f2e8d8f3ddb18c9f152df8b76fdb8c9e3 ${archives[0]}" | sha256sum --check --strict + test "${archives[0]}" -ef "$TREESEED_TEST_SDK_ARCHIVE" + echo "$TREESEED_TEST_SDK_ARCHIVE_SHA256 ${archives[0]}" | sha256sum --check --strict npm install --no-save --package-lock=false --ignore-scripts --no-audit --no-fund "${archives[0]}" - name: Obtain exact production verifier archive diff --git a/README.md b/README.md index 4240f1d..17a0661 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,8 @@ The package exposes only the `trsd` executable. It has no JavaScript library exp The complete package suite also verifies native acceptance assets with an actual production Reviewer archive. Set `TREESEED_TEST_REVIEWER_ARCHIVE` to its absolute tarball path and `TREESEED_TEST_REVIEWER_ARCHIVE_SHA256` to its verified digest. +Set `TREESEED_TEST_SDK_ARCHIVE` and `TREESEED_TEST_SDK_ARCHIVE_SHA256` to the held +SDK input already used by the owning dependency check; the fixture reuses it. The Verify workflow obtains its pinned archive from Reviewer Actions. The fixture installs it with production dependencies and scripts disabled; CLI adds no loader runtime dependency and retains the owning verifier's loader and import fence. diff --git a/tests/contract/package/installed-assets.test.ts b/tests/contract/package/installed-assets.test.ts index 2c769bf..d43aca7 100644 --- a/tests/contract/package/installed-assets.test.ts +++ b/tests/contract/package/installed-assets.test.ts @@ -37,18 +37,29 @@ test('native production CLI archive retains exact observation assets and execute const root = mkdtempSync(resolve(tmpdir(), 'cli-installed-assets-')); try { const names = ['@treeseed/sdk', '@treeseed/identity', '@treeseed/cli']; - const records=JSON.parse(await execute('npm',['pack','./node_modules/@treeseed/sdk','./node_modules/@treeseed/identity','.', - '--ignore-scripts','--json','--pack-destination',root])) as Packed[]; + const sdkInput=process.env.TREESEED_TEST_SDK_ARCHIVE,sdkDigest=process.env.TREESEED_TEST_SDK_ARCHIVE_SHA256; + assert.ok(sdkInput&&sdkDigest,'Reuse the exact held SDK archive instead of repacking its installed files');assert.equal(isAbsolute(sdkInput),true); + assert.equal(lstatSync(sdkInput).isSymbolicLink(),false);assert.equal(createHash('sha256').update(readFileSync(sdkInput)).digest('hex'),sdkDigest); + const [sdk]=JSON.parse(await execute('npm',['pack','--dry-run','--ignore-scripts','--json',sdkInput])) as Packed[]; + assert.ok(sdk);assert.equal(sdk.name,'@treeseed/sdk');copyFileSync(sdkInput,resolve(root,sdk.filename)); + const records=[sdk,...JSON.parse(await execute('npm',['pack','./node_modules/@treeseed/identity','.', + '--ignore-scripts','--json','--pack-destination',root])) as Packed[]]; assert.equal(records.length,names.length); const packed=names.map(name=>{const matches=records.filter(record=>record.name===name);assert.equal(matches.length,1);return matches[0]!;}); for (const archive of packed) { assert.equal(`sha512-${createHash('sha512').update(readFileSync(resolve(root, archive.filename))).digest('base64')}`, archive.integrity); } const dependencies = Object.fromEntries(packed.map((archive, index) => [names[index]!, `file:${resolve(root, archive.filename)}`])); - writeFileSync(resolve(root, 'package.json'), JSON.stringify({ private: true, type: 'module', dependencies, - overrides: { '@treeseed/sdk': '$@treeseed/sdk', '@treeseed/identity': '$@treeseed/identity' } })); - await execute('npm', ['install', '--prefix', root, '--omit=dev', '--ignore-scripts', '--package-lock=false', '--no-save', '--no-audit', '--no-fund','--prefer-offline', - ...packed.map(archive => resolve(root, archive.filename))], root); + const verifierArchive=process.env.TREESEED_TEST_REVIEWER_ARCHIVE,verifierDigest=process.env.TREESEED_TEST_REVIEWER_ARCHIVE_SHA256; + assert.ok(verifierArchive&&verifierDigest,'The exact production Reviewer archive must be supplied for native verifier closure'); + assert.equal(isAbsolute(verifierArchive),true); + assert.equal(lstatSync(verifierArchive).isSymbolicLink(),false); + assert.equal(createHash('sha256').update(readFileSync(verifierArchive)).digest('hex'),verifierDigest); + const verifierInput=resolve(root,basename(verifierArchive));assert.equal(existsSync(verifierInput),false);copyFileSync(verifierArchive,verifierInput); + writeFileSync(resolve(root,'package.json'),JSON.stringify({private:true,type:'module',dependencies:{...dependencies,'@treeseed/reviewer':`file:${verifierInput}`}, + overrides:{'@treeseed/sdk':'$@treeseed/sdk','@treeseed/identity':'$@treeseed/identity'}})); + await execute('npm',['install','--prefix',root,'--omit=dev','--ignore-scripts','--package-lock=false','--no-save','--no-audit','--no-fund','--prefer-offline','--install-strategy=nested', + ...packed.map(archive=>resolve(root,archive.filename)),verifierInput],root); await execute('npm', ['ls', '--all', '--omit=dev', '--json'], root); const installed = resolve(root, 'node_modules/@treeseed/cli'); assert.equal(realpathSync(installed), installed); assert.equal(lstatSync(installed).isSymbolicLink(), false); @@ -62,16 +73,6 @@ test('native production CLI archive retains exact observation assets and execute const env: NodeJS.ProcessEnv = { ...process.env, TREESEED_CONFIG_HOME: resolve(root, 'config') }; delete env.NODE_OPTIONS; delete env.NODE_TEST_CONTEXT; const result = await promisify(execFile)(process.execPath, [binary, '--help'], { cwd: root, env, encoding: 'utf8' }); assert.equal(result.stderr, ''); assert.match(result.stdout, /trsd/u); assert.deepEqual(readFileSync(binary), bytes); - const verifierArchive=process.env.TREESEED_TEST_REVIEWER_ARCHIVE,verifierDigest=process.env.TREESEED_TEST_REVIEWER_ARCHIVE_SHA256; - assert.ok(verifierArchive&&verifierDigest,'The exact production Reviewer archive must be supplied for native verifier closure'); - assert.equal(isAbsolute(verifierArchive),true); - assert.equal(lstatSync(verifierArchive).isSymbolicLink(),false); - assert.equal(createHash('sha256').update(readFileSync(verifierArchive)).digest('hex'),verifierDigest); - const verifierInput=resolve(root,basename(verifierArchive));assert.equal(existsSync(verifierInput),false);copyFileSync(verifierArchive,verifierInput); - writeFileSync(resolve(root,'package.json'),JSON.stringify({private:true,type:'module',dependencies:{...dependencies,'@treeseed/reviewer':`file:${verifierInput}`}, - overrides:{'@treeseed/sdk':'$@treeseed/sdk','@treeseed/identity':'$@treeseed/identity'}})); - await execute('npm',['install','--prefix',root,'--omit=dev','--ignore-scripts','--package-lock=false','--no-save','--no-audit','--no-fund','--prefer-offline','--install-strategy=nested', - ...packed.map(archive=>resolve(root,archive.filename)),verifierInput],root); const verifierRoot=resolve(root,'node_modules/@treeseed/reviewer'); const verifierManifest=JSON.parse(readFileSync(resolve(verifierRoot,'package.json'),'utf8')); assert.equal(verifierManifest.name,'@treeseed/reviewer');assert.ok(verifierManifest.dependencies.tsx); @@ -103,6 +104,7 @@ unlinkSync(${JSON.stringify(alias)});symlinkSync(${JSON.stringify(replacement)}, assert.equal(after.integrity, before.integrity, 'Development readiness changes must not change executable archive custody'); assert.deepEqual(after.files, before.files); assert.deepEqual(readFileSync(binary), bytes); for (const archive of packed) assert.equal(`sha512-${createHash('sha512').update(readFileSync(resolve(root, archive.filename))).digest('base64')}`, archive.integrity); + assert.equal(createHash('sha256').update(readFileSync(sdkInput)).digest('hex'),sdkDigest); console.log(JSON.stringify({ archives: packed.map(archive => ({ filename: archive.filename, sha256: createHash('sha256').update(readFileSync(resolve(root, archive.filename))).digest('hex') })), installedPublicBinary: 'passed' })); } finally { rmSync(root, { recursive: true, force: true }); assert.equal(existsSync(root), false); } From f538a7559ae0756e80c66ec222e78d31f0ce5af1 Mon Sep 17 00:00:00 2001 From: Adrian Webb Date: Tue, 13 Oct 2026 06:09:09 -0400 Subject: [PATCH 5/5] test: overlap independent archive proofs and await cleanup outcomes --- .../contract/package/installed-assets.test.ts | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/tests/contract/package/installed-assets.test.ts b/tests/contract/package/installed-assets.test.ts index d43aca7..ad9d8e5 100644 --- a/tests/contract/package/installed-assets.test.ts +++ b/tests/contract/package/installed-assets.test.ts @@ -40,10 +40,13 @@ test('native production CLI archive retains exact observation assets and execute const sdkInput=process.env.TREESEED_TEST_SDK_ARCHIVE,sdkDigest=process.env.TREESEED_TEST_SDK_ARCHIVE_SHA256; assert.ok(sdkInput&&sdkDigest,'Reuse the exact held SDK archive instead of repacking its installed files');assert.equal(isAbsolute(sdkInput),true); assert.equal(lstatSync(sdkInput).isSymbolicLink(),false);assert.equal(createHash('sha256').update(readFileSync(sdkInput)).digest('hex'),sdkDigest); - const [sdk]=JSON.parse(await execute('npm',['pack','--dry-run','--ignore-scripts','--json',sdkInput])) as Packed[]; + const [sdkInventory,ownerInventory]=await Promise.all([ + execute('npm',['pack','--dry-run','--ignore-scripts','--json',sdkInput]), + execute('npm',['pack','./node_modules/@treeseed/identity','.', '--ignore-scripts','--json','--pack-destination',root]), + ]); + const [sdk]=JSON.parse(sdkInventory) as Packed[]; assert.ok(sdk);assert.equal(sdk.name,'@treeseed/sdk');copyFileSync(sdkInput,resolve(root,sdk.filename)); - const records=[sdk,...JSON.parse(await execute('npm',['pack','./node_modules/@treeseed/identity','.', - '--ignore-scripts','--json','--pack-destination',root])) as Packed[]]; + const records=[sdk,...JSON.parse(ownerInventory) as Packed[]]; assert.equal(records.length,names.length); const packed=names.map(name=>{const matches=records.filter(record=>record.name===name);assert.equal(matches.length,1);return matches[0]!;}); for (const archive of packed) { @@ -71,8 +74,6 @@ test('native production CLI archive retains exact observation assets and execute const manifest = JSON.parse(readFileSync(resolve(installed, 'package.json'), 'utf8')); assert.equal(manifest.bin.trsd, './dist/cli/main.js'); const binary = resolve(installed, manifest.bin.trsd), bytes = readFileSync(binary); const env: NodeJS.ProcessEnv = { ...process.env, TREESEED_CONFIG_HOME: resolve(root, 'config') }; delete env.NODE_OPTIONS; delete env.NODE_TEST_CONTEXT; - const result = await promisify(execFile)(process.execPath, [binary, '--help'], { cwd: root, env, encoding: 'utf8' }); - assert.equal(result.stderr, ''); assert.match(result.stdout, /trsd/u); assert.deepEqual(readFileSync(binary), bytes); const verifierRoot=resolve(root,'node_modules/@treeseed/reviewer'); const verifierManifest=JSON.parse(readFileSync(resolve(verifierRoot,'package.json'),'utf8')); assert.equal(verifierManifest.name,'@treeseed/reviewer');assert.ok(verifierManifest.dependencies.tsx); @@ -83,10 +84,14 @@ test('native production CLI archive retains exact observation assets and execute let denied='';try{await promisify(execFile)(process.execPath,invocation,{cwd:installed,env,encoding:'utf8'});assert.fail('Missing archived loader helper must deny');} catch(error){denied=String((error as {stdout?:string}).stdout??'');assert.equal(JSON.parse(denied).success,false);} writeFileSync(helper,helperBytes); - const native=JSON.parse((await promisify(execFile)(process.execPath,invocation,{cwd:installed,env,encoding:'utf8'})).stdout); - assert.equal(native.success,true);assert.equal(native.numPassedTests,1);assert.equal(native.numFailedTests,0); - assert.equal(createHash('sha256').update(readFileSync(verifierInput)).digest('hex'),verifierDigest); - assert.deepEqual(readFileSync(helper),helperBytes);assert.equal(JSON.parse(denied).success,false); + // The public-binary/readiness checks and original installed diagnostic case + // read the same immutable executable bytes and use separate temporary config. + // Wait for both outcomes before cleanup, including when either fails. + const outcomes=await Promise.allSettled([ + promisify(execFile)(process.execPath,invocation,{cwd:installed,env,encoding:'utf8'}), + (async()=>{ + const result = await promisify(execFile)(process.execPath, [binary, '--help'], { cwd: root, env, encoding: 'utf8' }); + assert.equal(result.stderr, ''); assert.match(result.stdout, /trsd/u); assert.deepEqual(readFileSync(binary), bytes); const alias = resolve(root, 'trsd'), replacement = resolve(root, 'replacement.ts'), preload = resolve(root, 'switch-entrypoint.mts'); symlinkSync(binary, alias); writeFileSync(replacement, bytes); writeFileSync(preload, `import{registerHooks}from'node:module';import{unlinkSync,symlinkSync,writeFileSync}from'node:fs';import{pathToFileURL}from'node:url'; @@ -103,6 +108,14 @@ unlinkSync(${JSON.stringify(alias)});symlinkSync(${JSON.stringify(replacement)}, const after = await inventory(); assert.equal(after.integrity, before.integrity, 'Development readiness changes must not change executable archive custody'); assert.deepEqual(after.files, before.files); assert.deepEqual(readFileSync(binary), bytes); + })(), + ]); + for(const outcome of outcomes)if(outcome.status==='rejected')throw outcome.reason; + const observed=outcomes[0]!;assert.equal(observed.status,'fulfilled'); + const native=JSON.parse(observed.value.stdout); + assert.equal(native.success,true);assert.equal(native.numPassedTests,1);assert.equal(native.numFailedTests,0); + assert.equal(createHash('sha256').update(readFileSync(verifierInput)).digest('hex'),verifierDigest); + assert.deepEqual(readFileSync(helper),helperBytes);assert.equal(JSON.parse(denied).success,false); for (const archive of packed) assert.equal(`sha512-${createHash('sha512').update(readFileSync(resolve(root, archive.filename))).digest('base64')}`, archive.integrity); assert.equal(createHash('sha256').update(readFileSync(sdkInput)).digest('hex'),sdkDigest); console.log(JSON.stringify({ archives: packed.map(archive => ({ filename: archive.filename,