mirror of
https://github.com/affaan-m/ECC.git
synced 2026-09-28 12:35:13 +02:00
287 lines
15 KiB
JavaScript
287 lines
15 KiB
JavaScript
'use strict';
|
|
|
|
const assert = require('node:assert/strict');
|
|
const crypto = require('node:crypto');
|
|
const fs = require('node:fs');
|
|
const os = require('node:os');
|
|
const path = require('node:path');
|
|
const test = require('node:test');
|
|
const { withCarrierFixture } = require('./helpers/context-carrier-fixture');
|
|
const { createDirectoryLink, update, withFixture, write } = require('./helpers/context-fixture');
|
|
const { compileContextProfile } = require('../../scripts/lib/context-profiles');
|
|
const { digestObject } = require('../../scripts/lib/context-profile-support');
|
|
|
|
function request(repoRoot, options = {}) {
|
|
const input = { repoRoot, profileId: 'lean@1', target: 'codex', selectionMode: 'manual', ...options };
|
|
const expectedPlan = compileContextProfile(input);
|
|
const { planContextCarrier } = require('../../scripts/lib/context-carriers');
|
|
return { repoRoot, expectedPlan, artifact: planContextCarrier(input) };
|
|
}
|
|
|
|
function resign(artifact, changes) {
|
|
const { carrierDigest: _, ...value } = { ...artifact, ...changes };
|
|
return { ...value, carrierDigest: digestObject(value) };
|
|
}
|
|
|
|
function sha256(bytes) {
|
|
return crypto.createHash('sha256').update(bytes).digest('hex');
|
|
}
|
|
|
|
function freeze(value) {
|
|
if (value && typeof value === 'object') {
|
|
Object.values(value).forEach(freeze);
|
|
Object.freeze(value);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
test('materialization uses unique owned temporary roots and emits only structural evidence', () => withFixture(repoRoot => {
|
|
const options = freeze(request(repoRoot));
|
|
const roots = [];
|
|
const inspect = fixture => {
|
|
roots.push(fixture.root);
|
|
const relative = path.relative(fs.realpathSync(os.tmpdir()), fs.realpathSync(fixture.root));
|
|
assert.ok(relative && !relative.startsWith('..') && !path.isAbsolute(relative));
|
|
const evidence = fixture.verify();
|
|
assert.equal(evidence.schemaVersion, 'ecc.context-fixture-evidence.v1');
|
|
assert.equal(evidence.status, 'verified');
|
|
assert.equal(evidence.evidenceKind, 'structural');
|
|
assert.equal(evidence.nativeSupport, 'unobserved');
|
|
assert.equal(evidence.activation, 'unobserved');
|
|
assert.equal(evidence.carrierDigest, options.artifact.carrierDigest);
|
|
assert.equal(evidence.planDigest, options.expectedPlan.planDigest);
|
|
assert.equal(evidence.fileCount, options.artifact.files.length);
|
|
assert.deepEqual(evidence.files.map(file => file.path), options.artifact.files.map(file => file.destinationPath).sort());
|
|
assert.ok(!JSON.stringify(evidence).includes(fixture.root));
|
|
assert.ok(!JSON.stringify(evidence).includes(repoRoot));
|
|
return evidence;
|
|
};
|
|
assert.deepEqual(withCarrierFixture(options, inspect), withCarrierFixture(options, inspect));
|
|
assert.notEqual(roots[0], roots[1]);
|
|
assert.ok(roots.every(root => !fs.existsSync(root)));
|
|
}));
|
|
|
|
test('copies preserve full binary bytes and never execute bundled scripts', () => withFixture(repoRoot => {
|
|
const binary = Buffer.from([0, 255, 254, 128, 1, 10, 13, 0]);
|
|
const binaryPath = 'skills/ecc-guide/assets/payload.bin';
|
|
fs.mkdirSync(path.dirname(path.join(repoRoot, binaryPath)), { recursive: true });
|
|
fs.writeFileSync(path.join(repoRoot, binaryPath), binary);
|
|
write(repoRoot, 'skills/ecc-guide/run.js', 'throw new Error("Bundled scripts must never execute");');
|
|
const options = request(repoRoot);
|
|
withCarrierFixture(options, ({ root, verify }) => {
|
|
const file = options.artifact.files.find(value => value.sourcePath === binaryPath);
|
|
assert.ok(file, 'full selected resource tree must include the binary');
|
|
assert.deepEqual(fs.readFileSync(path.join(root, file.destinationPath)), binary);
|
|
const observed = verify().files.find(value => value.path === file.destinationPath);
|
|
assert.equal(observed.bytes, binary.length);
|
|
assert.equal(observed.digest, sha256(binary));
|
|
});
|
|
}));
|
|
|
|
test('generated manifests materialize the exact declared UTF-8 bytes', () => withFixture(repoRoot => {
|
|
const options = request(repoRoot, { target: 'claude' });
|
|
const generated = options.artifact.files.filter(file => file.kind === 'generated');
|
|
assert.ok(generated.length > 0);
|
|
withCarrierFixture(options, ({ root, verify }) => {
|
|
for (const file of generated) {
|
|
assert.deepEqual(fs.readFileSync(path.join(root, file.destinationPath)), Buffer.from(file.content, 'utf8'));
|
|
}
|
|
assert.equal(verify().fileCount, options.artifact.files.length);
|
|
});
|
|
}));
|
|
|
|
test('verification remains relocatable after original sources are removed', () => withFixture(repoRoot => {
|
|
const options = request(repoRoot);
|
|
withCarrierFixture(options, ({ verify }) => {
|
|
const before = verify();
|
|
fs.renameSync(path.join(repoRoot, 'skills'), path.join(repoRoot, 'held-source-skills'));
|
|
assert.deepEqual(verify(), before);
|
|
});
|
|
}));
|
|
|
|
test('source drift is rejected before entering the materialized-fixture callback', () => withFixture(repoRoot => {
|
|
const options = request(repoRoot);
|
|
fs.appendFileSync(path.join(repoRoot, 'skills/ecc-guide/SKILL.md'), '\nChanged after planning.\n');
|
|
let entered = false;
|
|
assert.throws(() => withCarrierFixture(options, () => { entered = true; }), /digest|drift|source|binding/i);
|
|
assert.equal(entered, false);
|
|
}));
|
|
|
|
test('source directory-link substitution is rejected before materialization', () => withFixture(repoRoot => {
|
|
const options = request(repoRoot);
|
|
fs.renameSync(path.join(repoRoot, 'skills'), path.join(repoRoot, 'held-skills'));
|
|
createDirectoryLink(path.join(repoRoot, 'held-skills'), path.join(repoRoot, 'skills'));
|
|
assert.throws(() => withCarrierFixture(options, () => assert.fail('unsafe source accepted')), /symlink|symbolic|identity/i);
|
|
}));
|
|
|
|
for (const mutation of ['missing', 'extra', 'tampered']) {
|
|
test(`independent observation rejects ${mutation} staged files`, () => withFixture(repoRoot => {
|
|
const options = request(repoRoot);
|
|
withCarrierFixture(options, ({ root, verify }) => {
|
|
const destination = path.join(root, options.artifact.files[0].destinationPath);
|
|
if (mutation === 'missing') fs.unlinkSync(destination);
|
|
if (mutation === 'extra') fs.writeFileSync(path.join(root, 'unexpected.txt'), 'unplanned');
|
|
if (mutation === 'tampered') fs.appendFileSync(destination, 'changed');
|
|
assert.throws(verify, /missing|extra|unexpected|digest|mismatch|changed|file set/i);
|
|
});
|
|
}));
|
|
}
|
|
|
|
test('schema and carrier digest validation precede fixture writes', () => withFixture(repoRoot => {
|
|
const options = request(repoRoot);
|
|
for (const artifact of [
|
|
{ ...options.artifact, carrierDigest: '0'.repeat(64) },
|
|
resign(options.artifact, { unexpected: 'field' }),
|
|
resign(options.artifact, { active: true }),
|
|
]) {
|
|
assert.throws(() => withCarrierFixture({ ...options, artifact }, () => assert.fail('invalid artifact accepted')),
|
|
/schema|digest|active|additional|contract/i);
|
|
}
|
|
}));
|
|
|
|
test('independent expected plan cannot be replaced with forged provenance', () => withFixture(repoRoot => {
|
|
const options = request(repoRoot);
|
|
const artifact = resign(options.artifact, { planDigest: '0'.repeat(64) });
|
|
assert.throws(() => withCarrierFixture({ ...options, artifact }, () => assert.fail('forged binding accepted')),
|
|
/plan|binding|digest/i);
|
|
const expectedPlan = { ...options.expectedPlan, selectedIds: [] };
|
|
assert.throws(() => withCarrierFixture({ ...options, expectedPlan }, () => assert.fail('tampered expected plan accepted')),
|
|
/plan|digest|selected|binding/i);
|
|
}));
|
|
|
|
test('self-consistently hashed artifacts cannot omit selected entrypoints or bundled resources', () => withFixture(repoRoot => {
|
|
write(repoRoot, 'skills/ecc-guide/references/required.md', 'Required reference.');
|
|
update(repoRoot, 'manifests/context-packs/skill-registry@1.json', value => ({ ...value, overrides: [{
|
|
id: 'skill:ecc-guide', requiredResources: ['skills/ecc-guide/references/required.md'],
|
|
}] }));
|
|
const options = request(repoRoot);
|
|
for (const sourcePath of ['skills/ecc-guide/SKILL.md', 'skills/ecc-guide/references/required.md']) {
|
|
const artifact = resign(options.artifact, { files: options.artifact.files.filter(file => file.sourcePath !== sourcePath) });
|
|
assert.throws(() => withCarrierFixture({ ...options, artifact }, () => assert.fail('omitted source accepted')),
|
|
/missing|required|resource|entrypoint|file set|closure/i);
|
|
}
|
|
const artifact = resign(options.artifact, { entries: options.artifact.entries.map(entry => ({ ...entry, requiredResources: [] })) });
|
|
assert.throws(() => withCarrierFixture({ ...options, artifact }, () => assert.fail('erased declaration accepted')),
|
|
/required|declaration|entry|mismatch/i);
|
|
}));
|
|
|
|
test('self-consistent false source-byte claims fail against independently read sources', () => withFixture(repoRoot => {
|
|
const options = request(repoRoot);
|
|
const copied = options.artifact.files.find(file => file.kind === 'copy');
|
|
const artifact = resign(options.artifact, { files: options.artifact.files.map(file => file === copied
|
|
? { ...file, digest: '0'.repeat(64), bytes: file.bytes + 1 } : file) });
|
|
assert.throws(() => withCarrierFixture({ ...options, artifact }, () => assert.fail('false source claim accepted')),
|
|
/source|bytes|digest|mismatch/i);
|
|
}));
|
|
|
|
test('unsafe or colliding destinations are rejected while outside sentinels remain unchanged', () => withFixture(repoRoot => {
|
|
const sentinel = path.join(repoRoot, 'outside-sentinel.txt');
|
|
fs.writeFileSync(sentinel, 'preserve existing source-side file');
|
|
const options = request(repoRoot);
|
|
for (const destinationPath of ['../outside-sentinel.txt', sentinel, 'folder/../../outside-sentinel.txt']) {
|
|
const artifact = resign(options.artifact, { files: options.artifact.files.map((file, index) => index === 0
|
|
? { ...file, destinationPath } : file) });
|
|
assert.throws(() => withCarrierFixture({ ...options, artifact }, () => assert.fail('unsafe destination accepted')),
|
|
/path|relative|destination|schema|escape/i);
|
|
assert.equal(fs.readFileSync(sentinel, 'utf8'), 'preserve existing source-side file');
|
|
}
|
|
const duplicate = resign(options.artifact, { files: [...options.artifact.files, options.artifact.files[0]] });
|
|
assert.throws(() => withCarrierFixture({ ...options, artifact: duplicate }, () => assert.fail('duplicate accepted')),
|
|
/duplicate|collision|destination|schema/i);
|
|
}));
|
|
|
|
for (const [label, spellings] of [
|
|
['case-folded', ['Case', 'case']],
|
|
['Unicode-normalized', ['caf\u00e9', 'cafe\u0301']],
|
|
]) {
|
|
test(`${label} directory-prefix aliases fail before the first staging write`, context => withFixture(repoRoot => {
|
|
const initial = request(repoRoot);
|
|
const files = ['one.txt', 'two.txt'];
|
|
spellings.forEach((directory, index) => {
|
|
write(repoRoot, `skills/ecc-guide/${directory}/${files[index]}`, `resource ${index}`);
|
|
});
|
|
const skillRoot = path.join(fs.realpathSync(repoRoot), 'skills/ecc-guide');
|
|
const originalList = fs.readdirSync;
|
|
const originalOpen = fs.opendirSync;
|
|
// Model both directory spellings even when the test host aliases them.
|
|
context.mock.method(fs, 'opendirSync', (directory, ...args) => {
|
|
let names;
|
|
if (directory === skillRoot) {
|
|
names = [...originalList(directory).filter(name => !spellings.includes(name)), ...spellings];
|
|
} else {
|
|
const index = spellings.findIndex(spelling => directory === path.join(skillRoot, spelling));
|
|
if (index < 0) return originalOpen(directory, ...args);
|
|
names = [files[index]];
|
|
}
|
|
let index = 0;
|
|
return {
|
|
readSync: () => index < names.length ? { name: names[index++] } : null,
|
|
closeSync() {},
|
|
};
|
|
});
|
|
const { loadContextRegistry } = require('../../scripts/lib/context-pack-registry');
|
|
const registry = loadContextRegistry({ repoRoot });
|
|
const expectedPlan = compileContextProfile({ repoRoot, target: 'codex', selectionMode: 'manual' });
|
|
const byId = new Map(registry.entries.map(entry => [entry.id, entry]));
|
|
const selected = expectedPlan.selectedIds.map(id => byId.get(id));
|
|
const copies = selected.flatMap(entry => entry.resources.map(resource => ({
|
|
kind: 'copy', skillId: entry.id, sourcePath: resource.path,
|
|
destinationPath: `${initial.artifact.layout.skillRoot}/${entry.name}/${resource.path.slice(path.posix.dirname(entry.sourcePath).length + 1)}`,
|
|
digest: resource.digest, bytes: resource.bytes,
|
|
})));
|
|
const bindings = Object.fromEntries(['registryDigest', 'profileDigest', 'compilerDigest', 'planDigest']
|
|
.map(key => [key, expectedPlan[key]]));
|
|
const artifact = resign(initial.artifact, { ...bindings,
|
|
entries: initial.artifact.entries.map(entry => ({ ...entry, contentDigest: byId.get(entry.id).contentDigest })),
|
|
files: [...copies, ...initial.artifact.files.filter(file => file.kind === 'generated')]
|
|
.sort((left, right) => left.destinationPath < right.destinationPath ? -1 : 1),
|
|
});
|
|
const originalWrite = fs.writeFileSync;
|
|
let stagingWrites = 0;
|
|
let failure;
|
|
context.mock.method(fs, 'writeFileSync', (...args) => {
|
|
stagingWrites++;
|
|
return originalWrite(...args);
|
|
});
|
|
try { withCarrierFixture({ repoRoot, artifact, expectedPlan }, () => {}); }
|
|
catch (error) { failure = error; }
|
|
context.mock.restoreAll();
|
|
assert.equal(stagingWrites, 0, 'Portable ancestor aliases must fail before writing the owned stage');
|
|
assert.ok(failure, 'Portable ancestor alias must be rejected');
|
|
assert.match(failure.message, /ancestor|collision|alias|prefix/i);
|
|
}));
|
|
}
|
|
|
|
test('unsupported carriers cannot create a staged fixture', () => withFixture(repoRoot => {
|
|
const options = request(repoRoot, { target: 'gemini' });
|
|
assert.equal(options.artifact.status, 'unsupported');
|
|
assert.throws(() => withCarrierFixture(options, () => assert.fail('unsupported target accepted')), /unsupported/i);
|
|
}));
|
|
|
|
test('failure cleanup removes only the helper-owned stage and preserves outside data', () => withFixture(repoRoot => {
|
|
const sentinel = path.join(repoRoot, 'outside-sentinel.txt');
|
|
fs.writeFileSync(sentinel, 'preserve');
|
|
let stagedRoot;
|
|
assert.throws(() => withCarrierFixture(request(repoRoot), ({ root }) => {
|
|
stagedRoot = root;
|
|
throw new Error('intentional acceptance failure');
|
|
}), /intentional acceptance failure/);
|
|
assert.ok(stagedRoot);
|
|
assert.equal(fs.existsSync(stagedRoot), false);
|
|
assert.equal(fs.readFileSync(sentinel, 'utf8'), 'preserve');
|
|
}));
|
|
|
|
test('root-link substitution fails observation and cleanup never follows the outside link', () => withFixture(repoRoot => {
|
|
const sentinel = path.join(repoRoot, 'outside-sentinel.txt');
|
|
fs.writeFileSync(sentinel, 'preserve');
|
|
let stageContainer;
|
|
withCarrierFixture(request(repoRoot), ({ root, verify }) => {
|
|
stageContainer = path.dirname(root);
|
|
fs.renameSync(root, `${root}-held`);
|
|
createDirectoryLink(repoRoot, root);
|
|
assert.throws(verify, /symlink|symbolic|root|identity/i);
|
|
});
|
|
assert.equal(fs.existsSync(stageContainer), false);
|
|
assert.equal(fs.readFileSync(sentinel, 'utf8'), 'preserve');
|
|
}));
|