Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
5dc7d61
fix(codex): avoid guardian review for local models
vincentkoc May 31, 2026
0a41020
fix(codex): route app-server auto exec review
vincentkoc May 31, 2026
2e67c27
fix(codex): make guardian requirements provider-aware
vincentkoc May 31, 2026
85e751e
fix(codex): block unrouted bound approvals
vincentkoc May 31, 2026
0d3b784
fix(channels): satisfy ingress queue lint
vincentkoc May 31, 2026
977ce31
fix(codex): use local-model policy for side forks
vincentkoc May 31, 2026
39e52aa
fix(extensions): satisfy ingress lint
vincentkoc May 31, 2026
c6bb17e
fix(codex): require trusted exec reviewer model
vincentkoc May 31, 2026
43473ef
fix(exec): share control command approval guards
vincentkoc May 31, 2026
5ba4085
fix(codex): fail closed for unknown guardian model provider
vincentkoc Jun 1, 2026
98b93b6
fix(codex): reject custom exec reviewer endpoints
vincentkoc Jun 3, 2026
048f750
fix(codex): preserve bound providers on app-server reuse
vincentkoc Jun 3, 2026
e7abf6f
fix(codex): prefer qualified app-server model providers
vincentkoc Jun 3, 2026
27fbad2
fix(codex): preserve guardian on model control switches
vincentkoc Jun 3, 2026
45bb105
fix(codex): retain local providers across model switches
vincentkoc Jun 3, 2026
2f31a7f
fix(codex): distrust aliased reviewer model refs
vincentkoc Jun 3, 2026
aa12e2c
fix(codex): preserve providers after thread rotation
vincentkoc Jun 3, 2026
5b1e966
fix(codex): clear stale providers on qualified model switches
vincentkoc Jun 3, 2026
92542db
fix(codex): prefer qualified models over legacy providers
vincentkoc Jun 3, 2026
4f7d742
fix(codex): validate reviewer trust before auto approvals
vincentkoc Jun 3, 2026
ff27272
fix(codex): recompute reviewer policy after binding rotation
vincentkoc Jun 3, 2026
0a68058
fix(codex): normalize reviewer aliases before trust checks
vincentkoc Jun 3, 2026
dcfa086
fix(codex): retain bound providers for slashed local models
vincentkoc Jun 3, 2026
2aa2905
fix(codex): normalize provider trust checks for exec review
vincentkoc Jun 3, 2026
88c6d4f
fix(codex): ignore stale bindings for explicit providers
vincentkoc Jun 3, 2026
03a8a53
fix(codex): share trusted reviewer endpoint policy
vincentkoc Jun 6, 2026
9d05c35
fix(codex): keep network approvals on plugin path
vincentkoc Jun 6, 2026
d6f8440
fix(codex): route provider-qualified model refs
vincentkoc Jun 6, 2026
dc1a9cf
fix(codex): reject blank masked OpenAI base overrides
vincentkoc Jun 7, 2026
653e206
fix(codex): scope exec reviewer alias trust
vincentkoc Jun 8, 2026
e3318f1
fix(codex): distrust exec reviewer transport overrides
vincentkoc Jun 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 143 additions & 1 deletion extensions/codex/src/app-server/app-server-policy.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// Codex tests cover app server policy plugin behavior.
import { describe, expect, it } from "vitest";
import { resolveCodexAppServerForOpenClawToolPolicy } from "./app-server-policy.js";
import {
resolveCodexAppServerForModelProvider,
resolveCodexAppServerForOpenClawToolPolicy,
} from "./app-server-policy.js";
import { readCodexPluginConfig, resolveCodexAppServerRuntimeOptions } from "./config.js";

