11// noinspection ES6RedundantAwait
22
33import { 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" ;
47import type { CodexAuthRequest } from "../../CodexAuthMethod" ;
58import type * as acp from "@agentclientprotocol/sdk" ;
69import { createTestFixture , createCodexMockTestFixture , createTestSessionState , type TestFixture } from "../acp-test-utils" ;
@@ -11,6 +14,26 @@ import type {ListMcpServerStatusResponse, Model, SkillsListResponse} from "../..
1114import type { RateLimitsMap } from "../../RateLimitsMap" ;
1215import { 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+
1437describe ( '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