Files
ECC/tests/lib/eval-harness/cli.test.js
T
f8640355e4 Consolidate recovered eval framework and operator workflows (#3040)
* feat: consolidate offline eval and operator workflows

Compose the retained framework, operator skill, roadmap and cleanup ranges on current main. Preserve current release dependencies and keep candidate execution disabled pending OS containment. Repair draft/DOCX behavior, obligation uniqueness, trusted send and audience guidance, runner provenance and eval diagnostics.

Source-PR: 2930 0abe3727d2b500c6e4830bdeb47ed67cae3f4785
Source-PR: 2931 992b49c44ed872def49675b791168b8fcd091df6
Source-PR: 2932 4a193dd13041cb7a6bebf4d2e910a0cd32bcc797
Source-PR: 2933 59cdfe500a91949ba1415f1edd7279620f21e804
Source-Base: ca185ef5f7

* fix: repair foundation CI and update js-yaml

* fix: reconcile pending-delete capsule locks after close

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 13:20:52 +01:00

152 lines
6.6 KiB
JavaScript

'use strict';
const assert = require('assert');
const fs = require('fs');
const path = require('path');
const { spawnSync } = require('child_process');
const vm = require('vm');
const { test, tempDir, cleanup, finish } = require('./helpers');
const harness = require('../../../scripts/lib/eval-harness');
const cli = path.resolve(__dirname, '../../../scripts/eval-harness.js');
const run = args => spawnSync(process.execPath, [cli, ...args], { encoding: 'utf8', timeout: 3000 });
// Exercise spawn failures without starting an example, mutating the real
// process object, or depending on a host-specific missing executable.
function exampleResult(result) {
const exit = Symbol('exit');
let status;
let stderr = '';
const calls = [];
const module = { exports: {} };
const context = {
module, __dirname: path.dirname(cli), __filename: cli,
require(name) {
if (name === 'child_process') return { spawnSync(...args) { calls.push(args); return result; } };
if (name === './lib/eval-harness') return harness;
return require(name);
},
process: {
execPath: '/synthetic/node',
stderr: { write(value) { stderr += value; } },
exit(value) { status = value; throw exit; },
},
};
vm.runInNewContext(fs.readFileSync(cli, 'utf8'), context, { timeout: 1000 });
assert.throws(() => module.exports.main(['example', '/synthetic/output']), error => error === exit);
assert.strictEqual(calls.length, 1);
assert.strictEqual(calls[0][0], '/synthetic/node');
assert.deepStrictEqual(Array.from(calls[0][1]), [path.resolve(path.dirname(cli), '../examples/eval-harness/run-example.js'), '/synthetic/output']);
assert.strictEqual(calls[0][2].stdio, 'inherit');
return { status, stderr };
}
test('example startup failure reports a stable diagnostic without child error details', () => {
const error = Object.assign(new Error('private argv and path marker'), {
code: 'ENOENT', path: '/synthetic/private', spawnargs: ['private argument'],
});
assert.deepStrictEqual(exampleResult({ error, status: null }), {
status: 1, stderr: 'eval-harness: example.spawn_failed: unable to start example process\n',
});
});
test('example startup diagnostic never interpolates an untrusted error code', () => {
assert.deepStrictEqual(exampleResult({ error: { code: 'private\nmarker' }, status: null }), {
status: 1, stderr: 'eval-harness: example.spawn_failed: unable to start example process\n',
});
});
test('example preserves child exit status and maps signal termination to failure', () => {
for (const status of [0, 7, null]) {
assert.deepStrictEqual(exampleResult({ status }), { status: status === null ? 1 : status, stderr: '' });
}
});
test('candidate slug normalization preserves composed and combining Unicode behavior', () => {
const { solve } = require('../../../examples/eval-harness/variants/candidate/run');
for (const [input, expected] of [
['Cr\u00e8me Br\u00fbl\u00e9e', 'creme-brulee'],
['Cre\u0300me_Bru\u0302le\u0301e', 'creme-brulee'],
['\u0300A\u036f', 'a'], ['\ufb03 \uff21', 'ffi-a'],
['---A__ B---', 'a-b'], ['\u4e2d\u6587', ''], [42, '42'],
]) assert.strictEqual(solve(input), expected);
});
test('dangling receipt value flags are usage errors before reading missing inputs', () => {
for (const command of [['receipt', 'verify', '/absent-receipt', '/absent-capsule'], ['receipt', 'build', '/absent-capsule']]) {
for (const flag of ['--artifact', '--gate', '--out']) {
for (const tail of [[flag], [flag, '--artifact']]) {
const result = run([...command, ...tail]);
assert.strictEqual(result.status, 2, `${tail}: ${result.stderr}`);
assert.match(result.stderr, /needs a value/);
}
}
}
});
test('invalid output flag does not cause producer projection writes', () => {
const dir = tempDir('cli-build');
try {
harness.capsule.Capsule.create(dir);
const result = run(['receipt', 'build', dir, '--out']);
assert.strictEqual(result.status, 2);
assert.ok(!fs.existsSync(path.join(dir, harness.capsule.PROJECTION_FILE)));
} finally { cleanup(dir); }
});
test('valid CLI build and verify persist then check a projection without healing it', () => {
const dir = tempDir('cli-receipt');
try {
harness.capsule.Capsule.create(dir).append('plan', 'start', {});
const out = path.join(dir, 'receipt.json');
assert.strictEqual(run(['receipt', 'build', dir, '--out', out]).status, 0);
assert.strictEqual(run(['receipt', 'verify', out, dir]).status, 0);
const projection = path.join(dir, harness.capsule.PROJECTION_FILE);
assert.ok(fs.existsSync(projection));
fs.unlinkSync(projection);
const result = run(['receipt', 'verify', out, dir]);
assert.strictEqual(result.status, 1);
assert.strictEqual(JSON.parse(result.stdout).check, 'projection');
assert.ok(!fs.existsSync(projection));
} finally { cleanup(dir); }
});
test('disabled gate still refuses before config or capsule I/O', () => {
const result = run(['gate', 'run', '/absent-config', '--capsule', '--trusted-local']);
assert.strictEqual(result.status, 1);
assert.match(result.stderr, /gate.isolation_required/);
});
test('a repeated value flag cannot conceal a missing value or override silently', () => {
for (const tail of [['--artifact', 'one', '--artifact'], ['--gate', 'one', '--gate', 'two']]) {
const result = run(['receipt', 'verify', '/absent-receipt', '/absent-capsule', ...tail]);
assert.strictEqual(result.status, 2);
}
});
test('capsule CLI projects and exports valid metadata, and rejects forged metadata', () => {
const root = tempDir('cli-capsule');
try {
const dir = path.join(root, 'source');
harness.capsule.Capsule.create(dir).append('plan', 'start', {});
const file = path.join(dir, harness.capsule.META_FILE);
const original = fs.readFileSync(file, 'utf8');
fs.writeFileSync(file, JSON.stringify({ ...JSON.parse(original), run_id: 'forged' }));
const invalid = run(['capsule', 'verify', dir]);
assert.strictEqual(invalid.status, 1);
assert.strictEqual(JSON.parse(invalid.stdout).code, 'capsule.metadata_mismatch');
assert.strictEqual(run(['capsule', 'project', dir]).status, 1);
assert.ok(!fs.existsSync(path.join(dir, harness.capsule.PROJECTION_FILE)));
fs.writeFileSync(file, original);
assert.strictEqual(run(['capsule', 'project', dir]).status, 0);
const out = path.join(root, 'bundle');
assert.strictEqual(run(['capsule', 'export', dir, out]).status, 0);
const valid = run(['capsule', 'verify', out]);
assert.strictEqual(valid.status, 0);
assert.strictEqual(JSON.parse(valid.stdout).ok, true);
} finally { cleanup(root); }
});
finish('cli');