fix(runner): isolate ACPX Codex shell state

This commit is contained in:
Dotta 2026-09-03 00:19:52 -05:00
parent 79daaaf9e0
commit 34e52d370b
2 changed files with 29 additions and 0 deletions

View File

@ -83,6 +83,17 @@ describe("ACPX runtime sandbox", () => {
sandbox.persistedEnvironment.PAPERCLIP_NATIVE_MCP_TOKEN,
).toBeUndefined();
expect(sandbox.persistedEnvironment.HOME).toBe(sandbox.homeDirectory);
if (agent === "codex") {
const config = await readFile(
join(sandbox.agentHomeDirectory, "config.toml"),
"utf8",
);
expect(config).toContain("shell_snapshot = false");
expect(config).toContain(
'exclude = ["OPENAI_API_KEY", "CODEX_API_KEY"]',
);
expect(config).not.toContain("provider-secret");
}
expect(await readFile(sandbox.workspaceRecordPath, "utf8")).toBe(
`${fixture.binding.workspacePath}\n`,
);

View File

@ -376,6 +376,24 @@ export async function prepareAcpxRuntimeSandbox(input: {
})}\n`,
);
}
if (input.agent === "codex") {
await writePrivateFile(
join(agentHomeDirectory, "config.toml"),
[
// Codex shell snapshots serialize the provider process environment.
// The ACPX sidecar receives a short-lived managed credential only so
// it can authenticate the provider; that value must never become
// durable runtime state or enter a model-invoked shell.
"[features]",
"shell_snapshot = false",
"",
"[shell_environment_policy]",
'exclude = ["OPENAI_API_KEY", "CODEX_API_KEY"]',
"ignore_default_excludes = false",
"",
].join("\n"),
);
}
const sanitizedSpawnInput = createSanitizedAcpxSpawnInput(
input.environment,