Skip to content

feat(cli): complete machine-readable output and exit-code contract (#171, #160, #150)#189

Merged
dgenio merged 4 commits into
mainfrom
claude/issue-triage-grouping-qyg4w1
Jun 18, 2026
Merged

feat(cli): complete machine-readable output and exit-code contract (#171, #160, #150)#189
dgenio merged 4 commits into
mainfrom
claude/issue-triage-grouping-qyg4w1

Conversation

@dgenio

@dgenio dgenio commented Jun 18, 2026

Copy link
Copy Markdown
Owner

Summary

Completes AgentFence's machine-readable output & exit-code contract across the CLI. check, explain, and audit summarize already supported --output json; this adds the same convention to the remaining subcommands so every gate a CI pipeline runs can be consumed structurally without parsing prose.

What changed (file by file):

  • cmd/agentfence/main.go
    • Add JSON output and exit-code contract to policy test #171policy test --output text|json. JSON emits a per-case report ({id, tool, expect, got, pass, reason}) plus {total, passed, failed}. Text path (PASS/FAIL, --verbose) unchanged. Non-zero exit on any failure preserved in both modes.
    • Add an audit verify --json machine-readable verification result #160audit verify --output text|json. JSON emits one combined {chain, signatures?, anchor?} object with stable status enums (ok/no_chain/partial/corrupt/failed, etc.). The three report functions were refactored into compute*Result + printText helpers; the text output is byte-for-byte unchanged (existing strings.Contains tests stay green). The JSON object is emitted even on failure, and exit codes are identical to text mode.
    • Add an audit-log statistics exit/summary for CI gate transparency #150check --summary <file|->. Writes a compact JSON gate summary (total, parse_errors, by_decision, top_denied_tools, top_denied_reasons, fail_on, matched, failed, dry_run) independent of --output, before the --fail-on exit so the artifact exists even when the gate fails. - sends it to stderr to keep --output stdout clean.
    • Usage/help strings updated for the new flags.
  • cmd/agentfence/main_test.go — 7 new tests: JSON shapes, exit codes, stdout-purity (no prose leak), unknown --output rejection, and gate-summary file + stderr destinations.
  • README.md — CI section documents --summary and the policy test/audit verify JSON modes.
  • CHANGELOG.md[Unreleased] entry.

Why

These three issues are one surface — extending the existing --output json convention to the subcommands that lacked it, plus a CI gate summary — all in cmd/agentfence/main.go. They share a module, a category, and a test pass, so they ship cleaner together than separately (this was the recommended combined group from the triage).

Scope note (Mode B): the repo norm is one-concern-per-PR; bundling these three was explicitly requested. They are tightly cohesive (same file, same convention, no cross-dependencies).

How verified

  • make ci (fmt-check + vet + test-race + coverage) — green; total coverage 81.1%.
  • go test ./cmd/agentfence/ -run 'PolicyTest|AuditVerify|CheckGateSummary|CheckOutput' -v — all pass.
  • Manual smoke against bundled examples:
    • policy test --output json{total:21, passed:21, failed:0, cases:[…]}, exit 0.
    • audit verify --output json{"chain":{"status":"no_chain","events":6,…}}.
    • check … --fail-on deny --summary - → JSON summary on stderr (matched:3, failed:true), exit 1.

Related issue

Fixes #171
Fixes #160
Fixes #150

Checklist

  • Tests added or updated
  • Documentation updated if needed
  • CI passes (make ci locally; green)
  • Issue number included

Tradeoffs / risks

  • The audit verify refactor is the largest change; mitigated by keeping the text output byte-for-byte identical and covered by existing tests.
  • New JSON shapes are public contracts going forward; field names were chosen to match the existing audit summarize style.

🤖 Generated with Claude Code

https://claude.ai/code/session_01E2YUNXPiwtyXJ6Javs4WxU


Generated by Claude Code

Extend the CLI's structured-output convention (already used by check,
explain, and audit summarize) to the remaining subcommands, so every gate
a CI pipeline runs can be consumed structurally while preserving exit codes.

- policy test: add --output text|json; JSON emits a per-case report
  ({id, tool, expect, got, pass, reason}) plus totals. (#171)
- audit verify: add --output text|json; JSON emits a combined
  {chain, signatures?, anchor?} object with a stable status enum. The text
  path is refactored into compute + printText helpers and is byte-for-byte
  unchanged. (#160)
- check: add --summary <file|->; writes a compact JSON gate summary
  (per-decision counts, top denied tools/reasons, fail-on match, failed
  flag) independent of --output, before the --fail-on exit. (#150)

Tests cover JSON shapes, exit codes, stdout-purity, unknown --output, and
the gate-summary file/stderr destinations. README and CHANGELOG updated.

Fixes #171
Fixes #160
Fixes #150

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E2YUNXPiwtyXJ6Javs4WxU
Copilot AI review requested due to automatic review settings June 18, 2026 09:12

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Completes AgentFence CLI’s machine-readable output and exit-code contract by extending --output json support to additional subcommands and adding a separate check --summary JSON artifact for CI gate reporting (without parsing human-oriented text).

Changes:

  • Add check --summary <file|-> to emit a compact JSON gate summary independent of --output.
  • Add policy test --output text|json with per-case results + totals, preserving failure exit semantics.
  • Add audit verify --output text|json with a combined {chain, signatures?, anchor?} JSON report while keeping text output and exit-code behavior consistent.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 6 comments.

File Description
cmd/agentfence/main.go Implements check --summary, policy test --output json, and audit verify --output json (plus helper result structs/functions).
cmd/agentfence/main_test.go Adds tests covering JSON shapes, exit semantics, stdout purity, and summary destinations.
README.md Documents check --summary and the new JSON modes for policy test / audit verify.
CHANGELOG.md Adds [Unreleased] entries describing the new CLI contracts.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread cmd/agentfence/main.go
Comment thread cmd/agentfence/main.go
Comment thread cmd/agentfence/main.go
Comment thread cmd/agentfence/main.go
Comment thread cmd/agentfence/main.go
Comment thread cmd/agentfence/main.go
claude added 3 commits June 18, 2026 09:19
Address PR review: the I/O-failure and otherwise-unclassified verification
paths in computeChainResult/computeAnchorResult returned a zero-value result,
emitting an empty chain.status / anchor.status in --output json and breaking
the advertised stable status-enum contract. Set status "error" with a detail
message in those paths; the text presenter is unaffected (it has no "error"
case and stays silent, as before). Document "error" on auditChainResult.

Refs #160

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E2YUNXPiwtyXJ6Javs4WxU
Address PR review: --summary - writes to stderr, which on a --fail-on gate
failure also carries the human "matched --fail-on" line and the root "error:"
line, so it is not pure JSON in that case. Clarify in the flag help and README
that a file path is the clean machine-readable artifact (produced even on gate
failure) and that - is a logging convenience. Behavior unchanged.

Refs #150

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E2YUNXPiwtyXJ6Javs4WxU
…acts

The audit verify --output json work added `signatures` and `anchor`
sub-objects as public machine-readable contracts, but only the `chain`
sub-object was asserted in JSON mode. Add JSON-mode tests that exercise:

- `--pubkey`: the signatures sub-object (status=ok, verified/unsigned
  counts) on a signed tamper-evident log, with no SIGNATURES: prose leak.
- `--anchor`: the anchor sub-object (status=ok, signature_status=
  not_checked for an unsigned anchor) with no ANCHOR: prose leak.
- a plain (non-chained) log: the chain `no_chain` status enum, with no
  PARSED: prose leak.

Tests drive the real CLI subcommands (keygen, anchor, check --sign-key)
to match the existing helper style. No production code changes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LRaLVqBWb8kbyXbm8LBn43
@dgenio dgenio merged commit 8a7f916 into main Jun 18, 2026
4 checks passed
@dgenio dgenio deleted the claude/issue-triage-grouping-qyg4w1 branch June 18, 2026 19:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants