open-design/apps/daemon/tests/sandbox-mode.test.ts
Denis Redozubov 9a3424d68c
feat(daemon): add sandbox runtime foundation (#3242)
* feat(daemon): add sandbox runtime foundation

* fix(daemon): preserve sandbox roots after agent env overrides

* fix(daemon): keep readiness probes pathless

* fix(daemon): harden headless run fallbacks

* fix(daemon): bootstrap sandbox runtime discovery

* fix(daemon): preserve explicit sandbox agent profile mounts

* fix(daemon): keep sandbox profile lookup run scoped

* fix(daemon): normalize sandbox data dir input

* fix(daemon): pin sandbox env roots to base data dir
2026-05-30 15:06:05 +00:00

98 lines
3.4 KiB
TypeScript

import os from 'node:os';
import path from 'node:path';
import { existsSync, mkdtempSync } from 'node:fs';
import { rm } from 'node:fs/promises';
import { afterEach, describe, expect, it } from 'vitest';
import {
applySandboxRuntimeEnv,
ensureSandboxRuntimeDirs,
isSandboxModeEnabled,
resolveSandboxRuntimeConfig,
} from '../src/sandbox-mode.js';
const tempDirs: string[] = [];
afterEach(async () => {
await Promise.all(
tempDirs.splice(0).map((dir) => rm(dir, { recursive: true, force: true })),
);
});
function tempDataDir(): string {
const dir = mkdtempSync(path.join(os.tmpdir(), 'od-sandbox-mode-'));
tempDirs.push(dir);
return dir;
}
describe('sandbox mode env parsing', () => {
it('is disabled when OD_SANDBOX_MODE is unset or false-like', () => {
expect(isSandboxModeEnabled({})).toBe(false);
expect(isSandboxModeEnabled({ OD_SANDBOX_MODE: '0' })).toBe(false);
expect(isSandboxModeEnabled({ OD_SANDBOX_MODE: 'false' })).toBe(false);
});
it('is enabled for explicit true-like values', () => {
expect(isSandboxModeEnabled({ OD_SANDBOX_MODE: '1' })).toBe(true);
expect(isSandboxModeEnabled({ OD_SANDBOX_MODE: 'true' })).toBe(true);
expect(isSandboxModeEnabled({ OD_SANDBOX_MODE: 'YES' })).toBe(true);
});
it('rejects ambiguous non-empty values', () => {
expect(() => isSandboxModeEnabled({ OD_SANDBOX_MODE: 'sandbox' })).toThrow(
'OD_SANDBOX_MODE must be one of',
);
});
});
describe('sandbox runtime roots', () => {
it('keeps all run-scoped roots under OD_DATA_DIR', () => {
const dataDir = tempDataDir();
const config = resolveSandboxRuntimeConfig(true, dataDir);
expect(config.enabled).toBe(true);
for (const dir of Object.values(config.roots)) {
expect(dir === dataDir || dir.startsWith(dataDir + path.sep)).toBe(true);
}
});
it('creates scoped runtime directories only when enabled', () => {
const dataDir = tempDataDir();
const enabled = resolveSandboxRuntimeConfig(true, dataDir);
const disabled = resolveSandboxRuntimeConfig(false, dataDir);
ensureSandboxRuntimeDirs(disabled);
expect(existsSync(enabled.roots.agentHomeDir)).toBe(false);
ensureSandboxRuntimeDirs(enabled);
expect(existsSync(enabled.roots.agentHomeDir)).toBe(true);
expect(existsSync(enabled.roots.previewStateDir)).toBe(true);
expect(existsSync(enabled.roots.toolConfigDir)).toBe(true);
});
it('pins agent home and tool config env to sandbox roots', () => {
const dataDir = tempDataDir();
const config = resolveSandboxRuntimeConfig(true, dataDir);
const env = applySandboxRuntimeEnv(
{
HOME: '/real/home',
CODEX_HOME: '/real/home/.codex',
CLAUDE_CONFIG_DIR: '/real/home/.claude',
OPENCODE_TEST_HOME: '/real/home/.opencode',
NPM_CONFIG_USERCONFIG: '/real/home/.npmrc',
OD_DATA_DIR: dataDir,
PATH: '/bin',
},
config,
);
expect(env.HOME).toBe(config.roots.agentHomeDir);
expect(env.USERPROFILE).toBe(config.roots.agentHomeDir);
expect(env.OD_AGENT_HOME).toBe(config.roots.agentHomeDir);
expect(env.CODEX_HOME).toBe(path.join(config.roots.agentHomeDir, '.codex'));
expect(env.CLAUDE_CONFIG_DIR).toBe(path.join(config.roots.configDir, 'claude'));
expect(env.OPENCODE_TEST_HOME).toBe(path.join(config.roots.agentHomeDir, '.opencode'));
expect(env.NPM_CONFIG_USERCONFIG).toBe(path.join(config.roots.toolConfigDir, 'npmrc'));
expect(env.PATH).toBe('/bin');
});
});