diff --git a/agent-governance-opencode/lib/policy.mjs b/agent-governance-opencode/lib/policy.mjs index 8523add64..8c98c6df1 100644 --- a/agent-governance-opencode/lib/policy.mjs +++ b/agent-governance-opencode/lib/policy.mjs @@ -1279,7 +1279,7 @@ export async function evaluateOpenCodeTool(state, input = {}) { /** * Inspect tool output after execution for OpenCode (tool.execute.after). - * Records an audit entry and (in enforce mode) returns a redaction directive + * Records an audit entry and returns a redaction directive in every mode * when the output appears to contain a known secret pattern. * * @param {object} state Loaded policy state from {@link loadPolicy}. @@ -1299,10 +1299,10 @@ export async function evaluateOpenCodeToolOutput(state, input = {}) { sessionId: input.sessionId, }); - if (!findings.length || state.policy.mode === "advisory") { + if (!findings.length) { return { redact: false, - reason: findings.length ? `AGT advisory: ${describeSecretFindings(findings)}` : "", + reason: "", }; } @@ -1360,4 +1360,3 @@ function redactSecretLikeContent(text, _findings) { function describeSecretFindings(findings) { return `matched ${findings.length} secret pattern(s): ${findings.join(", ")}`; } - diff --git a/agent-governance-opencode/test/policy.test.mjs b/agent-governance-opencode/test/policy.test.mjs index 76d5ada1b..89c5eb005 100644 --- a/agent-governance-opencode/test/policy.test.mjs +++ b/agent-governance-opencode/test/policy.test.mjs @@ -137,6 +137,35 @@ test("evaluateOpenCodeToolOutput redacts known secret patterns in enforce mode", await rm(root, { recursive: true, force: true }); }); +test("evaluateOpenCodeToolOutput redacts known secret patterns in advisory mode", async () => { + const root = await mkdtemp(join(tmpdir(), "agt-opencode-advisory-redact-")); + const policyPath = join(root, "policy.json"); + await writeFile( + policyPath, + JSON.stringify({ + schemaVersion: 1, + version: 1, + mode: "advisory", + toolPolicies: { allowedTools: ["*"] }, + }), + "utf8", + ); + const state = await loadPolicy({ policyPath, auditPath: join(root, "audit.json") }); + + const token = "ghp_" + "c".repeat(40); + const result = await evaluateOpenCodeToolOutput(state, { + tool: "bash", + output: `Here is your token: ${token}`, + sessionId: "advisory-redact-session", + }); + + assert.equal(result.redact, true); + assert.match(result.redactedOutput, /AGT_REDACTED:github-token/); + assert.doesNotMatch(result.redactedOutput, /ghp_c{40}/); + + await rm(root, { recursive: true, force: true }); +}); + test("evaluateOpenCodeToolOutput is a no-op for clean output", async () => { const root = await mkdtemp(join(tmpdir(), "agt-opencode-clean-")); const state = await loadPolicy({ auditPath: join(root, "audit.json") });