fix(codex): fail closed for unknown approvals

This commit is contained in:
Lucenx9
2026-04-22 23:50:20 +02:00
committed by Peter Steinberger
parent 4285958bcd
commit ec5015924c
2 changed files with 46 additions and 3 deletions

View File

@@ -106,6 +106,29 @@ describe("Codex app-server approval bridge", () => {
);
});
it("fails closed for unsupported native approval methods without requesting plugin approval", async () => {
const params = createParams();
const result = await handleCodexAppServerApprovalRequest({
method: "future/requestApproval",
requestParams: {
threadId: "thread-1",
turnId: "turn-1",
itemId: "future-1",
},
paramsForRun: params,
threadId: "thread-1",
turnId: "turn-1",
});
expect(result).toEqual({
decision: "decline",
reason: "OpenClaw codex app-server bridge does not grant native approvals yet.",
});
expect(mockCallGatewayTool).not.toHaveBeenCalled();
expect(params.onAgentEvent).not.toHaveBeenCalled();
});
it("maps app-server approval response families separately", () => {
expect(
buildApprovalResponse(
@@ -134,5 +157,9 @@ describe("Codex app-server approval bridge", () => {
permissions: { network: { allowHosts: ["example.com"] } },
scope: "turn",
});
expect(buildApprovalResponse("future/requestApproval", undefined, "approved-once")).toEqual({
decision: "decline",
reason: "OpenClaw codex app-server bridge does not grant native approvals yet.",
});
});
});

View File

@@ -38,6 +38,9 @@ export async function handleCodexAppServerApprovalRequest(params: {
if (!matchesCurrentTurn(requestParams, params.threadId, params.turnId)) {
return undefined;
}
if (!isSupportedAppServerApprovalMethod(params.method)) {
return unsupportedApprovalResponse();
}
const context = buildApprovalContext({
method: params.method,
@@ -161,9 +164,7 @@ export function buildApprovalResponse(
}
return { permissions: {}, scope: "turn" };
}
return {
decision: outcome === "approved-once" || outcome === "approved-session" ? "accept" : "decline",
};
return unsupportedApprovalResponse();
}
function matchesCurrentTurn(
@@ -299,6 +300,13 @@ function requestedPermissions(requestParams: JsonObject | undefined): JsonObject
return granted;
}
function unsupportedApprovalResponse(): JsonValue {
return {
decision: "decline",
reason: "OpenClaw codex app-server bridge does not grant native approvals yet.",
};
}
function hasAvailableDecision(requestParams: JsonObject | undefined, decision: string): boolean {
const available = requestParams?.availableDecisions;
if (!Array.isArray(available)) {
@@ -348,6 +356,14 @@ function approvalKindForMethod(method: string): AgentApprovalEventData["kind"] {
return "unknown";
}
function isSupportedAppServerApprovalMethod(method: string): boolean {
return (
method === "item/commandExecution/requestApproval" ||
method === "item/fileChange/requestApproval" ||
method === "item/permissions/requestApproval"
);
}
function emitApprovalEvent(params: EmbeddedRunAttemptParams, data: AgentApprovalEventData): void {
params.onAgentEvent?.({ stream: "approval", data: data as unknown as Record<string, unknown> });
}