Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 161 additions & 0 deletions cli/__tests__/adapters.claude.environment.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,167 @@ describe('claude adapter — ctx.environment', () => {
expect(calls).toHaveLength(0);
});

// Vera 69548: a mode-less public block used to fall straight through to the
// bare `claude` spawn — a record claiming confinement it never got. The
// derived record stores trust only (the block is portable, the host is not),
// so the adapter has to resolve the mode here.
test('public trust with NO mode resolves to Seatbelt workspace on darwin', async () => {
const originalPlatform = process.platform;
const publicState = fs.mkdtempSync(path.join(os.tmpdir(), 'cli-claude-public-state-'));
const { impl, calls } = makeSpawnImpl();
try {
Object.defineProperty(process, 'platform', { value: 'darwin' });
spawnSync.mockImplementation((cmd) => (
cmd === 'which'
? { status: 0, stdout: '/usr/bin/true\n' }
: { status: 0, stdout: '' }
));

await claude.spawn('hi', {
agentName: 'derived-sandbox',
sessionId: null,
cwd,
env: { PATH: process.env.PATH },
environment: { sandbox: { trust: 'public' } },
_publicClaudeState: publicState,
_spawnImpl: impl,
});

expect(calls).toHaveLength(1);
expect(calls[0].cmd).toBe('/usr/bin/sandbox-exec');
expect(calls[0].args[1]).toContain('(deny default)');
expect(calls[0].args).toContain('--setting-sources');
expect(calls[0].args).toContain('--permission-mode');
} finally {
Object.defineProperty(process, 'platform', { value: originalPlatform });
spawnSync.mockReset();
fs.rmSync(publicState, { recursive: true, force: true });
}
});

test('public trust with NO mode resolves to bwrap off darwin, with the same tool policy macOS gets', async () => {
const originalPlatform = process.platform;
const { impl, calls } = makeSpawnImpl();
try {
Object.defineProperty(process, 'platform', { value: 'linux' });
await claude.spawn('hi', {
sessionId: null,
cwd,
env: { PATH: process.env.PATH },
environment: { sandbox: { trust: 'public' } },
_spawnImpl: impl,
_detectBwrap: () => ({ available: true, path: 'bwrap' }),
});
expect(calls).toHaveLength(1);
expect(calls[0].cmd).toBe('bwrap');
expect(calls[0].args).toContain('--unshare-all');
expect(calls[0].args).toContain('--die-with-parent');
// The inner claude argv rides after `--`, inside the namespace.
const inner = calls[0].args.slice(calls[0].args.indexOf('--') + 1);
expect(inner[0]).toMatch(/claude$/);
// The jail bounds the filesystem, the policy bounds the tools — the
// Linux seat gets the same floor as the macOS one, not the half of it
// that happened to be on the other side of a branch (Vera 69578).
const settingSources = inner.indexOf('--setting-sources');
expect(settingSources).toBeGreaterThan(-1);
expect(inner[settingSources + 1]).toBe('');
expect(inner).toContain('--strict-mcp-config');
expect(inner).toContain('--no-chrome');
expect(inner).toEqual(expect.arrayContaining(['--permission-mode', 'dontAsk']));
expect(inner).toContain('--disallowedTools');
expect(inner.join(' ')).toContain('Read(./.env)');
} finally {
Object.defineProperty(process, 'platform', { value: originalPlatform });
}
});

test('a public Linux seat whose host has no bwrap refuses to derive, rather than failing per spawn', async () => {
const originalPlatform = process.platform;
const { impl, calls } = makeSpawnImpl();
try {
Object.defineProperty(process, 'platform', { value: 'linux' });
await expect(claude.spawn('hi', {
sessionId: null,
cwd,
env: { PATH: process.env.PATH },
environment: { sandbox: { trust: 'public' } },
_spawnImpl: impl,
_detectBwrap: () => ({ available: false, error: 'bwrap not found on PATH.' }),
})).rejects.toThrow(/require bwrap: bwrap not found/);
expect(calls).toHaveLength(0);
} finally {
Object.defineProperty(process, 'platform', { value: originalPlatform });
}
});

test('a bwrap seat with no public trust gets the jail without the public tool policy', async () => {
const originalPlatform = process.platform;
const { impl, calls } = makeSpawnImpl();
try {
Object.defineProperty(process, 'platform', { value: 'linux' });
await claude.spawn('hi', {
sessionId: null,
cwd,
env: { PATH: process.env.PATH },
environment: { sandbox: { mode: 'bwrap' } },
_spawnImpl: impl,
_detectBwrap: () => ({ available: true, path: 'bwrap' }),
});
expect(calls).toHaveLength(1);
const inner = calls[0].args.slice(calls[0].args.indexOf('--') + 1);
expect(inner).not.toContain('--setting-sources');
expect(inner).not.toContain('--permission-mode');
} finally {
Object.defineProperty(process, 'platform', { value: originalPlatform });
}
});

test('a legacy trust=internal record is resolved as public and confined, never run unconfined', async () => {
const originalPlatform = process.platform;
const publicState = fs.mkdtempSync(path.join(os.tmpdir(), 'cli-claude-internal-state-'));
const { impl, calls } = makeSpawnImpl();
try {
Object.defineProperty(process, 'platform', { value: 'darwin' });
spawnSync.mockImplementation((cmd) => (
cmd === 'which'
? { status: 0, stdout: '/usr/bin/true\n' }
: { status: 0, stdout: '' }
));

await claude.spawn('hi', {
agentName: 'legacy-internal',
sessionId: null,
cwd,
env: { PATH: process.env.PATH },
environment: { sandbox: { mode: 'workspace', trust: 'internal' } },
_publicClaudeState: publicState,
_spawnImpl: impl,
});

// It reads as "confine me" and used to mean the opposite: before this the
// adapter skipped Seatbelt entirely and spawned a bare, unconfined claude
// (Vera 69592).
expect(calls).toHaveLength(1);
expect(calls[0].cmd).toBe('/usr/bin/sandbox-exec');
expect(calls[0].args).toContain('--setting-sources');
} finally {
Object.defineProperty(process, 'platform', { value: originalPlatform });
spawnSync.mockReset();
fs.rmSync(publicState, { recursive: true, force: true });
}
});

