Skip to content

Commit e3318f1

Browse files
committed
fix(codex): distrust exec reviewer transport overrides
1 parent 653e206 commit e3318f1

2 files changed

Lines changed: 63 additions & 5 deletions

File tree

extensions/codex/src/app-server/config.test.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,52 @@ describe("Codex app-server config", () => {
411411
},
412412
}),
413413
).toBe(false);
414+
for (const openAIProvider of [
415+
{
416+
baseUrl: "https://api.openai.com/v1",
417+
request: { proxy: { mode: "explicit-proxy" as const, url: "http://localhost:8080" } },
418+
models: [],
419+
},
420+
{
421+
baseUrl: "https://api.openai.com/v1",
422+
headers: { "x-openclaw-reviewer-proxy": "local" },
423+
models: [],
424+
},
425+
{
426+
baseUrl: "https://api.openai.com/v1",
427+
authHeader: false,
428+
models: [],
429+
},
430+
{
431+
baseUrl: "https://api.openai.com/v1",
432+
models: [
433+
{
434+
id: "gpt-5.5",
435+
name: "GPT with custom headers",
436+
reasoning: true,
437+
input: ["text" as const],
438+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
439+
contextWindow: 128_000,
440+
maxTokens: 8_192,
441+
headers: { "x-openclaw-reviewer-proxy": "local" },
442+
},
443+
],
444+
},
445+
]) {
446+
expect(
447+
canUseCodexModelBackedApprovalsReviewerForModel({
448+
modelProvider: "openai",
449+
model: "gpt-5.5",
450+
config: {
451+
models: {
452+
providers: {
453+
openai: openAIProvider,
454+
},
455+
},
456+
},
457+
}),
458+
).toBe(false);
459+
}
414460
expect(
415461
canUseCodexModelBackedApprovalsReviewerForModel({
416462
modelProvider: "openai",

extensions/codex/src/app-server/config.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1350,10 +1350,13 @@ function configuredOpenAIProviderIsTrustedForModelBackedReview(
13501350
openAIProvider: Record<string, unknown>,
13511351
modelInput: string | undefined,
13521352
): boolean {
1353-
if (readRecord(openAIProvider.localService)) {
1354-
return false;
1355-
}
1356-
if (!isNativeOpenAIBaseUrl(openAIProvider.baseUrl)) {
1353+
if (
1354+
readRecord(openAIProvider.localService) ||
1355+
hasNonEmptyRecord(openAIProvider.headers) ||
1356+
hasNonEmptyRecord(openAIProvider.request) ||
1357+
typeof openAIProvider.authHeader === "boolean" ||
1358+
!isNativeOpenAIBaseUrl(openAIProvider.baseUrl)
1359+
) {
13571360
return false;
13581361
}
13591362
const models = openAIProvider.models;
@@ -1369,7 +1372,11 @@ function configuredOpenAIProviderIsTrustedForModelBackedReview(
13691372
if (typeof model?.id !== "string" || !matchesConfiguredOpenAIModelId(modelId, model.id)) {
13701373
continue;
13711374
}
1372-
if (!isNativeOpenAIBaseUrl(model.baseUrl)) {
1375+
if (
1376+
hasNonEmptyRecord(model.headers) ||
1377+
hasNonEmptyRecord(model.request) ||
1378+
!isNativeOpenAIBaseUrl(model.baseUrl)
1379+
) {
13731380
return false;
13741381
}
13751382
}
@@ -1390,6 +1397,11 @@ function matchesConfiguredOpenAIModelId(modelId: string, configuredModelId: stri
13901397
return Boolean(configured) && (modelId === configured || modelId.startsWith(`${configured}@`));
13911398
}
13921399

1400+
function hasNonEmptyRecord(value: unknown): boolean {
1401+
const record = readRecord(value);
1402+
return record !== undefined && Object.keys(record).length > 0;
1403+
}
1404+
13931405
function isNativeOpenAIBaseUrl(value: unknown): boolean {
13941406
if (typeof value !== "string" || !value.trim()) {
13951407
return true;

0 commit comments

Comments
 (0)