Files
stack/agents/rocko/work/queue-178/sandbox-probe.mjs
jason.woltje 068d868a99 lead: commit rocko's untracked evidence (4471 files: queue-124 queue-129 queue-171 queue-178 queue-280 queue-31 queue-84 queue-85 queue-94)
Unclaimed files left in the canonical checkout. Inventory: canonical-cleanup-inventory.md (commit-as-evidence groups). detect-secrets scan clean on 2026-11-02: hits are sha256 pins, git object ids, test sentinels already in tracked tests and unit-file lines.
2026-11-02 15:05:15 -06:00

34 lines
2.9 KiB
JavaScript

// Run only with the granted slot. All filesystem effects are fixture-only.
import { mkdtempSync, mkdirSync, writeFileSync, rmSync, existsSync, readFileSync } from 'node:fs';
import { join } from 'node:path';
import { tmpdir, homedir } from 'node:os';
import { spawnSync } from 'node:child_process';
import { binds, prepareRun, sandboxArgv } from '/mnt/storage/src/mosaic-stack-rocko-178/packages/seat/src/sandbox.mjs';
const root = mkdtempSync(join(tmpdir(), 'proof-sandbox-'));
try {
const runDir = join(root, 'run'), workspace = join(root, 'workspace'), outside = join(root, 'fixture-host-home', '.config');
for (const dir of [runDir, workspace, outside, join(runDir, 'bundle')]) mkdirSync(dir, { recursive: true });
const marker = join(outside, 'marker'); writeFileSync(marker, 'fixture-marker');
writeFileSync(join(runDir, 'session.json'), '{}'); prepareRun(runDir);
const adapter = join(runDir, 'adapter.sh'), socket = join(runDir, 'fixture-bus.sock');
writeFileSync(adapter, '#!/bin/sh\nexit 0\n'); writeFileSync(socket, 'fixture socket mount stand-in');
const pi = await import('/mnt/storage/src/mosaic-stack-rocko-178/packages/plugins/harness/pi/index.mjs');
const claude = await import('/mnt/storage/src/mosaic-stack-rocko-178/packages/plugins/harness/claude-code/index.mjs');
const mountLists = [pi.mounts({ env: {} }), claude.mounts({ env: { MOSAIC_CLAUDE_BIN: '/usr/bin/true' } })];
const code = `const fs=require('node:fs');const paths=JSON.parse(process.argv[1]);if(paths.some(p=>fs.existsSync(p)))process.exit(1);console.log('fixture host config, host config path and private HOME config are hidden');`;
const paths = [marker, join(homedir(), '.config'), join(runDir, 'home', '.config')];
for (const harnessMounts of mountLists) {
const list = binds({ runDir, workspace, adapter, brokerSocket: socket, harnessMounts });
const argv = sandboxArgv(list, runDir, [process.execPath, '-e', code, JSON.stringify(paths)], { business: 'demo', role: 'coder' });
const r = spawnSync(argv[0], argv.slice(1), { encoding: 'utf8', timeout: 10000 });
if (!existsSync(marker)) throw Error('host fixture marker vanished');
if (r.status !== 0) throw Error(`sandbox probe failed: ${r.status}: ${r.stderr}`);
console.log(r.stdout.trim());
}
const compose = readFileSync('/mnt/storage/src/mosaic-stack-rocko-178/compose.yaml', 'utf8');
const volumes = compose.split(' volumes:\n')[1].split('\n').filter(line => /^ - /.test(line)).map(line => line.trim());
if (volumes.length !== 2 || !volumes[0].includes('MOSAIC_DATA_ROOT') || !volumes[1].includes('PI_AUTH_FILE')) throw Error('unexpected container mount list');
console.log('run-task container source check: exactly dataRoot and read-only PI_AUTH_FILE; no host ~/.config mount');
console.log('Scope: no live config read; dataRoot and PI_AUTH_FILE overrides must not expose the proof path. No Docker runtime test claimed.');
} finally { rmSync(root, { recursive: true, force: true }); }