storebound/tests/bypass.test.ts

39 lines
2.4 KiB
TypeScript

// Bypass mode: off by default; when the owner turns it on, owner-only steps open to the agent and every one is logged.
import { describe, expect, test } from 'bun:test';
import { mkdtempSync, readFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { decide } from '../cli/api/gate';
import { bypassOn, logOwnerAction, setBypass } from '../cli/lib/bypass';
import { listTools, OWNER_STEP, toArgv } from '../cli/mcp-tools';
const owner = { kind: 'owner' as const, method: 'POST', dry: false, yes: true, tty: false, agent: true, getOnly: false, confirm: 'reviewSubmissions_createInstance', opId: 'reviewSubmissions_createInstance' };
describe('bypass mode', () => {
test('off by default; on / off per machine (settings.json)', () => {
const env = { STOREBOUND_HOME: mkdtempSync(join(tmpdir(), 'sb-home-')) };
expect(bypassOn(env)).toBe(false);
setBypass(true, env);
expect(bypassOn(env)).toBe(true);
setBypass(false, env);
expect(bypassOn(env)).toBe(false);
});
test('the api gate: owner operations refused for an agent unless bypass, then only with --yes --confirm <operationId>', () => {
expect(decide(owner).action).toBe('refuse');
expect(decide({ ...owner, bypass: true }).action).toBe('send');
expect(decide({ ...owner, bypass: true, confirm: 'other' }).action).toBe('refuse');
expect(decide({ ...owner, bypass: true, confirm: undefined }).action).toBe('refuse');
expect(decide({ ...owner, bypass: true, yes: false }).action).toBe('dry');
});
test('MCP lists owner_step only in bypass mode; dry run first', () => {
expect(listTools(false).some(t => t.name === 'owner_step')).toBe(false);
expect(listTools(true).some(t => t.name === 'owner_step')).toBe(true);
expect(toArgv(OWNER_STEP, { command: 'apple submit', args: ['--build', '42'] }).argv).toEqual(['apple', 'submit', '--build', '42', '--dry']);
expect(toArgv(OWNER_STEP, { command: 'play rollout', args: ['--percent', '20'], dry_run: false })).toEqual({ argv: ['play', 'rollout', '--percent', '20'], dryRun: false });
});
test('every owner action is logged in the project', () => {
const root = mkdtempSync(join(tmpdir(), 'sb-owner-'));
const f = logOwnerAction(root, { command: 'storebound apple submit --build 42 --yes', dry: false, exit: 0, summary: 'submitted' });
expect(readFileSync(f, 'utf8')).toMatch(/\tRAN\texit 0\tstorebound apple submit --build 42 --yes\tsubmitted\n$/);
});
});