feat(audit): weekly CodeRabbit Deep Scan audit that files findings as issues

DO
23m ago
+1258-0

Summary

Adds a weekly audit (Thursday 17:01 UTC) that reads CodeRabbit Deep Scan findings from GET /v1/security/scans/code?format=sarif&state=all and keeps one issue per finding, keyed on findingFingerprint, in the repo that owns the code. These findings currently reach neither the SonarCloud nor the CodeQL audit.

Standard: standards/ci-standards.md § CodeRabbit Audit.

Design choices (approved by the repo owner before this PR)

ChoiceDecision
Public issue contentFingerprint, finding ID, severity, repo. No category, CWE, subsystem, path, line, description or call stack: every org repo is public and these findings can describe exploit chains
dev-leadNever added by the audit. Issues get needs-verification; a person confirms the finding and adds dev-lead. The API exposes no verification result to gate on
Severity thresholdEvery severity is filed (MIN_SEVERITY defaults to low)

Behavior worth reviewing

  • Routing: a finding located in a caller stub (no steps:, calling one org repo's reusable workflow) goes to that repo. Call-stack frames are not used, because CodeRabbit guarantees neither their order nor their format.
  • Closing: only on an explicit fixed or dismissed. A finding absent from the export stays open and is counted, because a partial-coverage scan omits findings it did not reach.
  • Fail closed: a failed read, an export missing expected identity fields, an unreadable stub, or an unlistable repo fails the run with no issue writes. API error bodies are never logged.
  • Artifact: the counts-only summary.md.

Test plan

  • bats test/scripts/coderabbit-audit/: 56 pass, including stubbed end-to-end runs with canary strings in every sensitive field
  • Mutation checks: leaking finding text to logs or issue text, adding dev-lead, closing on absence, passing the key in argv, and filing duplicates each fail a test
  • shellcheck, actionlint, check-cron-timing.sh, gitleaks
  • Dry run over two real UI exports with curl stubbed: parses and routes, no issue writes
  • First keyed workflow_dispatch with dry_run: true

Not yet verified

No API key exists yet, so the live endpoint has not been called. Check these on the first keyed dry run:

  • The API's SARIF matches the UI export's fields. A mismatch fails the run with no writes.
  • state=all returns fixed and dismissed findings. The sample exports contain only open.
  • The key works on this plan. The endpoint page says all plans qualify.
  • findingFingerprint is stable across scans. Every sampled finding has only been seen in one scan. If it is not stable, each scan files duplicates, visible as a rising "absent from this export" count.

Before merge

  1. Create a non-agentic CodeRabbit API key with security:read and add it as the CODERABBIT_API_KEY repository secret on combsmith/.github.
  2. Set a recurring Deep Scan schedule per repo in CodeRabbit. The API only reads results, and scans are usage-billed.

The first non-dry run files about 72 issues based on current exports.

🤖 Generated with Claude Code

Problem

See the linked issue.

Risk

Medium — changes GitHub Actions workflow behavior, which is exercised only post-merge; verify via the affected workflow runs.

Test plan

Tests added/updated: test/scripts/coderabbit-audit/audit-run.bats,test/scripts/coderabbit-audit/pure-helpers.bats. Verification: bash scripts/dev-lead-lint.sh (shellcheck --severity=warning) ran pre-commit; the bats suite runs in CI.

Rollback

Revert this PR. No non-revertible side effects (no tags, migrations, or external state).

Monitoring

Watch the affected workflow run(s) in the Actions tab and this PR's Lint check for regressions.