diff --git a/src/gateway/node-invoke-system-run-approval-match.test.ts b/src/gateway/node-invoke-system-run-approval-match.test.ts index 87e79e7c8..0312733f4 100644 --- a/src/gateway/node-invoke-system-run-approval-match.test.ts +++ b/src/gateway/node-invoke-system-run-approval-match.test.ts @@ -164,4 +164,56 @@ describe("evaluateSystemRunApprovalMatch", () => { } expect(result.code).toBe("APPROVAL_REQUEST_MISMATCH"); }); + + test("prefers v1 binding over legacy command text fields", () => { + const result = evaluateSystemRunApprovalMatch({ + cmdText: "echo SAFE", + argv: ["echo", "SAFE"], + request: { + host: "node", + // Intentionally stale legacy fields; v1 should be authoritative. + command: "echo STALE", + commandArgv: ["echo STALE"], + systemRunBindingV1: buildSystemRunApprovalBindingV1({ + argv: ["echo", "SAFE"], + cwd: null, + agentId: null, + sessionKey: null, + }).binding, + }, + binding: { + cwd: null, + agentId: null, + sessionKey: null, + }, + }); + expect(result).toEqual({ ok: true }); + }); + + test("rejects v1 mismatch even when legacy command text matches", () => { + const result = evaluateSystemRunApprovalMatch({ + cmdText: "echo SAFE", + argv: ["echo", "SAFE"], + request: { + host: "node", + command: "echo SAFE", + systemRunBindingV1: buildSystemRunApprovalBindingV1({ + argv: ["echo SAFE"], + cwd: null, + agentId: null, + sessionKey: null, + }).binding, + }, + binding: { + cwd: null, + agentId: null, + sessionKey: null, + }, + }); + expect(result.ok).toBe(false); + if (result.ok) { + throw new Error("unreachable"); + } + expect(result.code).toBe("APPROVAL_REQUEST_MISMATCH"); + }); }); diff --git a/src/gateway/system-run-approval-binding.test.ts b/src/gateway/system-run-approval-binding.test.ts index 882990637..66dae6900 100644 --- a/src/gateway/system-run-approval-binding.test.ts +++ b/src/gateway/system-run-approval-binding.test.ts @@ -4,6 +4,7 @@ import { buildSystemRunApprovalEnvBinding, matchSystemRunApprovalBindingV1, matchSystemRunApprovalEnvHash, + toSystemRunApprovalMismatchError, } from "./system-run-approval-binding.js"; describe("buildSystemRunApprovalEnvBinding", () => { @@ -99,3 +100,32 @@ describe("matchSystemRunApprovalBindingV1", () => { expect(result.code).toBe("APPROVAL_ENV_MISMATCH"); }); }); + +describe("toSystemRunApprovalMismatchError", () => { + test("includes runId/code and preserves mismatch details", () => { + const result = toSystemRunApprovalMismatchError({ + runId: "approval-123", + match: { + ok: false, + code: "APPROVAL_ENV_MISMATCH", + message: "approval id env binding mismatch", + details: { + envKeys: ["SAFE_A"], + expectedEnvHash: "expected-hash", + actualEnvHash: "actual-hash", + }, + }, + }); + expect(result).toEqual({ + ok: false, + message: "approval id env binding mismatch", + details: { + code: "APPROVAL_ENV_MISMATCH", + runId: "approval-123", + envKeys: ["SAFE_A"], + expectedEnvHash: "expected-hash", + actualEnvHash: "actual-hash", + }, + }); + }); +});