mirror of
https://github.com/PR0M3TH3AN/TORCH.git
synced 2026-10-27 07:51:52 +00:00
139 lines
8.4 KiB
JavaScript
139 lines
8.4 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import { chmodSync, existsSync, mkdirSync, mkdtempSync, readFileSync, symlinkSync, writeFileSync } from 'node:fs';
|
|
import { tmpdir } from 'node:os';
|
|
import { join } from 'node:path';
|
|
import test from 'node:test';
|
|
import { managedProvider, planProviderUpdates, providerStore, updateProviders } from '../../src/adapters/updates.mjs';
|
|
import { createRuntimeAdapterRegistry } from '../../src/adapters/registry.mjs';
|
|
import { execFileSync } from 'node:child_process';
|
|
import { inspectRepository } from '../../src/kernel/git.mjs';
|
|
import { analyzeRepository } from '../../src/kernel/analyze.mjs';
|
|
import { proposeDomains } from '../../src/kernel/domains.mjs';
|
|
import { installProject } from '../../src/kernel/install.mjs';
|
|
import { createWorktrees } from '../../src/kernel/worktrees.mjs';
|
|
import { runCli } from '../../src/cli.mjs';
|
|
|
|
function fixture() {
|
|
const root = mkdtempSync(join(tmpdir(), 'torch-provider-update-'));
|
|
const env = { ...process.env, XDG_DATA_HOME: root };
|
|
const calls = [];
|
|
let version = '1.2.3';
|
|
let failInstall = false;
|
|
const runner = (command, args, options) => {
|
|
calls.push({ command, args, options });
|
|
if (args[0] === 'view') return { status: 0, stdout: JSON.stringify(version) };
|
|
if (args[0] === 'install') {
|
|
if (failInstall) return { status: 1, stderr: 'offline' };
|
|
const pkg = args.at(-1);
|
|
const name = pkg.startsWith('@openai/') ? 'codex' : pkg.startsWith('@anthropic-ai/') ? 'claude' : 'pi';
|
|
const prefix = args[args.indexOf('--prefix') + 1];
|
|
mkdirSync(join(prefix, 'node_modules', '.bin'), { recursive: true });
|
|
const path = join(prefix, 'node_modules', '.bin', name);
|
|
writeFileSync(path, `#!/bin/sh\n# ${version}\n`);
|
|
chmodSync(path, 0o755);
|
|
return { status: 0, stdout: 'installed' };
|
|
}
|
|
return { status: 0, stdout: args[0] === '--version' ? `provider ${version}`
|
|
: args.includes('exec') ? '{"type":"thread.started","thread_id":"provider-update-fixture-session"}\n{"type":"turn.completed"}\n' : 'help' };
|
|
};
|
|
return { env, calls, runner, next: v => { version = v; }, breakInstall: () => { failInstall = true; } };
|
|
}
|
|
|
|
test('SCN-provider-updates: all built-ins resolve official latest, verify and launch the managed binary', () => {
|
|
const f = fixture();
|
|
const plan = planProviderUpdates(['codex', 'claude', 'pi'], f);
|
|
assert.equal(f.calls.length, 0);
|
|
assert.equal(plan.modifiesGlobalInstallations, false);
|
|
assert.throws(() => updateProviders(['codex'], f), { code: 'APPROVAL_REQUIRED' });
|
|
assert.equal(existsSync(providerStore(f.env)), false);
|
|
const result = updateProviders(['codex', 'claude', 'pi'], { ...f, authorized: true });
|
|
assert.deepEqual(result.results.map(r => r.outcome), ['updated', 'updated', 'updated']);
|
|
const registry = createRuntimeAdapterRegistry({ env: f.env });
|
|
for (const name of ['codex', 'claude', 'pi']) {
|
|
const selected = managedProvider(name, f);
|
|
assert.equal(registry.get(name).executable, selected.executable);
|
|
assert.equal(selected.version, '1.2.3');
|
|
assert.equal(f.calls.some(c => c.command === selected.executable && c.args[0] === '--version'), true);
|
|
assert.equal(f.calls.some(c => c.command === selected.executable && c.args[0] === '--help'), true);
|
|
}
|
|
for (const call of f.calls.filter(c => c.command === 'npm')) {
|
|
assert.equal(call.args.includes('-g'), false);
|
|
assert.equal(call.args.includes('--registry'), true);
|
|
assert.equal(call.options.timeout > 0, true);
|
|
}
|
|
assert.equal(f.calls.find(c => c.args.at(-1) === '@earendil-works/[email protected]').args.includes('--ignore-scripts'), true);
|
|
const count = f.calls.length;
|
|
assert.equal(updateProviders(['codex'], { ...f, authorized: true }).results[0].outcome, 'fresh');
|
|
assert.equal(f.calls.length, count, 'fresh startup performs no network/install calls');
|
|
});
|
|
|
|
test('SCN-provider-update-cli: opted-in startup updates selected provider, dry runs stay offline, failed refresh cannot launch', async () => {
|
|
const f = fixture();
|
|
const root = join(f.env.XDG_DATA_HOME, 'repo');
|
|
mkdirSync(root);
|
|
const git = args => execFileSync('git', ['-C', root, ...args], { stdio: 'pipe' });
|
|
git(['init', '-b', 'main']); git(['config', 'user.email', '[email protected]']); git(['config', 'user.name', 'Fixture']);
|
|
writeFileSync(join(root, 'README.md'), '# Test project\n');
|
|
git(['add', '.']); git(['commit', '-m', 'fixture']);
|
|
const repository = inspectRepository(root);
|
|
const proposal = proposeDomains({ repository, analysis: analyzeRepository(repository) });
|
|
proposal.review = { status: 'approved', reviewedAt: '2026-09-30T00:00:00Z', reviewedBy: 'fixture-owner', notes: [] };
|
|
installProject({ repository, proposal, env: f.env, runtimes: ['codex'] });
|
|
const stdout = process.stdout.write;
|
|
const outputs = [];
|
|
process.stdout.write = chunk => { outputs.push(String(chunk)); return true; };
|
|
try {
|
|
const run = args => runCli(args, { cwd: root, env: f.env, spawn: f.runner });
|
|
assert.equal(await run(['runtimes', 'update-policy', '--mode', 'auto', '--yes', '--json']), 0);
|
|
const config = JSON.parse(readFileSync(join(root, '.torch', 'torch.yaml')));
|
|
assert.deepEqual(config.runtimes.codex.updatePolicy, { mode: 'auto', max_age_hours: 24 });
|
|
git(['add', '.torch']); git(['commit', '-m', 'config']);
|
|
createWorktrees({ repository: inspectRepository(root), parentOverride: join(f.env.XDG_DATA_HOME, 'worktrees') });
|
|
assert.equal(await run(['up', '--fresh', '--only', 'session-manager', '--dry-run', '--json']), 0);
|
|
assert.equal(f.calls.length, 0, 'dry-run never downloads or launches');
|
|
assert.equal(await run(['up', '--fresh', '--only', 'session-manager', '--yes', '--json']), 0);
|
|
const selected = managedProvider('codex', f);
|
|
const launches = f.calls.filter(c => c.args.includes('exec'));
|
|
assert.equal(launches.length, 1);
|
|
assert.equal(launches[0].command, selected.executable);
|
|
assert.equal(f.calls.some(c => c.args.at(-1)?.startsWith('@anthropic-ai/')), false);
|
|
const pointer = join(providerStore(f.env), 'codex.json');
|
|
const stale = JSON.parse(readFileSync(pointer)); stale.checkedAt = '2000-01-01T00:00:00Z';
|
|
writeFileSync(pointer, JSON.stringify(stale)); f.next('1.3.0'); f.breakInstall();
|
|
assert.equal(await run(['up', '--only', 'session-manager', '--yes', '--json']), 2);
|
|
assert.equal(f.calls.filter(c => c.args.includes('exec')).length, 1, 'failed refresh must not launch the old provider silently');
|
|
assert.equal(outputs.some(s => s.includes('RUNTIME_UPDATE_FAILED')), true);
|
|
} finally { process.stdout.write = stdout; }
|
|
});
|
|
|
|
test('SCN-provider-updates-recovery: failed updates retain last activation; tampering and concurrent updates stop', () => {
|
|
const f = fixture();
|
|
updateProviders(['codex'], { ...f, authorized: true });
|
|
const active = managedProvider('codex', f);
|
|
f.next('1.3.0'); f.breakInstall();
|
|
assert.throws(() => updateProviders(['codex'], { ...f, authorized: true, force: true }), { code: 'RUNTIME_UPDATE_FAILED' });
|
|
assert.equal(managedProvider('codex', f).executable, active.executable);
|
|
assert.equal(managedProvider('codex', f).version, '1.2.3');
|
|
mkdirSync(join(providerStore(f.env), 'update.lock'));
|
|
assert.throws(() => updateProviders(['codex'], { ...f, authorized: true }), { code: 'RUNTIME_UPDATE_BUSY' });
|
|
writeFileSync(active.executable, 'tampered');
|
|
assert.throws(() => managedProvider('codex', f), { code: 'RUNTIME_UPDATE_FAILED' });
|
|
});
|
|
|
|
test('SCN-provider-update-safety: arbitrary packages, unsafe registry versions, path escape and symlink stores fail closed', () => {
|
|
const f = fixture();
|
|
assert.throws(() => planProviderUpdates(['untrusted-command'], f), { code: 'RUNTIME_UPDATE_FAILED' });
|
|
f.next('1.2.3;touch /tmp/evil');
|
|
assert.throws(() => updateProviders(['codex'], { ...f, authorized: true }), { code: 'RUNTIME_UPDATE_FAILED' });
|
|
assert.equal(f.calls.some(c => c.args[0] === 'install'), false);
|
|
f.next('1.2.3'); updateProviders(['codex'], { ...f, authorized: true });
|
|
const path = join(providerStore(f.env), 'codex.json');
|
|
const record = JSON.parse(readFileSync(path));
|
|
record.prefix = tmpdir(); writeFileSync(path, JSON.stringify(record));
|
|
assert.throws(() => managedProvider('codex', f), { code: 'RUNTIME_UPDATE_FAILED' });
|
|
const other = fixture();
|
|
mkdirSync(join(other.env.XDG_DATA_HOME, 'torch'));
|
|
symlinkSync(tmpdir(), providerStore(other.env));
|
|
assert.throws(() => planProviderUpdates(['pi'], other), { code: 'RUNTIME_UPDATE_FAILED' });
|
|
});
|