describe("Codex app-server policy", () => {
Expand Down Expand Up @@ -66,4 +69,143 @@ describe("Codex app-server policy", () => {
expect(explicitEnv.approvalPolicy).toBe("never");
expect(explicitRequirements.approvalPolicy).toBe("never");
});

it("keeps model-backed reviewers for explicit OpenAI model providers", () => {
const appServer = resolveCodexAppServerRuntimeOptions({
env: {},
requirementsToml: null,
execMode: "auto",
modelProvider: "openai",
});

expect(
resolveCodexAppServerForModelProvider({
appServer,
provider: "codex",
model: "openai/gpt-5.5",
}).approvalsReviewer,
).toBe("auto_review");
expect(
resolveCodexAppServerForModelProvider({
appServer,
provider: "codex",
model: "gpt-5.5",
}).approvalsReviewer,
).toBe("user");
expect(
resolveCodexAppServerForModelProvider({ appServer, provider: "openai" }).approvalsReviewer,
).toBe("auto_review");
});

it("uses human approval for OpenAI-compatible custom endpoints", () => {
const appServer = resolveCodexAppServerRuntimeOptions({
env: {},
requirementsToml: null,
execMode: "auto",
modelProvider: "openai",
model: "gpt-5.5",
config: {
models: {
providers: {
openai: {
baseUrl: "http://localhost:8080/v1",
models: [],
},
},
},
},
});

expect(appServer.approvalsReviewer).toBe("user");
expect(
resolveCodexAppServerForModelProvider({
appServer,
provider: "openai",
model: "gpt-5.5",
config: {
models: {
providers: {
openai: {
baseUrl: "http://localhost:8080/v1",
models: [],
},
},
},
},
}).approvalsReviewer,
).toBe("user");
});

it("uses human approval instead of Codex Guardian for custom model providers", () => {
const appServer = resolveCodexAppServerRuntimeOptions({
env: {},
requirementsToml: null,
execMode: "auto",
modelProvider: "openai",
});

const resolved = resolveCodexAppServerForModelProvider({
appServer,
provider: "lmstudio",
});
const vendorPrefixedModel = resolveCodexAppServerForModelProvider({
appServer,
provider: "openrouter",
model: "openai/gpt-5.5",
});

expect(appServer.approvalsReviewer).toBe("auto_review");
expect(resolved.approvalPolicy).toBe("on-request");
expect(resolved.sandbox).toBe("workspace-write");
expect(resolved.approvalsReviewer).toBe("user");
expect(vendorPrefixedModel.approvalsReviewer).toBe("user");
});

it("infers custom providers from provider-qualified model refs", () => {
const appServer = resolveCodexAppServerRuntimeOptions({
env: {},
requirementsToml: null,
execMode: "auto",
});

expect(
resolveCodexAppServerForModelProvider({
appServer,
model: "lmstudio/local-model",
}).approvalsReviewer,
).toBe("user");
});

it("uses provider-qualified model refs to override broad native provider wrappers", () => {
const appServer = resolveCodexAppServerRuntimeOptions({
env: {},
requirementsToml: null,
execMode: "auto",
});

expect(
resolveCodexAppServerForModelProvider({
appServer,
provider: "codex",
model: "lmstudio/local-model",
}).approvalsReviewer,
).toBe("user");
});

it("downgrades legacy guardian_subagent for custom model providers", () => {
const appServer = resolveCodexAppServerRuntimeOptions({
env: {},
requirementsToml: null,
pluginConfig: {
appServer: {
mode: "guardian",
approvalsReviewer: "guardian_subagent",
},
},
});

expect(
resolveCodexAppServerForModelProvider({ appServer, provider: "local" }).approvalsReviewer,
).toBe("user");
});
});
47 changes: 43 additions & 4 deletions extensions/codex/src/app-server/app-server-policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
* Policy promotion for Codex app-server runs that can safely use OpenClaw tool
* approvals.
*/
import type {
CodexAppServerRuntimeOptions,
CodexPluginConfig,
OpenClawExecPolicyForCodexAppServer,
import {
canUseCodexModelBackedApprovalsReviewerForModel,
type CodexAppServerRuntimeOptions,
type CodexPluginConfig,
type OpenClawExecPolicyForCodexAppServer,
} from "./config.js";

/**
Expand Down Expand Up @@ -44,6 +45,35 @@ export function resolveCodexAppServerForOpenClawToolPolicy(params: {
};
}

export function resolveCodexAppServerForModelProvider(params: {
appServer: CodexAppServerRuntimeOptions;
provider?: string;
model?: string;
config?: Parameters<typeof canUseCodexModelBackedApprovalsReviewerForModel>[0]["config"];
env?: NodeJS.ProcessEnv;
agentDir?: string;
codexConfigToml?: string | null;
}): CodexAppServerRuntimeOptions {
const explicitProvider = normalizeModelBackedReviewerProvider(params.provider);
if (
!isCodexModelBackedApprovalsReviewer(params.appServer.approvalsReviewer) ||
canUseCodexModelBackedApprovalsReviewerForModel({
modelProvider: explicitProvider,
model: params.model,
config: params.config,
env: params.env,
agentDir: params.agentDir,
codexConfigToml: params.codexConfigToml,
})
) {
return params.appServer;
}
return {
...params.appServer,
approvalsReviewer: "user",
};
}

function isCodexAppServerPolicyMode(value: unknown): boolean {
return value === "guardian" || value === "yolo";
}
Expand All @@ -53,3 +83,12 @@ function isCodexAppServerApprovalPolicy(value: unknown): boolean {
value === "never" || value === "on-request" || value === "on-failure" || value === "untrusted"
);
}

function isCodexModelBackedApprovalsReviewer(value: string): boolean {
return value === "auto_review" || value === "guardian_subagent";
}

function normalizeModelBackedReviewerProvider(provider: string | undefined): string | undefined {
const normalized = provider?.trim().toLowerCase();
return normalized || undefined;
}
Loading
Loading