import assert from 'node:assert/strict' import { it } from 'node:test' import { DockerRunner, FakeContainerRunner, dockerRunArgs } from '../dist/index.js' const baseSpec = { label: 'radial-turn-1', image: 'radial/harness:latest', argv: ['sh', '-c', 'echo hi'], env: { FOO: 'bar', BAZ: 'qux' }, mounts: [ { source: '/host/bundle', target: '/bundle', readOnly: true }, { source: '/host/checkout', target: '/workspace', readOnly: false }, ], network: 'radial-bridge', workdir: '/workspace', timeoutMs: 60_000, tmpfs: ['/tmp', '/run'], } it('dockerRunArgs hardens the container and preserves deterministic ordering', () => { const args = dockerRunArgs(baseSpec) assert.equal(args[0], 'run') assert.ok(args.includes('--rm')) assert.ok(args.includes('--cap-drop=ALL')) const securityOptIndex = args.indexOf('--security-opt') assert.ok(securityOptIndex !== -1) assert.equal(args[securityOptIndex + 1], 'no-new-privileges') const pidsLimitIndex = args.indexOf('--pids-limit') assert.ok(pidsLimitIndex !== -1) assert.equal(args[pidsLimitIndex + 1], '512') const userIndex = args.indexOf('--user') assert.equal(args[userIndex + 1], '1000:1000') assert.ok(args.includes('--read-only')) const tmpfsIndexes = args.reduce((acc, value, index) => (value === '--tmpfs' ? [...acc, index] : acc), []) assert.deepEqual( tmpfsIndexes.map((index) => args[index + 1]), ['/tmp', '/run'], ) const labelIndex = args.indexOf('--label') assert.equal(args[labelIndex + 1], 'radial-turn-1') const nameIndex = args.indexOf('--name') assert.equal(args[nameIndex + 1], 'radial-turn-1') const networkIndex = args.indexOf('--network') assert.equal(args[networkIndex + 1], 'radial-bridge') const workdirIndex = args.indexOf('-w') assert.equal(args[workdirIndex + 1], '/workspace') assert.ok(args.includes('-v')) assert.ok(args.includes('/host/bundle:/bundle:ro')) assert.ok(args.includes('/host/checkout:/workspace')) assert.ok(!args.includes('/host/checkout:/workspace:ro')) assert.ok(args.includes('-e')) assert.ok(args.includes('FOO')) assert.ok(args.includes('BAZ')) assert.equal(args.includes('FOO=bar'), false) assert.equal(args.includes('BAZ=qux'), false) const imageIndex = args.indexOf('radial/harness:latest') assert.ok(imageIndex !== -1) assert.deepEqual(args.slice(imageIndex + 1), ['sh', '-c', 'echo hi']) // -v/-e ordering: image must come after every mount/env flag, and mounts before env. const lastMountIndex = args.lastIndexOf('/host/checkout:/workspace') const firstEnvIndex = args.indexOf('-e') assert.ok(lastMountIndex < firstEnvIndex) assert.ok(firstEnvIndex < imageIndex) }) it('dockerRunArgs applies memory and a custom pids-limit/user when set, and skips --read-only when disabled', () => { const args = dockerRunArgs({ ...baseSpec, memory: '512m', pidsLimit: 128, user: '2000:2000', readOnlyRootfs: false, }) const memoryIndex = args.indexOf('--memory') assert.equal(args[memoryIndex + 1], '512m') const pidsLimitIndex = args.indexOf('--pids-limit') assert.equal(args[pidsLimitIndex + 1], '128') const userIndex = args.indexOf('--user') assert.equal(args[userIndex + 1], '2000:2000') assert.ok(!args.includes('--read-only')) }) it('dockerRunArgs omits optional flags that are unset', () => { const args = dockerRunArgs({ label: 'radial-turn-2', image: 'radial/harness:latest', argv: [], env: {}, mounts: [], timeoutMs: 1000, }) assert.ok(!args.includes('--network')) assert.ok(!args.includes('-w')) assert.ok(!args.includes('--memory')) assert.ok(!args.includes('--tmpfs')) assert.ok(args.includes('--read-only')) }) it('dockerRunArgs emits --add-host per extraHosts entry, right after --network', () => { const args = dockerRunArgs({ ...baseSpec, extraHosts: ['host.docker.internal:host-gateway'] }) const networkIndex = args.indexOf('--network') assert.equal(args[networkIndex + 2], '--add-host') assert.equal(args[networkIndex + 3], 'host.docker.internal:host-gateway') }) it('DockerRunner can be constructed without throwing (Docker itself is not exercised here)', () => { const runner = new DockerRunner() assert.equal(typeof runner.run, 'function') assert.equal(typeof runner.listByLabel, 'function') assert.equal(typeof runner.kill, 'function') }) it('FakeContainerRunner.run invokes the injected fn and tracks/untracks state by label', async () => { const seen = [] const runner = new FakeContainerRunner(async (spec) => { seen.push(spec.label) return { exitCode: 0, timedOut: false } }) assert.deepEqual(await runner.listByLabel('radial-turn-1'), []) const result = await runner.run(baseSpec) assert.deepEqual(result, { exitCode: 0, timedOut: false }) assert.deepEqual(seen, ['radial-turn-1']) const started = await runner.listByLabel('radial-turn-1') assert.equal(started.length, 1) await runner.kill(started[0]) assert.deepEqual(await runner.listByLabel('radial-turn-1'), []) }) it('FakeContainerRunner.kill on an unknown id is a no-op', async () => { const runner = new FakeContainerRunner(async () => ({ exitCode: 0, timedOut: false })) await assert.doesNotReject(runner.kill('does-not-exist')) })