feat(vulns): add read-only detail vulns command for security scan findings

Merged
TJ
14h ago
+1622-48

Summary

Adds a read-only detail vulns command group for findings from Detail's security scans ("vulns"), modeled on detail bugs and detail scans. Findings have a severity instead of a priority and no review state, so there is no close / reopen / prioritize.

  • detail vulns list [repo] mirrors bugs list: --severity critical|high|medium|low (repeatable or comma-separated, default all), --sort newest|oldest|severity (default newest), --scan-id <wr_…>, --since / --until, --all, --limit (1–100, default 50), --page, --format table|json. Severity, sort and scan ID are filtered by the API. --all and the time window fetch every page and filter client-side, the same way bugs does.
  • detail vulns show <ssf_…> mirrors bugs show: ID, title, severity, file, created, commit, scan, linked issues and fix PR, then the markdown description rendered the same way as a bug summary.
  • detail vulns scans [repo] mirrors scans list for security scans: --status, --since / --until, --limit, --page, --format. Cards show per-severity counts (e.g. 14 High, 60 Medium, 412 Low) instead of open/dismissed/resolved.
  • Repo inference, pagination, JSON output, error messages and the update-notice silencing for --format json all work as they do for the bugs commands.

Other changes:

  • detail bugs list --vulns help text now says it filters bug-finder bugs flagged as security vulnerabilities, and points to detail vulns list for security-scan findings.
  • Bundled skill: detail-bugs (installed by detail skill) now has a detail vulns section and says when to use it rather than bugs list --vulns.
  • docs/HELP.md regenerated.

Dependency

Depends on usedetail/detail#18482, which adds the public endpoints GET /public/v1/vulns, GET /public/v1/vulns/{vuln_id} and GET /public/v1/vuln-scans.

[!WARNING]
The openapi.json in this PR was pulled from a local backend running #18482, not from prod, so the vendored-artifact CI step (cargo xtask check / openapi check) will fail until #18482 is deployed to prod. After that, cargo xtask generate-openapi should produce an identical file. The file uses the same formatting as xtask: I checked that re-serializing the current file reproduces it byte-for-byte.

Testing

  • cargo fmt --check, cargo clippy -- -D warnings, cargo test (345 unit tests, 18 integration) and cargo xtask check-help all pass.
  • New unit tests cover severity query building, time and scan filtering, pagination, list and show card contents, the severity breakdown, and CLI parsing (flags, bounds, --all conflicts, no mutating subcommands, JSON silencing). Integration help and no-auth tests now include vulns.
  • Smoke-tested against a local backend on forked prod data for usedetail/detail (515 vulns):
    • vulns list: default view, --severity critical,high --sort severity, --scan-id (486 for the seeded scan), --all (515 of 515), --since 7d --until 1d, and an empty-window hint. Pagination totals were correct, and --format json output was valid.
    • vulns show: a finding with a linked issue and a fix PR in both table and JSON output, plus one without a fix PR (fixPr omitted).
    • vulns scans: per-severity counts, --status / --since filters, and pagination.
    • Error paths: a malformed vuln ID, a malformed scan ID, an unknown vuln (403), an unknown scan (400) and an unknown repo.

šŸ¤– Generated with Claude Code