Skip to content

Commit 5fe6355

Browse files
committed
test: allow running "should authenticate with key" test in sandboxed environments
Otherwise, it fails `failed to save api key: Operation not permitted (os error 1).` when trying to run it having `CODEX_SANDBOX=seatbelt, CODEX_CI=1`
1 parent fcfe17c commit 5fe6355

1 file changed

Lines changed: 44 additions & 17 deletions

File tree

src/__tests__/CodexACPAgent/CodexAcpClient.test.ts

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
// noinspection ES6RedundantAwait
22

33
import {describe, expect, it, vi, beforeEach} from 'vitest';
4+
import fs from "node:fs";
5+
import os from "node:os";
6+
import path from "node:path";
47
import type {CodexAuthRequest} from "../../CodexAuthMethod";
58
import type * as acp from "@agentclientprotocol/sdk";
69
import {createTestFixture, createCodexMockTestFixture, createTestSessionState, type TestFixture} from "../acp-test-utils";
@@ -11,6 +14,26 @@ import type {ListMcpServerStatusResponse, Model, SkillsListResponse} from "../..
1114
import type {RateLimitsMap} from "../../RateLimitsMap";
1215
import {ModelId} from "../../ModelId";
1316

17+
const CODEX_HOME_ENV = "CODEX_HOME";
18+
19+
async function overrideCodexHome<T>(configToml: string, run: () => Promise<T>): Promise<T> {
20+
const previousCodexHome = process.env[CODEX_HOME_ENV];
21+
const codexHome = fs.mkdtempSync(path.join(os.tmpdir(), "codex-acp-codex-home-"));
22+
fs.writeFileSync(path.join(codexHome, "config.toml"), configToml, "utf8");
23+
process.env[CODEX_HOME_ENV] = codexHome;
24+
25+
try {
26+
return await run();
27+
} finally {
28+
if (previousCodexHome === undefined) {
29+
delete process.env[CODEX_HOME_ENV];
30+
} else {
31+
process.env[CODEX_HOME_ENV] = previousCodexHome;
32+
}
33+
fs.rmSync(codexHome, { recursive: true, force: true });
34+
}
35+
}
36+
1437
describe('ACP server test', { timeout: 40_000 }, () => {
1538

1639
let fixture: TestFixture;
@@ -50,31 +73,35 @@ describe('ACP server test', { timeout: 40_000 }, () => {
5073
});
5174

5275
it('should authenticate with key', async () => {
53-
const codexAcpAgent = fixture.getCodexAcpAgent();
76+
// In sandboxed environments Codex may fail when trying to write to the OS keychain (`Operation not permitted`).
77+
await overrideCodexHome('cli_auth_credentials_store = "file"', async () => {
78+
const keyFixture = createTestFixture();
79+
const codexAcpAgent = keyFixture.getCodexAcpAgent();
5480

55-
await codexAcpAgent.initialize({protocolVersion: 1});
56-
await fixture.getCodexAcpClient().logout();
81+
await codexAcpAgent.initialize({protocolVersion: 1});
82+
await keyFixture.getCodexAcpClient().logout();
5783

5884

59-
const unauthenticatedResponse = await fixture.getCodexAcpAgent().extMethod("authentication/status", {});
60-
expect(unauthenticatedResponse).toEqual({type: "unauthenticated"});
85+
const unauthenticatedResponse = await keyFixture.getCodexAcpAgent().extMethod("authentication/status", {});
86+
expect(unauthenticatedResponse).toEqual({type: "unauthenticated"});
6187

62-
fixture.clearCodexConnectionDump();
88+
keyFixture.clearCodexConnectionDump();
6389

64-
const authRequest: CodexAuthRequest = { methodId: "api-key", _meta: { "api-key": { apiKey: "TOKEN" }}}
65-
await codexAcpAgent.authenticate(authRequest);
66-
const newSessionResponse = await codexAcpAgent.newSession({cwd: "", mcpServers: []});
67-
expect(newSessionResponse.sessionId).toBeDefined()
90+
const authRequest: CodexAuthRequest = { methodId: "api-key", _meta: { "api-key": { apiKey: "TOKEN" }}}
91+
await codexAcpAgent.authenticate(authRequest);
92+
const newSessionResponse = await codexAcpAgent.newSession({cwd: "", mcpServers: []});
93+
expect(newSessionResponse.sessionId).toBeDefined()
6894

69-
const transportDump = fixture.getCodexConnectionDump([...ignoredFields, "upgrade"]);
70-
await expect(transportDump).toMatchFileSnapshot("data/auth-with-key.json");
95+
const transportDump = keyFixture.getCodexConnectionDump([...ignoredFields, "upgrade"]);
96+
await expect(transportDump).toMatchFileSnapshot("data/auth-with-key.json");
7197

72-
const authenticatedResponse = await fixture.getCodexAcpAgent().extMethod("authentication/status", {});
73-
expect(authenticatedResponse).toEqual({type: "api-key"});
98+
const authenticatedResponse = await keyFixture.getCodexAcpAgent().extMethod("authentication/status", {});
99+
expect(authenticatedResponse).toEqual({type: "api-key"});
74100

75-
await fixture.getCodexAcpAgent().extMethod("authentication/logout", {});
76-
const logoutResponse = await fixture.getCodexAcpAgent().extMethod("authentication/status", {});
77-
expect(logoutResponse).toEqual({type: "unauthenticated"});
101+
await keyFixture.getCodexAcpAgent().extMethod("authentication/logout", {});
102+
const logoutResponse = await keyFixture.getCodexAcpAgent().extMethod("authentication/status", {});
103+
expect(logoutResponse).toEqual({type: "unauthenticated"});
104+
});
78105
});
79106

80107
it('should authenticate with a gateway', async () => {

0 commit comments

Comments
 (0)