Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 3 additions & 4 deletions agent-governance-opencode/lib/policy.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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}.
Expand All @@ -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: "",
};
}

Expand Down Expand Up @@ -1360,4 +1360,3 @@ function redactSecretLikeContent(text, _findings) {
function describeSecretFindings(findings) {
return `matched ${findings.length} secret pattern(s): ${findings.join(", ")}`;
}

29 changes: 29 additions & 0 deletions agent-governance-opencode/test/policy.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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") });
Expand Down
Loading