@@ -3,9 +3,11 @@ import { tmpdir } from "node:os";
33import { join } from "node:path" ;
44import { afterEach , describe , expect , test } from "bun:test" ;
55import { parse } from "smol-toml" ;
6+ import { scanRuntimeCodexConfig } from "../src/api.js" ;
67import {
78 ConfigurationError ,
89 DEFAULT_CODEX_CONFIG ,
10+ type JsonObject ,
911 mergedCodexConfig ,
1012 writeCodexConfig ,
1113} from "../src/index.js" ;
@@ -26,6 +28,39 @@ async function temporaryDirectory(): Promise<string> {
2628 return path ;
2729}
2830
31+ function runPinnedCodex ( codexHome : string , arguments_ : readonly string [ ] ) {
32+ const node = Bun . which ( "node" ) ;
33+ if ( node === null ) {
34+ throw new Error ( "The pinned Codex CLI requires Node.js." ) ;
35+ }
36+ const environment : NodeJS . ProcessEnv = {
37+ ...process . env ,
38+ CODEX_HOME : codexHome ,
39+ } ;
40+ delete environment [ "OPENAI_API_KEY" ] ;
41+ delete environment [ "CODEX_API_KEY" ] ;
42+ return Bun . spawnSync (
43+ [
44+ node ,
45+ join (
46+ import . meta. dir ,
47+ ".." ,
48+ "node_modules" ,
49+ "@openai" ,
50+ "codex" ,
51+ "bin" ,
52+ "codex.js" ,
53+ ) ,
54+ ...arguments_ ,
55+ ] ,
56+ {
57+ env : environment ,
58+ stdout : "pipe" ,
59+ stderr : "pipe" ,
60+ } ,
61+ ) ;
62+ }
63+
2964describe ( "Codex configuration" , ( ) => {
3065 test ( "deep-merges native multi-agent v2 defaults" , async ( ) => {
3166 const merged = await mergedCodexConfig ( {
@@ -49,6 +84,183 @@ describe("Codex configuration", () => {
4984 expect ( merged [ "windows" ] ) . toEqual ( { sandbox : "elevated" } ) ;
5085 } ) ;
5186
87+ test ( "preserves legacy elevated Windows sandbox overrides" , async ( ) => {
88+ const merged = await mergedCodexConfig ( {
89+ codexOverrides : {
90+ features : { elevated_windows_sandbox : true } ,
91+ } ,
92+ } ) ;
93+
94+ expect ( merged ) . toMatchObject ( {
95+ features : { elevated_windows_sandbox : true } ,
96+ windows : { sandbox : "elevated" } ,
97+ } ) ;
98+ } ) ;
99+
100+ test ( "projects legacy elevated Windows overrides into selected profiles" , async ( ) => {
101+ const merged = await mergedCodexConfig ( {
102+ codexOverrides : {
103+ profile : "elevated" ,
104+ profiles : {
105+ elevated : {
106+ features : { elevated_windows_sandbox : true } ,
107+ } ,
108+ } ,
109+ } ,
110+ } ) ;
111+
112+ expect ( merged ) . toMatchObject ( {
113+ windows : { sandbox : "unelevated" } ,
114+ profiles : {
115+ elevated : {
116+ features : { elevated_windows_sandbox : true } ,
117+ windows : { sandbox : "elevated" } ,
118+ } ,
119+ } ,
120+ } ) ;
121+ } ) ;
122+
123+ test ( "allows selected profiles to override root elevated sandbox defaults" , async ( ) => {
124+ const merged = await mergedCodexConfig ( {
125+ codexOverrides : {
126+ features : { elevated_windows_sandbox : true } ,
127+ profile : "restricted" ,
128+ profiles : {
129+ restricted : {
130+ features : { elevated_windows_sandbox : false } ,
131+ } ,
132+ } ,
133+ } ,
134+ } ) ;
135+
136+ expect ( merged ) . toMatchObject ( {
137+ windows : { sandbox : "elevated" } ,
138+ profiles : {
139+ restricted : {
140+ features : { elevated_windows_sandbox : false } ,
141+ windows : { sandbox : "unelevated" } ,
142+ } ,
143+ } ,
144+ } ) ;
145+ } ) ;
146+
147+ test ( "gives profile-local Windows sandbox overrides precedence" , async ( ) => {
148+ const merged = await mergedCodexConfig ( {
149+ codexOverrides : {
150+ profile : "restricted" ,
151+ profiles : {
152+ restricted : {
153+ features : { elevated_windows_sandbox : true } ,
154+ windows : { sandbox : "unelevated" } ,
155+ } ,
156+ } ,
157+ } ,
158+ } ) ;
159+
160+ expect ( merged ) . toMatchObject ( {
161+ profiles : {
162+ restricted : {
163+ features : { elevated_windows_sandbox : true } ,
164+ windows : { sandbox : "unelevated" } ,
165+ } ,
166+ } ,
167+ } ) ;
168+ } ) ;
169+
170+ test ( "gives explicit Windows sandbox overrides precedence" , async ( ) => {
171+ const merged = await mergedCodexConfig ( {
172+ codexOverrides : {
173+ features : { elevated_windows_sandbox : true } ,
174+ windows : { sandbox : "unelevated" } ,
175+ } ,
176+ } ) ;
177+
178+ expect ( merged ) . toMatchObject ( {
179+ features : { elevated_windows_sandbox : true } ,
180+ windows : { sandbox : "unelevated" } ,
181+ } ) ;
182+ } ) ;
183+
184+ test ( "retains the Windows sandbox in the hardened scan profile" , async ( ) => {
185+ const stateDirectory = join ( tmpdir ( ) , "codex-security-windows-state" ) ;
186+ const merged = await mergedCodexConfig ( { } ) ;
187+
188+ expect ( scanRuntimeCodexConfig ( merged , stateDirectory ) ) . toMatchObject ( {
189+ windows : { sandbox : "unelevated" } ,
190+ default_permissions : "codex_security_scan" ,
191+ permissions : {
192+ codex_security_scan : {
193+ filesystem : {
194+ ":root" : "read" ,
195+ ":workspace_roots" : "write" ,
196+ [ stateDirectory ] : "write" ,
197+ } ,
198+ } ,
199+ } ,
200+ } ) ;
201+ } ) ;
202+
203+ test ( "writes Windows sandbox settings accepted by the pinned Codex CLI" , async ( ) => {
204+ const root = await temporaryDirectory ( ) ;
205+ const path = join ( root , "config.toml" ) ;
206+ await writeCodexConfig ( path , await mergedCodexConfig ( { } ) ) ;
207+
208+ expect ( parse ( await readFile ( path , "utf8" ) ) ) . toMatchObject ( {
209+ windows : { sandbox : "unelevated" } ,
210+ } ) ;
211+
212+ const result = runPinnedCodex ( root , [ "features" , "list" ] ) ;
213+ expect ( result . exitCode ) . toBe ( 0 ) ;
214+ expect ( result . stdout . length ) . toBeGreaterThan ( 0 ) ;
215+ } ) ;
216+
217+ test ( "writes selected profile sandbox settings accepted by the pinned Codex CLI" , async ( ) => {
218+ const root = await temporaryDirectory ( ) ;
219+ const path = join ( root , "config.toml" ) ;
220+ const config = await mergedCodexConfig ( {
221+ codexOverrides : {
222+ profile : "elevated" ,
223+ profiles : {
224+ elevated : {
225+ features : { elevated_windows_sandbox : true } ,
226+ } ,
227+ } ,
228+ } ,
229+ } ) ;
230+ const nativeConfig = structuredClone ( config ) ;
231+ delete nativeConfig [ "profile" ] ;
232+ delete nativeConfig [ "profiles" ] ;
233+ const profileConfig = ( config [ "profiles" ] as JsonObject ) [
234+ "elevated"
235+ ] as JsonObject ;
236+ const profilePath = join ( root , "elevated.config.toml" ) ;
237+ await writeCodexConfig ( path , nativeConfig ) ;
238+ await writeCodexConfig ( profilePath , profileConfig ) ;
239+
240+ expect ( parse ( await readFile ( path , "utf8" ) ) ) . toMatchObject ( {
241+ windows : { sandbox : "unelevated" } ,
242+ } ) ;
243+ expect ( parse ( await readFile ( profilePath , "utf8" ) ) ) . toMatchObject ( {
244+ features : { elevated_windows_sandbox : true } ,
245+ windows : { sandbox : "elevated" } ,
246+ } ) ;
247+
248+ const result = runPinnedCodex ( root , [
249+ "--profile" ,
250+ "elevated" ,
251+ "mcp" ,
252+ "list" ,
253+ "--json" ,
254+ ] ) ;
255+ if ( result . exitCode !== 0 ) {
256+ throw new Error (
257+ `The pinned Codex CLI rejected the selected Windows sandbox profile: ${ new TextDecoder ( ) . decode ( result . stderr ) } ` ,
258+ ) ;
259+ }
260+ expect ( result . exitCode ) . toBe ( 0 ) ;
261+ expect ( result . stdout . length ) . toBeGreaterThan ( 0 ) ;
262+ } ) ;
263+
52264 test ( "rejects prototype-bearing override keys" , async ( ) => {
53265 for ( const key of [ "__proto__" , "constructor" , "prototype" ] ) {
54266 await expect (
@@ -73,6 +285,7 @@ describe("Codex configuration", () => {
73285 test ( "keeps exported default configuration deeply immutable" , async ( ) => {
74286 expect ( Object . isFrozen ( DEFAULT_CODEX_CONFIG ) ) . toBe ( true ) ;
75287 expect ( Object . isFrozen ( DEFAULT_CODEX_CONFIG [ "features" ] ) ) . toBe ( true ) ;
288+ expect ( Object . isFrozen ( DEFAULT_CODEX_CONFIG [ "windows" ] ) ) . toBe ( true ) ;
76289 expect (
77290 Object . isFrozen (
78291 ( DEFAULT_CODEX_CONFIG [ "features" ] as Record < string , unknown > ) [
0 commit comments