mirror of
https://github.com/affaan-m/ECC.git
synced 2026-08-17 21:15:40 +02:00
test(release): verify packed Ito distribution (#2803)
This commit is contained in:
@@ -135,7 +135,7 @@ function getNpmExecInvocation(publicArgs, environment, platform = process.platfo
|
|||||||
|
|
||||||
const commandParts = ['npm', ...npmArgs];
|
const commandParts = ['npm', ...npmArgs];
|
||||||
for (const part of commandParts) {
|
for (const part of commandParts) {
|
||||||
if (!/^[A-Za-z0-9_.=+/-]+$/.test(part)) {
|
if (!/^[A-Za-z0-9_.=+,:/-]+$/.test(part)) {
|
||||||
throw new Error(`Unsafe npm exec argument for Windows lifecycle: ${part}`);
|
throw new Error(`Unsafe npm exec argument for Windows lifecycle: ${part}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -292,18 +292,70 @@ function runLifecycle(options) {
|
|||||||
assert.match(setupHelp.stdout, /ECC guided setup/);
|
assert.match(setupHelp.stdout, /ECC guided setup/);
|
||||||
assert.match(setupHelp.stdout, /ecc setup --mode claude-plugin/);
|
assert.match(setupHelp.stdout, /ecc setup --mode claude-plugin/);
|
||||||
|
|
||||||
|
const itoInstallArgs = [
|
||||||
|
'install',
|
||||||
|
'--profile', 'core',
|
||||||
|
'--with', 'capability:ito-compute',
|
||||||
|
'--with', 'capability:prediction-markets',
|
||||||
|
'--target', 'cursor',
|
||||||
|
'--json',
|
||||||
|
];
|
||||||
parseJsonOutput(
|
parseJsonOutput(
|
||||||
runCli(['install', '--profile', 'core', '--target', 'cursor', '--json']),
|
runCli(itoInstallArgs),
|
||||||
'initial install'
|
'initial Itô install'
|
||||||
);
|
);
|
||||||
assert.ok(fs.existsSync(statePath), 'initial install must write Cursor install-state');
|
assert.ok(fs.existsSync(statePath), 'initial install must write Cursor install-state');
|
||||||
const initialState = JSON.parse(fs.readFileSync(statePath, 'utf8'));
|
const initialState = JSON.parse(fs.readFileSync(statePath, 'utf8'));
|
||||||
const initialLedger = getOperationLedger(initialState);
|
const initialLedger = getOperationLedger(initialState);
|
||||||
|
assert.ok(
|
||||||
|
initialState.operations.some(operation => operation.moduleId === 'ito-compute'),
|
||||||
|
'installed ledger must include the Itô compute module'
|
||||||
|
);
|
||||||
|
assert.ok(
|
||||||
|
initialState.operations.some(operation => operation.moduleId === 'prediction-market-skills'),
|
||||||
|
'installed ledger must include the Itô baskets module'
|
||||||
|
);
|
||||||
|
for (const relativePath of [
|
||||||
|
'skills/ito-baskets/SKILL.md',
|
||||||
|
'skills/ito-baskets/agents/openai.yaml',
|
||||||
|
'skills/ito-baskets/scripts/ito-baskets.js',
|
||||||
|
'skills/ito-compute/SKILL.md',
|
||||||
|
'skills/ito-compute/agents/openai.yaml',
|
||||||
|
'skills/ito-inference/SKILL.md',
|
||||||
|
'skills/ito-training/SKILL.md',
|
||||||
|
]) {
|
||||||
|
const installedPath = path.join(cursorRoot, relativePath);
|
||||||
|
const installedStat = fs.lstatSync(installedPath);
|
||||||
|
assert.ok(installedStat.isFile(), `packed Itô asset is not a file: ${relativePath}`);
|
||||||
|
assert.ok(!installedStat.isSymbolicLink(), `packed Itô asset is a symlink: ${relativePath}`);
|
||||||
|
assert.ok(installedStat.size > 0, `packed Itô asset is empty: ${relativePath}`);
|
||||||
|
}
|
||||||
|
const hostileBin = path.join(tempRoot, 'hostile-bin');
|
||||||
|
const hostileItoSentinel = path.join(tempRoot, 'hostile-ito-spawned');
|
||||||
|
fs.mkdirSync(hostileBin, { recursive: true });
|
||||||
|
const hostileIto = path.join(hostileBin, process.platform === 'win32' ? 'ito.cmd' : 'ito');
|
||||||
|
if (process.platform === 'win32') {
|
||||||
|
fs.writeFileSync(hostileIto, `@echo hostile>"${hostileItoSentinel}"\r\n`, 'utf8');
|
||||||
|
} else {
|
||||||
|
fs.writeFileSync(hostileIto, `#!${process.execPath}\nrequire('fs').writeFileSync(${JSON.stringify(hostileItoSentinel)}, 'spawned');\n`, 'utf8');
|
||||||
|
fs.chmodSync(hostileIto, 0o755);
|
||||||
|
}
|
||||||
|
const itoStatus = runCli(['ito', 'status'], {
|
||||||
|
expectedStatus: 1,
|
||||||
|
env: {
|
||||||
|
...environment,
|
||||||
|
PATH: `${hostileBin}${path.delimiter}${environment.PATH || environment.Path || ''}`,
|
||||||
|
ITO_API_KEY: 'must-not-reach-hostile-path',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
assert.match(itoStatus.stderr, /canonical ito-compute-cli is unpublished/i);
|
||||||
|
assert.doesNotMatch(itoStatus.stderr, /npx|npm exec|npm link|install -g/i);
|
||||||
|
assert.ok(!fs.existsSync(hostileItoSentinel), 'packed Itô bridge executed a PATH collision');
|
||||||
const managedSnapshot = getManagedOperationSnapshot(initialState, cursorRoot);
|
const managedSnapshot = getManagedOperationSnapshot(initialState, cursorRoot);
|
||||||
assert.ok(managedSnapshot.length > 0, 'initial install must create managed Cursor files');
|
assert.ok(managedSnapshot.length > 0, 'initial install must create managed Cursor files');
|
||||||
|
|
||||||
parseJsonOutput(
|
parseJsonOutput(
|
||||||
runCli(['install', '--profile', 'core', '--target', 'cursor', '--json']),
|
runCli(itoInstallArgs),
|
||||||
'repeat install'
|
'repeat install'
|
||||||
);
|
);
|
||||||
const repeatState = JSON.parse(fs.readFileSync(statePath, 'utf8'));
|
const repeatState = JSON.parse(fs.readFileSync(statePath, 'utf8'));
|
||||||
@@ -405,7 +457,8 @@ function runLifecycle(options) {
|
|||||||
lifecycle: [
|
lifecycle: [
|
||||||
'npm-install',
|
'npm-install',
|
||||||
'public-ecc-universal-setup',
|
'public-ecc-universal-setup',
|
||||||
'cursor-install',
|
'cursor-ito-install',
|
||||||
|
'public-ecc-ito-fail-closed',
|
||||||
'cursor-repeat-install',
|
'cursor-repeat-install',
|
||||||
'doctor-clean',
|
'doctor-clean',
|
||||||
'status-installed',
|
'status-installed',
|
||||||
|
|||||||
@@ -125,6 +125,25 @@ test('public CLI invocations use npm exec instead of internal package paths', ()
|
|||||||
assert.ok(!unixInvocation.args.some(argument => argument.includes('node_modules')));
|
assert.ok(!unixInvocation.args.some(argument => argument.includes('node_modules')));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Windows public CLI invocation accepts the exact Itô capability selection', () => {
|
||||||
|
const invocation = lifecycle.getNpmExecInvocation(
|
||||||
|
[
|
||||||
|
'ecc', 'install', '--profile', 'core',
|
||||||
|
'--with', 'capability:ito-compute',
|
||||||
|
'--with', 'capability:prediction-markets',
|
||||||
|
'--target', 'cursor', '--json',
|
||||||
|
],
|
||||||
|
{ ComSpec: 'C:\\Windows\\System32\\cmd.exe' },
|
||||||
|
'win32'
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.strictEqual(invocation.command, 'C:\\Windows\\System32\\cmd.exe');
|
||||||
|
assert.strictEqual(
|
||||||
|
invocation.args[3],
|
||||||
|
'npm exec --offline --yes=false -- ecc install --profile core --with capability:ito-compute --with capability:prediction-markets --target cursor --json'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
test('lifecycle cleanup retries Windows file locks without masking results', () => {
|
test('lifecycle cleanup retries Windows file locks without masking results', () => {
|
||||||
const source = fs.readFileSync(
|
const source = fs.readFileSync(
|
||||||
path.join(__dirname, 'packed-artifact-lifecycle.js'),
|
path.join(__dirname, 'packed-artifact-lifecycle.js'),
|
||||||
|
|||||||
@@ -161,6 +161,35 @@ test('packed lifecycle invokes installed public bins, including setup help', ()
|
|||||||
assert.doesNotMatch(lifecycleRunnerSource, /node_modules.*scripts.*ecc\.js/);
|
assert.doesNotMatch(lifecycleRunnerSource, /node_modules.*scripts.*ecc\.js/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('packed lifecycle installs and verifies the opt-in Ito distribution surface', () => {
|
||||||
|
assert.match(
|
||||||
|
lifecycleRunnerSource,
|
||||||
|
/'--profile', 'core'[\s\S]*'--with', 'capability:ito-compute'[\s\S]*'--with', 'capability:prediction-markets'/
|
||||||
|
);
|
||||||
|
for (const moduleId of ['ito-compute', 'prediction-market-skills']) {
|
||||||
|
assert.match(lifecycleRunnerSource, new RegExp(`moduleId === '${moduleId}'`));
|
||||||
|
}
|
||||||
|
for (const installedPath of [
|
||||||
|
'skills/ito-baskets/SKILL.md',
|
||||||
|
'skills/ito-baskets/agents/openai.yaml',
|
||||||
|
'skills/ito-baskets/scripts/ito-baskets.js',
|
||||||
|
'skills/ito-compute/SKILL.md',
|
||||||
|
'skills/ito-compute/agents/openai.yaml',
|
||||||
|
'skills/ito-inference/SKILL.md',
|
||||||
|
'skills/ito-training/SKILL.md',
|
||||||
|
]) {
|
||||||
|
assert.match(lifecycleRunnerSource, new RegExp(installedPath.replaceAll('.', '\\.')));
|
||||||
|
}
|
||||||
|
assert.match(lifecycleRunnerSource, /\['ito', 'status'\]/);
|
||||||
|
assert.match(lifecycleRunnerSource, /canonical ito-compute-cli is unpublished/i);
|
||||||
|
assert.match(lifecycleRunnerSource, /npx\|npm exec\|npm link\|install -g/i);
|
||||||
|
assert.match(lifecycleRunnerSource, /installedStat\.isFile\(\)/);
|
||||||
|
assert.match(lifecycleRunnerSource, /installedStat\.size > 0/);
|
||||||
|
assert.match(lifecycleRunnerSource, /hostileItoSentinel/);
|
||||||
|
assert.match(lifecycleRunnerSource, /must-not-reach-hostile-path/);
|
||||||
|
assert.match(lifecycleRunnerSource, /packed Itô bridge executed a PATH collision/);
|
||||||
|
});
|
||||||
|
|
||||||
console.log(`\nPassed: ${passed}`);
|
console.log(`\nPassed: ${passed}`);
|
||||||
console.log(`Failed: ${failed}`);
|
console.log(`Failed: ${failed}`);
|
||||||
process.exit(failed > 0 ? 1 : 0);
|
process.exit(failed > 0 ? 1 : 0);
|
||||||
|
|||||||
Reference in New Issue
Block a user