From b4c9c3fe74fd8ad58fe34e6f544fc0a6b359ab21 Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN Date: Fri, 2 Oct 2026 21:33:25 -0400 Subject: [PATCH] TASK-company-runtime-recovery forward MCP runtime directory --- docs/TEST_INTEGRITY.md | 24 ++++++++++++++++ src/adapters/codex.mjs | 21 ++++++++++++-- test/fleet/mcp-adapter.test.mjs | 50 +++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 3 deletions(-) diff --git a/docs/TEST_INTEGRITY.md b/docs/TEST_INTEGRITY.md index a35e033..2b19a3b 100644 --- a/docs/TEST_INTEGRITY.md +++ b/docs/TEST_INTEGRITY.md @@ -2811,3 +2811,27 @@ test_integrity_note: did_relax_any_assertion: false if_true_explain_spec_basis: "" ``` + +```yaml +test_integrity_note: + change_type: new_tests + scenarios: + - id: SCN-codex-mcp-runtime-dir + given: "A Codex adapter receives an injected Linux parent environment with a valid XDG runtime directory, or deterministic missing, malformed, or unsupported-platform context" + when: "It creates or resumes an identity-bound Codex session with a TORCH MCP server" + then: "Both launch records name only XDG_RUNTIME_DIR in MCP env_vars for valid context; invalid context emits no env_vars, and no runtime value, DBUS, home, path, token, or general environment is serialized" + observable_outcomes: + - "Create and resume plans expose the exact single-name MCP env_vars allowlist only for valid parent context" + - "Invalid or unsupported context omits the allowlist without synthesizing a runtime path" + - "The serialized invocation never exposes parent environment values" + determinism_controls: + - "Narrow injected adapter env and platform inputs; no process-wide environment mutation, host service, provider, or native check" + anti_cheat_rationale: + prevents: + - "Hard-coded runtime UID or directory values" + - "Forwarding DBUS, secrets, home, PATH, or the complete parent environment" + - "Treating a mocked launch record as native runtime qualification" + relaxation: + did_relax_any_assertion: false + if_true_explain_spec_basis: "" +``` diff --git a/src/adapters/codex.mjs b/src/adapters/codex.mjs index 9ec7447..1f09450 100644 --- a/src/adapters/codex.mjs +++ b/src/adapters/codex.mjs @@ -31,15 +31,28 @@ function commandRecord(command, args, cwd) { return { command, args, cwd, mutatesRuntime: true }; } -function mcpArgs(mcp) { +function mcpRuntimeEnvironmentNames(env, platform) { + const runtimeDirectory = env?.XDG_RUNTIME_DIR; + if (platform !== 'linux' || typeof runtimeDirectory !== 'string' + || !/^\/run\/user\/[1-9]\d*$/.test(runtimeDirectory)) { + return []; + } + return ['XDG_RUNTIME_DIR']; +} + +function mcpArgs(mcp, { env, platform } = {}) { if (!mcp) return []; if (typeof mcp.name !== 'string' || !/^[a-z0-9_-]+$/.test(mcp.name) || typeof mcp.command !== 'string' || !Array.isArray(mcp.args)) { throw new TorchError('Codex MCP launch configuration is invalid', { code: 'INVALID_RUNTIME_INPUT' }); } + const environmentNames = mcpRuntimeEnvironmentNames(env, platform); return [ '-c', `mcp_servers.${mcp.name}.command=${JSON.stringify(mcp.command)}`, '-c', `mcp_servers.${mcp.name}.args=${JSON.stringify(mcp.args)}`, + ...(environmentNames.length + ? ['-c', `mcp_servers.${mcp.name}.env_vars=${JSON.stringify(environmentNames)}`] + : []), ]; } @@ -169,12 +182,14 @@ export function diagnoseCodexStartupFailure({ stdout, stderr } = {}) { export class CodexRuntimeAdapter { constructor({ env = process.env, + platform = process.platform, runner = null, executable = 'codex', nodeExecutable = process.execPath, } = {}) { this.name = 'codex'; this.env = env; + this.platform = platform; this.runner = runner; this.executable = executable; this.nodeExecutable = nodeExecutable; @@ -241,7 +256,7 @@ export class CodexRuntimeAdapter { const cwd = text(worktree, 'worktree'); const args = [ '--cd', cwd, ...launchPolicyArgs(launchPolicy ?? this.configuration.launchPolicy), - ...mcpArgs(mcp), + ...mcpArgs(mcp, { env: this.env, platform: this.platform }), ...((reasoning ?? this.configuration.reasoning) ? ['-c', `model_reasoning_effort=${JSON.stringify(text(reasoning ?? this.configuration.reasoning, 'reasoning'))}`] : []), 'exec', '--json', ...optionalModelArgs(model ?? this.configuration.model), @@ -266,7 +281,7 @@ export class CodexRuntimeAdapter { : ''; const args = [ '--cd', cwd, ...launchPolicyArgs(launchPolicy ?? this.configuration.launchPolicy), - ...mcpArgs(mcp), + ...mcpArgs(mcp, { env: this.env, platform: this.platform }), ...((reasoning ?? this.configuration.reasoning) ? ['-c', `model_reasoning_effort=${JSON.stringify(text(reasoning ?? this.configuration.reasoning, 'reasoning'))}`] : []), 'exec', 'resume', '--json', ...optionalModelArgs(model ?? this.configuration.model), sessionId, `${text(message, 'message')}${currentInstructions}`, diff --git a/test/fleet/mcp-adapter.test.mjs b/test/fleet/mcp-adapter.test.mjs index 4cd07be..089f674 100644 --- a/test/fleet/mcp-adapter.test.mjs +++ b/test/fleet/mcp-adapter.test.mjs @@ -242,6 +242,56 @@ test('SCN-codex-adapter: turns are resumable, identity-bound, durable, and capab control.close(); }); +test('SCN-codex-mcp-runtime-dir: only a valid Linux parent runtime directory is named for MCP inheritance', () => { + const context = fixture(); + const validParent = { + XDG_RUNTIME_DIR: '/run/user/1000', + DBUS_SESSION_BUS_ADDRESS: 'unix:path=/run/user/1000/bus', + HOME: '/home/fixture', PATH: '/usr/bin', TOKEN: 'not-forwarded', + }; + const adapter = createCodexAdapter({ env: validParent, platform: 'linux' }); + const mcp = adapter.configure({ repositoryRoot: context.root, areaId: context.worker, mcpEntry: MCP_SERVER }).mcp; + const create = adapter.createSession({ + areaId: context.worker, worktree: '/tmp/codex-runtime-dir', promptFile: '/tmp/prompt.md', + firstMessage: 'Start.', mcp, + }); + const resume = adapter.resumeSession({ + areaId: context.worker, runtimeSessionId: 'thread-runtime-dir', worktree: '/tmp/codex-runtime-dir', + message: 'Resume.', mcp, + }); + const expected = `mcp_servers.${mcp.name}.env_vars=[\"XDG_RUNTIME_DIR\"]`; + for (const launch of [create, resume]) { + assert.equal(launch.launch.args.includes(expected), true); + assert.equal(launch.launch.args.some((arg) => /env_vars=/.test(arg) && arg !== expected), false); + assert.equal(launch.launch.args.some((arg) => arg.includes(validParent.XDG_RUNTIME_DIR) + || arg.includes(validParent.DBUS_SESSION_BUS_ADDRESS) || arg.includes(validParent.HOME) + || arg.includes(validParent.PATH) || arg.includes(validParent.TOKEN)), false); + } + + for (const invalid of [ + { env: {}, platform: 'linux' }, + { env: { XDG_RUNTIME_DIR: '' }, platform: 'linux' }, + { env: { XDG_RUNTIME_DIR: 'relative/runtime' }, platform: 'linux' }, + { env: validParent, platform: 'darwin' }, + ]) { + const unsupported = createCodexAdapter(invalid); + const unsupportedMcp = unsupported.configure({ + repositoryRoot: context.root, areaId: context.worker, mcpEntry: MCP_SERVER, + }).mcp; + const createPlan = unsupported.createSession({ + areaId: context.worker, worktree: '/tmp/codex-runtime-dir', promptFile: '/tmp/prompt.md', + firstMessage: 'Start.', mcp: unsupportedMcp, + }); + const resumePlan = unsupported.resumeSession({ + areaId: context.worker, runtimeSessionId: 'thread-runtime-dir', worktree: '/tmp/codex-runtime-dir', + message: 'Resume.', mcp: unsupportedMcp, + }); + for (const plan of [createPlan, resumePlan]) { + assert.equal(plan.launch.args.some((arg) => /env_vars=/.test(arg)), false); + } + } +}); + test('SCN-mcp-stdio: an MCP host can initialize and list the TORCH tool surface over stdio', async () => { const context = fixture(); const child = spawn(process.execPath, [MCP_SERVER, '--root', context.root, '--area', context.worker], {