test('public trust with an unresolvable explicit mode refuses rather than falls through', async () => {
const { impl, calls } = makeSpawnImpl();
await expect(claude.spawn('hi', {
sessionId: null,
cwd,
environment: { sandbox: { mode: 'unconfined', trust: 'public' } },
_spawnImpl: impl,
})).rejects.toThrow(/require an enforced sandbox mode/);
expect(calls).toHaveLength(0);
});

// ── ${COMMONLY_*} native MCP environment expansion ────────────────────────
// Values exist only in Claude's per-spawn environment. The JSON retains
// placeholders so a cm_agent_* bearer token never exists on disk.
Expand Down
73 changes: 71 additions & 2 deletions cli/__tests__/adapters.codex.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,41 @@ describe('codex adapter — spawn()', () => {
.toContain('=== Current turn ===\nhi\n=== Before this session ends ===');
});

test('a legacy trust=internal record gets the public profile, never the bypass flag', async () => {
const operatorHome = await mkdtemp(join(tmpdir(), 'commonly-codex-operator-home-'));
const publicHome = await mkdtemp(join(tmpdir(), 'commonly-codex-public-home-'));
const operatorAuth = join(operatorHome, 'auth.json');
await writeFile(operatorAuth, '{"test":true}', 'utf8');
const { impl, calls } = makeSpawnImpl({
stdoutChunks: ['{"type":"thread.started","thread_id":"sid-internal"}\n'],
outputContents: 'ok',
});

await codex.spawn('work safely', {
sessionId: null,
cwd: '/tmp/legacy-internal-workspace',
environment: {
sandbox: { mode: 'workspace', trust: 'internal' },
},
env: { ...process.env, CODEX_HOME: operatorHome },
agentName: 'legacy-internal-agent',
_publicCodexHome: publicHome,
_spawnImpl: impl,
});

// Before this, `internal` read by no adapter meant the operator got the
// bypass flag — the exact opposite of the confinement they declared
// (Vera 69592). It is now read as public and confined.
const args = calls[0].args;
expect(args).not.toContain('--dangerously-bypass-approvals-and-sandbox');
expect(args).not.toContain('--sandbox');
const cFlags = args
.map((a, i) => (a === '-c' ? args[i + 1] : null))
.filter(Boolean);
expect(cFlags).toContain('default_permissions="commonly_public"');
expect(calls[0].opts.env.CODEX_HOME).toBe(publicHome);
});

test('public workspace mode uses a deny-by-default permission profile and never the legacy sandbox or bypass', async () => {
const operatorHome = await mkdtemp(join(tmpdir(), 'commonly-codex-operator-home-'));
const publicHome = await mkdtemp(join(tmpdir(), 'commonly-codex-public-home-'));
Expand Down Expand Up @@ -312,14 +347,48 @@ describe('codex adapter — spawn()', () => {
expect(args).not.toContain('--dangerously-bypass-approvals-and-sandbox');
});

test('public trust fails closed when no enforced public sandbox mode is declared', async () => {
// INVERTED deliberately (TASK-052, Wren 69545): this test used to require a
// throw for a mode-less public record. The derived record stores trust only —
// the block is portable, the host is not — so a mode-less public record must
// now spawn under the public profile with the write-capable workspace default.
// Leaving the throw in place would make every derived codex seat unspawnable,
// which is the same breakage Vera measured on Linux for claude (69542).
test('public trust with no mode defaults to the workspace permission profile', async () => {
const operatorHome = await mkdtemp(join(tmpdir(), 'commonly-codex-operator-home-'));
const publicHome = await mkdtemp(join(tmpdir(), 'commonly-codex-public-home-'));
await writeFile(join(operatorHome, 'auth.json'), '{"test":true}', 'utf8');
const { impl, calls } = makeSpawnImpl({
stdoutChunks: ['{"type":"thread.started","thread_id":"sid-derived"}\n'],
outputContents: 'ok',
});

await codex.spawn('work safely', {
sessionId: null,
cwd: '/tmp/public-agent-workspace',
environment: { sandbox: { trust: 'public' } },
env: { ...process.env, CODEX_HOME: operatorHome },
agentName: 'derived-sandbox-agent',
_publicCodexHome: publicHome,
_spawnImpl: impl,
});

const args = calls[0].args;
const cFlags = args.map((a, i) => (a === '-c' ? args[i + 1] : null)).filter(Boolean);
expect(cFlags).toContain('default_permissions="commonly_public"');
expect(cFlags.find((flag) => flag.startsWith(
'permissions.commonly_public.filesystem=',
))).toContain('"."="write"');
expect(args).not.toContain('--dangerously-bypass-approvals-and-sandbox');
});

test('public trust with an unreadable explicit mode still fails closed', async () => {
const { impl } = makeSpawnImpl({
stdoutChunks: ['{"type":"turn.completed"}\n'],
outputContents: 'should not run',
});

await expect(codex.spawn('x', {
environment: { sandbox: { trust: 'public' } },
environment: { sandbox: { mode: 'unconfined', trust: 'public' } },
_spawnImpl: impl,
})).rejects.toThrow(/require sandbox.mode=workspace or read-only/);
});
Expand Down
Loading
Loading