// docs · v1.x

SARIF and Code Scanning

Write review, guard and leaks findings as a SARIF 2.1.0 log with --sarif and upload them to GitHub Code Scanning. Covers the format, categories, fingerprints, failure modes and limits.

Updated October 20, 2026

SARIF (Static Analysis Results Interchange Format) is the JSON format GitHub Code Scanning and most security dashboards read. --sarif makes a review write one SARIF 2.1.0 log instead of cards, markdown or JSON. Requires v1.19.0 or later. guard --sarif and leaks --sarif: Requires v1.21.0 or later.

Key facts. Local boolean flag on the root review, on commitbrief diff, on guard and on leaks. The review and guard need an API provider. Every command fails closed: a degraded or partial run writes no file.

Writing the log

commitbrief diff origin/main...HEAD --sarif -o commitbrief.sarif

Without -o the log goes to stdout. It is a renderer choice like --json, so it combines with --fail-on, which gates on the same set the file contains.

Uploading to GitHub

permissions:
  contents: read
  security-events: write

steps:
  - uses: actions/checkout@v4
    with:
      fetch-depth: 0
  - run: commitbrief diff origin/${{ github.base_ref }}...HEAD --sarif -o commitbrief.sarif
    env:
      ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
  - uses: github/codeql-action/upload-sarif@v4
    if: always()
    with:
      sarif_file: commitbrief.sarif
      category: commitbrief

For guard and leaks, use the category from the table in Categories.

security-events: write is required; private repositories also need actions: read. Code Scanning availability depends on your GitHub plan and repository visibility; check GitHub’s documentation for your account. Use a distinct category so CommitBrief results do not replace those of another tool.

What each result carries

SARIF fieldValue
ruleId, ruleIndexThe finding’s rule id and its index in tool.driver.rules[]
levelcritical and high map to error, medium to warning, low and info to note
rank90, 70, 50, 30, 10 by severity. GitHub ignores it.
message.textTitle — Description, plus Suggestion: … on a new line
locations[].physicalLocationRepo-relative forward-slash URI with uriBaseId %SRCROOT%, startLine, endLine
partialFingerprints["commitbrief/v1"]The finding’s fingerprint
properties["commitbrief/severity"]The original five-level severity

tool.driver.rules[] lists all 30 rules, each with a short definition, a default level, tags (the category, plus security for sec.*) and a help link to the rule list. automationDetails.id is commitbrief/ for the review (see Categories for guard and leaks). Because the fingerprint ignores line numbers, Code Scanning keeps tracking an alert when surrounding code moves.

A finding with no usable line (line 0 or less) is anchored on line 1 and marked properties["commitbrief/file-level"] = true.

Categories

Each command writes its own automationDetails.id, and each should be uploaded with the matching category:

CommandautomationDetails.idUpload category
Root review and diffcommitbrief/commitbrief
guardcommitbrief/guard/commitbrief/guard
leakscommitbrief/leaks/commitbrief/leaks

Code Scanning treats a result that is missing from a category as fixed. If the three commands shared one category, a clean leaks run would close the alerts a review had opened, and the reverse. Separate categories keep each command’s alerts independent.

Policy gate: guard --sarif

Requires v1.21.0 or later.

commitbrief guard --sarif -o guard.sarif

The log holds only the findings that cause a violation under your .commitbrief/policy.yml. It is built from the same set the verdict is computed from, so the file and the exit code cannot disagree. When the total cap is exceeded, every finding not waived by rules.allow is in it; waived findings never are. A passing run writes a valid log with results: [], which clears old commitbrief/guard/ alerts.

It fails closed like the review: when the model response could not be parsed into structured findings, whether in a live run or from --from-json input, no file is written and the command exits 1. Re-run the review. See Policy gate.

Secret scan: leaks --sarif

Requires v1.21.0 or later.

commitbrief leaks --sarif -o leaks.sarif

Every result uses the rule id sec.hardcoded-secret. A result never contains the matched text, a snippet, an author or a fingerprint. The names of the matching patterns are in properties["commitbrief/patterns"], and for a finding in history the short commit hash is in properties["commitbrief/commit"].

Because Code Scanning closes alerts that are absent from the upload, leaks --sarif only writes a log for a complete scan:

  • It refuses to combine with --no-worktree, --no-history, --file, --dir, --exclude-file, --exclude-dir, --author, --committer, --start-date, --end-date, --text or a git range. That is a usage error.
  • If the history scan stops at the --max-commits window, no file is written and the command exits 1. Pass a larger window with --max-commits N and re-run.
  • If the history is longer than the commit walk can cover, no file is written and the command exits 1. --max-commits cannot raise that limit.

The human report moves to stderr, and --fail-on still decides the exit code, so a run with findings writes the log and exits 1. --sarif does not combine with --json or --patterns. See Credential audit.

Failure modes

SituationResult
Empty diff after filteringA valid log with results: [], so a clean run still clears old alerts
Degraded or unparsed model response, fresh or from cacheError, no file written, exit 1
CLI-backed provider (claude-cli, gemini-cli, codex-cli)Refused before any call: these emit plain text, not findings
--json, --markdown, --suggest-commit, --cli or --show-prompt togetherRefused as conflicting output flags
guard or leaks with a degraded or partial runError, no file written, exit 1; see the sections above

The degraded case is deliberate: a half-parsed review uploaded as clean would close real alerts. On a fresh degraded run the cache is still written.

Limits

  • --min-severity does not filter SARIF. Every finding is in the file.
  • guard --sarif lists violating findings only; the other commands list every finding.
  • Severity and rule choice come from the model. A rule id the model gets wrong is still a wrong alert; see When the model picks the wrong id.
  • The rank field is informational only.

See also