mirror of
https://github.com/PR0M3TH3AN/TORCH.git
synced 2026-10-27 07:51:52 +00:00
476 lines
27 KiB
JavaScript
476 lines
27 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import { execFileSync, spawnSync } from 'node:child_process';
|
|
import { mkdtempSync, readFileSync, writeFileSync } from 'node:fs';
|
|
import { tmpdir } from 'node:os';
|
|
import { basename, join } from 'node:path';
|
|
import test from 'node:test';
|
|
import { createClaudeAdapter } from '../../src/adapters/claude.mjs';
|
|
import { createCodexAdapter } from '../../src/adapters/codex.mjs';
|
|
import { createPiAdapter } from '../../src/adapters/pi.mjs';
|
|
import { createRuntimeAdapterRegistry } from '../../src/adapters/registry.mjs';
|
|
import { createConsoleServer } from '../../src/console/server.mjs';
|
|
import { openControlPlane } from '../../src/control-plane/service.mjs';
|
|
import { analyzeRepository } from '../../src/kernel/analyze.mjs';
|
|
import { proposeDomains } from '../../src/kernel/domains.mjs';
|
|
import { diagnoseProject } from '../../src/kernel/doctor.mjs';
|
|
import { inspectRepository } from '../../src/kernel/git.mjs';
|
|
import { installProject } from '../../src/kernel/install.mjs';
|
|
import { createWorktrees } from '../../src/kernel/worktrees.mjs';
|
|
import { planAreaUp, planFleetUp } from '../../src/runtime/lifecycle.mjs';
|
|
import { unsupportedCapability } from '../../src/adapters/runtime.mjs';
|
|
import { observeProject } from '../../src/observability/snapshot.mjs';
|
|
|
|
function localAdapter() {
|
|
return {
|
|
name: 'local-agent',
|
|
configuration: { worker_pool: 'local' },
|
|
capabilities: {
|
|
detect: true, configure: 'plan-only', modelSelection: true, reasoningSelection: true,
|
|
perInvocationCostCeiling: { createSession: [], resumeSession: [] },
|
|
createSession: true, resumeSession: true, sendOrSteer: false, getStatus: false,
|
|
listSessions: false, stopSession: false, captureRuntimeId: false,
|
|
installHooks: false, removeHooks: false,
|
|
},
|
|
detect: () => ({ available: true, adapter: 'local-agent' }),
|
|
configure: ({ repositoryRoot, areaId }) => ({
|
|
adapter: 'local-agent', mutationPerformed: false,
|
|
mcp: { name: `torch-${areaId}`, command: process.execPath, args: [], cwd: repositoryRoot },
|
|
}),
|
|
createSession: ({ areaId, worktree, model, reasoning }) => ({
|
|
adapter: 'local-agent', areaId, runtimeSessionId: null,
|
|
requiresRuntimeIdCapture: false,
|
|
profile: { model, reasoning },
|
|
launch: { command: 'local-agent', args: [model, reasoning], cwd: worktree, mutatesRuntime: true },
|
|
}),
|
|
resumeSession: ({ areaId, runtimeSessionId, worktree, model, reasoning }) => ({
|
|
adapter: 'local-agent', areaId, runtimeSessionId,
|
|
profile: { model, reasoning },
|
|
launch: { command: 'local-agent', args: [model, reasoning], cwd: worktree, mutatesRuntime: true },
|
|
}),
|
|
sendOrSteer() { return unsupportedCapability(this.name, 'sendOrSteer'); },
|
|
getStatus() { return unsupportedCapability(this.name, 'getStatus'); },
|
|
listSessions() { return unsupportedCapability(this.name, 'listSessions'); },
|
|
stopSession() { return unsupportedCapability(this.name, 'stopSession'); },
|
|
captureRuntimeId() { return unsupportedCapability(this.name, 'captureRuntimeId'); },
|
|
installHooks() { return unsupportedCapability(this.name, 'installHooks'); },
|
|
removeHooks() { return unsupportedCapability(this.name, 'removeHooks'); },
|
|
};
|
|
}
|
|
|
|
function fixture(registry) {
|
|
const root = mkdtempSync(join(tmpdir(), 'torch-runtime-profiles-'));
|
|
const env = { ...process.env, XDG_DATA_HOME: join(tmpdir(), `${basename(root)}-state`) };
|
|
execFileSync('git', ['init', '-b', 'main', root]);
|
|
execFileSync('git', ['-C', root, 'config', 'user.email', '[email protected]']);
|
|
execFileSync('git', ['-C', root, 'config', 'user.name', 'TORCH Test']);
|
|
writeFileSync(join(root, 'app.js'), 'export const app = true;\n');
|
|
execFileSync('git', ['-C', root, 'add', '.']);
|
|
execFileSync('git', ['-C', root, 'commit', '-m', 'fixture']);
|
|
const repository = inspectRepository(root);
|
|
const proposal = proposeDomains({ repository, analysis: analyzeRepository(repository) });
|
|
const worker = proposal.domains[0];
|
|
worker.runtime = 'codex';
|
|
worker.model = 'gpt-worker';
|
|
worker.reasoning = null;
|
|
worker.resources = [];
|
|
proposal.session_manager = {
|
|
runtime: 'claude', model: 'claude-manager', reasoning: 'high',
|
|
};
|
|
proposal.domains.push({
|
|
id: 'docs', title: 'Documentation', scope: ['documentation maintenance'],
|
|
not_scope: ['application implementation'], owned_paths: ['docs/**'], shared_paths: [],
|
|
neighbours: [worker.id], required_checks: [], resources: [],
|
|
runtime: 'local-agent', model: 'manual-model', reasoning: 'deep',
|
|
});
|
|
proposal.domains.push({
|
|
id: 'codex-defaults', title: 'Codex Defaults', scope: ['default Codex profile'],
|
|
not_scope: ['application implementation'], owned_paths: ['defaults/**'], shared_paths: [],
|
|
neighbours: [], required_checks: [], resources: [], runtime: 'codex',
|
|
});
|
|
proposal.review = {
|
|
status: 'approved', reviewedAt: '2026-09-28T00:00:00Z', reviewedBy: 'fixture-owner', notes: [],
|
|
};
|
|
installProject({
|
|
repository, proposal, env, projectId: 'runtime-profile-fixture',
|
|
runtimes: ['claude', 'codex', 'local-agent'], runtimeRegistry: registry,
|
|
});
|
|
execFileSync('git', ['-C', root, 'add', '.torch']);
|
|
execFileSync('git', ['-C', root, 'commit', '-m', 'install torch']);
|
|
createWorktrees({ repository: inspectRepository(root), parentOverride: join(tmpdir(), `${basename(root)}-worktrees`) });
|
|
return { root, env, worker: worker.id };
|
|
}
|
|
|
|
test('SCN-runtime-profiles: each identity launches through its assigned adapter and profile', () => {
|
|
const registry = createRuntimeAdapterRegistry({ adapters: [localAdapter()] });
|
|
const context = fixture(registry);
|
|
const control = openControlPlane({ repositoryRoot: context.root, env: context.env });
|
|
const adapters = registry.toMap();
|
|
adapters.set('codex', createCodexAdapter({ executable: 'codex' }));
|
|
adapters.set('claude', createClaudeAdapter({ executable: 'claude' }));
|
|
|
|
const plan = planFleetUp({
|
|
repositoryRoot: context.root, controlPlane: control, adapters, fresh: true,
|
|
});
|
|
assert.equal(plan.canProceed, true, JSON.stringify(plan.blockers));
|
|
const worker = plan.actions.find((action) => action.areaId === context.worker);
|
|
const docs = plan.actions.find((action) => action.areaId === 'docs');
|
|
const manager = plan.actions.find((action) => action.areaId === 'session-manager');
|
|
const defaultCodex = plan.actions.find((action) => action.areaId === 'codex-defaults');
|
|
assert.equal(worker.runtime, 'codex');
|
|
assert.deepEqual(worker.profile, { model: 'gpt-worker', reasoning: 'high', launchPolicy: { approval: 'approve-for-me' } });
|
|
assert.equal(worker.launch.args.includes('gpt-worker'), true);
|
|
assert.equal(worker.profile.reasoning, 'high', 'omitted identity reasoning inherits Codex default');
|
|
assert.equal(manager.runtime, 'claude');
|
|
assert.deepEqual(manager.profile, { model: 'claude-manager', reasoning: 'high', launchPolicy: {} });
|
|
assert.deepEqual(manager.launch.args.slice(manager.launch.args.indexOf('--effort'), manager.launch.args.indexOf('--effort') + 2), ['--effort', 'high']);
|
|
assert.deepEqual(defaultCodex.profile, { model: 'gpt-6-luna', reasoning: 'high', launchPolicy: { approval: 'approve-for-me' } });
|
|
assert.equal(defaultCodex.launch.args.includes('gpt-6-luna'), true);
|
|
assert.equal(defaultCodex.launch.args.includes('model_reasoning_effort="high"'), true);
|
|
assert.deepEqual(
|
|
(({ runtime, model, reasoning }) => ({ runtime, model, reasoning }))(control.identity('codex-defaults')),
|
|
{ runtime: 'codex', model: 'gpt-6-luna', reasoning: 'high' },
|
|
'live identity query resolves and exposes the configured adapter defaults',
|
|
);
|
|
assert.deepEqual(
|
|
(({ runtime, model, reasoning }) => ({ runtime, model, reasoning }))(control.identity('session-manager')),
|
|
{ runtime: 'claude', model: 'claude-manager', reasoning: 'high' },
|
|
'identity-specific runtime profile overrides remain visible',
|
|
);
|
|
assert.equal(docs.runtime, 'local-agent');
|
|
assert.deepEqual(docs.profile, { model: 'manual-model', reasoning: 'deep', launchPolicy: {} });
|
|
assert.deepEqual(docs.launch.args, ['manual-model', 'deep']);
|
|
assert.equal(plan.mutationPerformed, false);
|
|
|
|
const configPath = join(context.root, '.torch', 'torch.yaml');
|
|
const config = JSON.parse(readFileSync(configPath, 'utf8'));
|
|
assert.deepEqual(config.runtimes.codex, {
|
|
model: 'gpt-6-luna', reasoning: 'high', launchPolicy: { approval: 'approve-for-me' },
|
|
});
|
|
assert.deepEqual(config.runtimes.claude, { model: 'sonnet', background: true });
|
|
assert.equal(config.session_manager.model, 'claude-manager', 'identity overrides remain independent');
|
|
config.runtimes.codex.launchPolicy = { sandbox: 'workspace-write', approval: 'on-request' };
|
|
config.domains.find((area) => area.id === context.worker).launchPolicy = { approval: 'never' };
|
|
config.session_manager.launchPolicy = { permissionMode: 'acceptEdits' };
|
|
writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`);
|
|
const policyPlan = planFleetUp({ repositoryRoot: context.root, controlPlane: control, adapters, fresh: true });
|
|
assert.equal(policyPlan.canProceed, true, JSON.stringify(policyPlan.blockers));
|
|
const policyWorker = policyPlan.actions.find((action) => action.areaId === context.worker);
|
|
const policyDefault = policyPlan.actions.find((action) => action.areaId === 'codex-defaults');
|
|
const policyManager = policyPlan.actions.find((action) => action.areaId === 'session-manager');
|
|
assert.deepEqual(policyWorker.profile.launchPolicy, { sandbox: 'workspace-write', approval: 'never' });
|
|
assert.ok(policyWorker.launch.args.includes('--sandbox'));
|
|
assert.ok(policyWorker.launch.args.includes('workspace-write'));
|
|
assert.ok(policyWorker.launch.args.includes('--ask-for-approval'));
|
|
assert.ok(policyWorker.launch.args.includes('never'));
|
|
assert.deepEqual(policyDefault.profile.launchPolicy, { sandbox: 'workspace-write', approval: 'on-request' });
|
|
assert.ok(policyDefault.launch.args.includes('--ask-for-approval'));
|
|
assert.ok(policyDefault.launch.args.includes('on-request'));
|
|
assert.ok(policyManager.launch.args.includes('--permission-mode'));
|
|
assert.ok(policyManager.launch.args.includes('acceptEdits'));
|
|
assert.equal(policyPlan.mutationPerformed, false, 'policy resolution only changes a future launch plan');
|
|
assert.equal(policyPlan.actions.every((action) => action.launch.mutatesRuntime), true, 'plan describes launches but starts none');
|
|
|
|
const invalidConfig = JSON.parse(readFileSync(configPath, 'utf8'));
|
|
invalidConfig.runtimes.codex.launchPolicy = { sandbox: 'workspace-write', approval: 'approve-for-me' };
|
|
writeFileSync(configPath, `${JSON.stringify(invalidConfig, null, 2)}\n`);
|
|
const conflictPlan = planFleetUp({ repositoryRoot: context.root, controlPlane: control, adapters, fresh: true });
|
|
assert.equal(conflictPlan.canProceed, false);
|
|
assert.ok(conflictPlan.blockers.some((blocker) => blocker.code === 'RUNTIME_PROFILE_UNSUPPORTED'
|
|
&& blocker.capabilities.some((issue) => issue.conflictsWith === 'launchPolicy.sandbox')));
|
|
invalidConfig.runtimes.codex.launchPolicy = { approval: 'never' };
|
|
invalidConfig.domains.find((area) => area.id === 'docs').launchPolicy = { permissionMode: 'bypassPermissions' };
|
|
writeFileSync(configPath, `${JSON.stringify(invalidConfig, null, 2)}\n`);
|
|
const unsafePlan = planFleetUp({ repositoryRoot: context.root, controlPlane: control, adapters, fresh: true });
|
|
assert.equal(unsafePlan.canProceed, false, 'unsafe Claude permission modes block before execution');
|
|
assert.ok(unsafePlan.blockers.some((blocker) => blocker.areaId === 'docs' && blocker.code === 'RUNTIME_PROFILE_UNSUPPORTED'));
|
|
invalidConfig.domains.find((area) => area.id === 'docs').launchPolicy = { sandbox: 'workspace-write' };
|
|
writeFileSync(configPath, `${JSON.stringify(invalidConfig, null, 2)}\n`);
|
|
const unsupportedPlan = planFleetUp({ repositoryRoot: context.root, controlPlane: control, adapters, fresh: true });
|
|
assert.equal(unsupportedPlan.canProceed, false, 'custom adapter without a launch-policy declaration fails closed');
|
|
assert.ok(unsupportedPlan.blockers.some((blocker) => blocker.areaId === 'docs' && blocker.code === 'RUNTIME_PROFILE_UNSUPPORTED'));
|
|
delete invalidConfig.domains.find((area) => area.id === 'docs').launchPolicy;
|
|
writeFileSync(configPath, `${JSON.stringify(invalidConfig, null, 2)}\n`);
|
|
const snapshot = observeProject({ repositoryRoot: context.root, env: context.env, runtimeRegistry: registry });
|
|
assert.deepEqual(
|
|
snapshot.agents.find((agent) => agent.areaId === 'codex-defaults')
|
|
&& { model: snapshot.agents.find((agent) => agent.areaId === 'codex-defaults').model,
|
|
reasoning: snapshot.agents.find((agent) => agent.areaId === 'codex-defaults').reasoning },
|
|
{ model: 'gpt-6-luna', reasoning: 'high' },
|
|
'dashboard snapshot surfaces effective adapter defaults',
|
|
);
|
|
config.runtimes.codex.reasoning = 'medium';
|
|
config.runtimes.codex.model = 'gpt-6-luna-custom';
|
|
writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`);
|
|
const editedProfilePlan = planFleetUp({
|
|
repositoryRoot: context.root, controlPlane: control, adapters, fresh: true,
|
|
});
|
|
assert.equal(editedProfilePlan.canProceed, true, 'owner can change the project default without replacing the adapter');
|
|
const editedDefault = editedProfilePlan.actions.find((action) => action.areaId === 'codex-defaults');
|
|
assert.deepEqual(editedDefault.profile, {
|
|
model: 'gpt-6-luna-custom', reasoning: 'medium',
|
|
launchPolicy: { sandbox: 'workspace-write', approval: 'on-request' },
|
|
});
|
|
assert.equal(editedDefault.launch.args.includes('gpt-6-luna-custom'), true);
|
|
assert.equal(editedDefault.launch.args.includes('model_reasoning_effort="medium"'), true);
|
|
assert.equal(editedProfilePlan.mutationPerformed, false, 'profile changes only affect a future reviewed launch');
|
|
const editedSnapshot = observeProject({ repositoryRoot: context.root, env: context.env, runtimeRegistry: registry });
|
|
const editedAgent = editedSnapshot.agents.find((agent) => agent.areaId === 'codex-defaults');
|
|
assert.deepEqual({ model: editedAgent.model, reasoning: editedAgent.reasoning }, {
|
|
model: 'gpt-6-luna-custom', reasoning: 'medium',
|
|
});
|
|
const diagnosis = diagnoseProject({
|
|
repository: inspectRepository(context.root), env: context.env, runtimeRegistry: registry,
|
|
});
|
|
assert.equal(diagnosis.findings.some((finding) => finding.code === 'RUNTIME_PROFILE_UNSUPPORTED'), false);
|
|
assert.equal(diagnosis.findings.some((finding) => finding.code === 'RUNTIME_ADAPTER_UNKNOWN'
|
|
&& finding.runtime === 'local-agent'), false);
|
|
control.close();
|
|
});
|
|
|
|
test('SCN-runtime-cost-ceiling: exact session mode must declare and return an enforced per-invocation USD cap', () => {
|
|
const builtinAdapters = [
|
|
createClaudeAdapter({ executable: 'claude' }),
|
|
createCodexAdapter({ executable: 'codex' }),
|
|
createPiAdapter({ executable: 'pi' }),
|
|
];
|
|
for (const adapter of builtinAdapters) {
|
|
assert.deepEqual(adapter.capabilities.perInvocationCostCeiling, {
|
|
createSession: [], resumeSession: [],
|
|
});
|
|
}
|
|
|
|
const local = localAdapter();
|
|
local.capabilities = {
|
|
...local.capabilities,
|
|
perInvocationCostCeiling: { createSession: ['fixture-hard-cap'], resumeSession: [] },
|
|
};
|
|
const create = local.createSession;
|
|
local.createSession = (input) => {
|
|
const plan = create(input);
|
|
if (input.maxCostUsd === undefined) return plan;
|
|
return {
|
|
...plan,
|
|
costCeiling: { enforced: true, maxUsd: input.maxCostUsd, mode: 'fixture-hard-cap' },
|
|
launch: { ...plan.launch, args: [...plan.launch.args, '--max-cost-usd', String(input.maxCostUsd)] },
|
|
};
|
|
};
|
|
const registry = createRuntimeAdapterRegistry({ adapters: [local] });
|
|
const context = fixture(registry);
|
|
const control = openControlPlane({ repositoryRoot: context.root, env: context.env });
|
|
const uncapped = planAreaUp({
|
|
repositoryRoot: context.root, controlPlane: control, areaId: 'session-manager',
|
|
adapter: createClaudeAdapter({ executable: 'claude' }), maxCostUsd: 0.25,
|
|
});
|
|
assert.equal(uncapped.canProceed, false);
|
|
assert.equal(uncapped.actions.length, 0);
|
|
assert.equal(uncapped.blockers[0].code, 'RUNTIME_COST_CEILING_UNSUPPORTED');
|
|
|
|
const capped = planAreaUp({
|
|
repositoryRoot: context.root, controlPlane: control, areaId: 'docs', adapter: local, maxCostUsd: 0.25,
|
|
});
|
|
assert.equal(capped.canProceed, true, JSON.stringify(capped.blockers));
|
|
assert.deepEqual(capped.actions[0].costCeiling, {
|
|
enforced: true, maxUsd: 0.25, mode: 'fixture-hard-cap',
|
|
});
|
|
assert.deepEqual(capped.actions[0].launch.args.slice(-2), ['--max-cost-usd', '0.25']);
|
|
assert.equal(capped.mutationPerformed, false, 'planning does not invoke the runtime');
|
|
|
|
const deceptive = {
|
|
...local,
|
|
createSession: (input) => ({
|
|
...local.createSession(input),
|
|
costCeiling: { enforced: true, maxUsd: 10, mode: 'fixture-hard-cap' },
|
|
}),
|
|
};
|
|
const rejected = planAreaUp({
|
|
repositoryRoot: context.root, controlPlane: control, areaId: 'docs', adapter: deceptive, maxCostUsd: 0.25,
|
|
});
|
|
assert.equal(rejected.canProceed, false, 'an adapter receipt for a different cap must fail closed');
|
|
assert.equal(rejected.actions.length, 0);
|
|
assert.equal(rejected.blockers[0].code, 'RUNTIME_COST_CEILING_UNPROVEN');
|
|
control.close();
|
|
});
|
|
|
|
test('SCN-runtime-profile-cli: owner can change and reset project-local profiles without launching sessions', () => {
|
|
const context = fixture(createRuntimeAdapterRegistry({ adapters: [localAdapter()] }));
|
|
const cli = new URL('../../bin/torch.mjs', import.meta.url).pathname;
|
|
const run = (...args) => spawnSync(process.execPath, [cli, 'profile', ...args], {
|
|
cwd: context.root, env: context.env, encoding: 'utf8',
|
|
});
|
|
|
|
const shown = run('show', '--area', 'codex-defaults', '--json');
|
|
assert.equal(shown.status, 0, shown.stderr);
|
|
assert.deepEqual(JSON.parse(shown.stdout), {
|
|
areaId: 'codex-defaults', runtime: 'codex', model: 'gpt-6-luna', reasoning: 'high',
|
|
launchPolicy: { approval: 'approve-for-me' },
|
|
overrides: { runtime: true, model: false, reasoning: false, launchPolicy: false },
|
|
});
|
|
|
|
const refused = run('set', '--area', 'codex-defaults', '--model', 'gpt-custom', '--json');
|
|
assert.equal(refused.status, 2);
|
|
assert.match(refused.stdout, /--yes/);
|
|
|
|
const dryRun = run('set', '--area', 'codex-defaults', '--runtime', 'claude', '--model', 'dry-run-opus', '--dry-run', '--json');
|
|
assert.equal(dryRun.status, 0, dryRun.stderr);
|
|
assert.equal(JSON.parse(dryRun.stdout).beforeProfile.runtime, 'codex');
|
|
assert.equal(JSON.parse(dryRun.stdout).profile.runtime, 'claude');
|
|
assert.equal(JSON.parse(dryRun.stdout).mutationPerformed, false);
|
|
|
|
const configPath = join(context.root, '.torch', 'torch.yaml');
|
|
const legacyConfig = JSON.parse(readFileSync(configPath, 'utf8'));
|
|
delete legacyConfig.runtimes.codex.launchPolicy;
|
|
legacyConfig.runtimes.codex.sandbox = 'workspace-write';
|
|
legacyConfig.runtimes.codex.approval = 'approve-for-me';
|
|
writeFileSync(configPath, `${JSON.stringify(legacyConfig, null, 2)}\n`);
|
|
const migrated = run('defaults', '--runtime', 'codex', '--launch-policy', 'approval=never', '--yes', '--json');
|
|
assert.equal(migrated.status, 0, migrated.stderr);
|
|
assert.deepEqual(JSON.parse(migrated.stdout).profile.launchPolicy, {
|
|
sandbox: 'workspace-write', approval: 'never',
|
|
});
|
|
const migratedConfig = JSON.parse(readFileSync(configPath, 'utf8'));
|
|
assert.deepEqual(migratedConfig.runtimes.codex.launchPolicy, {
|
|
sandbox: 'workspace-write', approval: 'never',
|
|
}, 'leaving the implicit approve-for-me mode preserves its workspace-write sandbox');
|
|
assert.equal(Object.hasOwn(migratedConfig.runtimes.codex, 'sandbox'), false);
|
|
assert.equal(Object.hasOwn(migratedConfig.runtimes.codex, 'approval'), false);
|
|
const migratedArgs = createCodexAdapter({ executable: 'codex' }).createSession({
|
|
areaId: 'migrated', worktree: context.root, promptFile: '/tmp/prompt.md', firstMessage: 'start',
|
|
model: 'gpt-6-luna', launchPolicy: migratedConfig.runtimes.codex.launchPolicy,
|
|
}).launch.args;
|
|
assert.deepEqual(migratedArgs.slice(migratedArgs.indexOf('--sandbox'), migratedArgs.indexOf('--sandbox') + 2),
|
|
['--sandbox', 'workspace-write']);
|
|
assert.deepEqual(migratedArgs.slice(migratedArgs.indexOf('--ask-for-approval'), migratedArgs.indexOf('--ask-for-approval') + 2),
|
|
['--ask-for-approval', 'never']);
|
|
const resetPolicy = run('defaults', '--runtime', 'codex', '--reset-launch-policy', '--yes', '--json');
|
|
assert.equal(resetPolicy.status, 0, resetPolicy.stderr);
|
|
assert.deepEqual(JSON.parse(resetPolicy.stdout).profile.launchPolicy, { approval: 'approve-for-me' });
|
|
|
|
const changed = run(
|
|
'set', '--area', 'codex-defaults', '--runtime', 'claude', '--model', 'opus', '--reasoning', 'high', '--yes', '--json',
|
|
);
|
|
assert.equal(changed.status, 0, changed.stderr);
|
|
const changeReceipt = JSON.parse(changed.stdout);
|
|
assert.deepEqual(changeReceipt.profile, {
|
|
areaId: 'codex-defaults', runtime: 'claude', model: 'opus', reasoning: 'high',
|
|
launchPolicy: {},
|
|
overrides: { runtime: true, model: true, reasoning: true, launchPolicy: false },
|
|
});
|
|
assert.equal(changeReceipt.sessionsStarted, false);
|
|
assert.equal(changeReceipt.existingSessionChanged, false);
|
|
|
|
const reset = run('set', '--area', 'codex-defaults', '--reset', '--yes', '--json');
|
|
assert.equal(reset.status, 0, reset.stderr);
|
|
assert.deepEqual(JSON.parse(reset.stdout).profile, {
|
|
areaId: 'codex-defaults', runtime: 'claude', model: 'sonnet', reasoning: null,
|
|
launchPolicy: {},
|
|
overrides: { runtime: true, model: false, reasoning: false, launchPolicy: false },
|
|
});
|
|
const config = JSON.parse(readFileSync(join(context.root, '.torch', 'torch.yaml'), 'utf8'));
|
|
assert.equal(config.domains.find((area) => area.id === 'codex-defaults').runtime, 'claude');
|
|
assert.equal(Object.hasOwn(config.domains.find((area) => area.id === 'codex-defaults'), 'model'), false);
|
|
assert.equal(Object.hasOwn(config.domains.find((area) => area.id === 'codex-defaults'), 'reasoning'), false);
|
|
|
|
const defaults = run('defaults', '--runtime', 'codex', '--model', 'gpt-custom', '--reasoning', 'medium', '--yes', '--json');
|
|
assert.equal(defaults.status, 0, defaults.stderr);
|
|
assert.deepEqual(JSON.parse(defaults.stdout).profile, {
|
|
model: 'gpt-custom', reasoning: 'medium', launchPolicy: { approval: 'approve-for-me' },
|
|
});
|
|
const workerProfile = run('show', '--area', context.worker, '--json');
|
|
assert.equal(workerProfile.status, 0, workerProfile.stderr);
|
|
assert.deepEqual(JSON.parse(workerProfile.stdout), {
|
|
areaId: context.worker, runtime: 'codex', model: 'gpt-worker', reasoning: 'medium',
|
|
launchPolicy: { approval: 'approve-for-me' },
|
|
overrides: { runtime: true, model: true, reasoning: false, launchPolicy: false },
|
|
});
|
|
|
|
const audit = openControlPlane({ repositoryRoot: context.root, env: context.env });
|
|
const profileEvents = audit.database.prepare(`
|
|
SELECT actor_id, entity_type, entity_id FROM audit_events WHERE operation = 'profile.change' ORDER BY rowid
|
|
`).all();
|
|
assert.equal(profileEvents.length, 5, 'confirmed identity and default edits are audited, dry runs are not');
|
|
assert.ok(profileEvents.every((entry) => entry.actor_id === 'owner'));
|
|
assert.equal(profileEvents.some((entry) => entry.entity_id === 'codex-defaults'), true);
|
|
audit.close();
|
|
});
|
|
|
|
test('SCN-console-runtime-profile: owner previews and confirms an audited next-launch profile without touching running sessions', async (context) => {
|
|
const fixtureState = fixture(createRuntimeAdapterRegistry({ adapters: [localAdapter()] }));
|
|
const server = createConsoleServer({ repositoryRoot: fixtureState.root, env: fixtureState.env });
|
|
await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve));
|
|
context.after(() => server.close());
|
|
const origin = `http://127.0.0.1:${server.address().port}`;
|
|
const post = (path, body, requestOrigin = origin) => fetch(`${origin}${path}`, {
|
|
method: 'POST', headers: { origin: requestOrigin, 'content-type': 'application/json', 'sec-fetch-site': 'same-origin' },
|
|
body: JSON.stringify(body),
|
|
});
|
|
const configPath = join(fixtureState.root, '.torch', 'torch.yaml');
|
|
const configBefore = readFileSync(configPath, 'utf8');
|
|
const crossOrigin = await post('/api/runtime-profiles/preview', {
|
|
areaId: 'codex-defaults', runtime: 'claude', model: 'opus', reasoning: 'high',
|
|
}, 'http://attacker.invalid');
|
|
assert.equal(crossOrigin.status, 403);
|
|
|
|
const firstPreviewResponse = await post('/api/runtime-profiles/preview', {
|
|
areaId: 'codex-defaults', runtime: 'claude', model: 'opus', reasoning: 'high',
|
|
});
|
|
assert.equal(firstPreviewResponse.status, 200);
|
|
const firstPreview = await firstPreviewResponse.json();
|
|
assert.equal(firstPreview.plan.mutationPerformed, false);
|
|
assert.equal(firstPreview.plan.beforeProfile.runtime, 'codex');
|
|
assert.equal(firstPreview.plan.profile.runtime, 'claude');
|
|
assert.equal(firstPreview.plan.profile.model, 'opus');
|
|
assert.equal(firstPreview.plan.resetLaunchPolicy, true);
|
|
assert.match(firstPreview.plan.effect, /future launch plans only/);
|
|
assert.equal(readFileSync(configPath, 'utf8'), configBefore, 'preview is read-only');
|
|
|
|
const changedConfig = JSON.parse(configBefore);
|
|
changedConfig.runtimes.claude.reasoning = 'medium';
|
|
writeFileSync(configPath, `${JSON.stringify(changedConfig, null, 2)}\n`);
|
|
const stale = await post('/api/runtime-profiles', {
|
|
areaId: 'codex-defaults', runtime: 'claude', model: 'opus', reasoning: 'high',
|
|
token: firstPreview.token, planHash: firstPreview.planHash,
|
|
});
|
|
assert.equal(stale.status, 409);
|
|
assert.equal((await stale.json()).error, 'RUNTIME_PROFILE_PREVIEW_STALE');
|
|
|
|
const previewResponse = await post('/api/runtime-profiles/preview', {
|
|
areaId: 'codex-defaults', runtime: 'claude', model: 'opus', reasoning: 'high',
|
|
});
|
|
assert.equal(previewResponse.status, 200);
|
|
const preview = await previewResponse.json();
|
|
const payload = {
|
|
areaId: 'codex-defaults', runtime: 'claude', model: 'opus', reasoning: 'high',
|
|
token: preview.token, planHash: preview.planHash,
|
|
};
|
|
const confirmed = await post('/api/runtime-profiles', payload);
|
|
assert.equal(confirmed.status, 200, await confirmed.clone().text());
|
|
const result = await confirmed.json();
|
|
assert.deepEqual(
|
|
{ runtime: result.profile.runtime, model: result.profile.model, reasoning: result.profile.reasoning },
|
|
{ runtime: 'claude', model: 'opus', reasoning: 'high' },
|
|
);
|
|
assert.equal(result.sessionsStarted, false);
|
|
assert.equal(result.existingSessionChanged, false);
|
|
const replay = await post('/api/runtime-profiles', payload);
|
|
assert.equal(replay.status, 200);
|
|
assert.deepEqual(await replay.json(), result);
|
|
|
|
const verify = openControlPlane({ repositoryRoot: fixtureState.root, env: fixtureState.env });
|
|
const event = verify.database.prepare(`
|
|
SELECT actor_id, entity_type, entity_id, details FROM audit_events WHERE operation = 'profile.change' ORDER BY rowid DESC LIMIT 1
|
|
`).get();
|
|
assert.equal(event.actor_id, 'owner');
|
|
assert.equal(event.entity_type, 'runtime-profile');
|
|
assert.equal(event.entity_id, 'codex-defaults');
|
|
assert.equal(JSON.parse(event.details).after.runtime, 'claude');
|
|
verify.close();
|
|
|
|
const html = readFileSync(new URL('../../site/console.html', import.meta.url), 'utf8');
|
|
const client = readFileSync(new URL('../../site/console.js', import.meta.url), 'utf8');
|
|
assert.match(html, /data-runtime-profile-preview/);
|
|
assert.match(html, /data-profile-before/);
|
|
assert.match(html, /Running sessions are not changed or restarted/);
|
|
assert.match(client, /\/api\/runtime-profiles\/preview/);
|
|
assert.match(client, /\/api\/runtime-profiles'/);
|
|
});
|