Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion .github/workflows/verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ 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:
- name: Checkout
uses: actions/checkout@v4
Expand Down Expand Up @@ -55,9 +59,19 @@ 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
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
Expand Down
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,15 @@ 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.
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.

```sh
npm ci
npm run lint
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
15 changes: 15 additions & 0 deletions guarantees/verifiers/golden.verifiers.yaml
Original file line number Diff line number Diff line change
@@ -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"
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
7 changes: 4 additions & 3 deletions tests/acceptance/workday-events.test.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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'));
Expand Down Expand Up @@ -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<number | null>((accept, reject) => { child!.once('error', reject); child!.once('close', accept); });
assert.deepEqual(argv, before); assert.equal(child.signalCode, null);
Expand Down Expand Up @@ -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); });
Expand Down
66 changes: 53 additions & 13 deletions tests/contract/package/installed-assets.test.ts
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -36,18 +36,33 @@ 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 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 [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(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) {
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',
...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);
Expand All @@ -59,6 +74,22 @@ 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 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);
// 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');
Expand All @@ -77,7 +108,16 @@ 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,
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); }
Expand Down
19 changes: 19 additions & 0 deletions tests/support/native-loader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/** 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;index<args.length;index++) {
const argument=args[index]!;
if(argument==='--import') {
const value=args[++index];
if(!value||value.startsWith('--'))throw new Error('Original native import value is required.');
imports.push(argument,value);specifiers.push(value);
}else if(argument.startsWith('--import=')) {
const value=argument.slice('--import='.length);
if(!value||value.startsWith('--'))throw new Error('Original native import value is required.');
imports.push(argument);specifiers.push(value);
}
}
if(!specifiers.some(value=>value==='tsx'||/[/\\]tsx[/\\]/u.test(value)))
throw new Error('Original owning TypeScript loader is required.');
return imports;
}
17 changes: 17 additions & 0 deletions tests/unit/command-boundary/observation/native-loader.test.ts
Original file line number Diff line number Diff line change
@@ -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=--test','--import=tsx'],['--import','data:text/javascript,fence'],['--import','unrelated-loader']])
assert.throws(()=>nativePreloadArguments(args));
});
Loading