Skip to main content
The SARIF emitter writes a schema-validated SARIF 2.1.0 file that any code-scanning UI can consume. Source: reports/sarif.py

When to use this page

  • You’re wiring AgentGuardian into a GitHub Actions workflow and need the SARIF to upload to the Security tab.
  • You’re feeding a Sonar / SemGrep-style aggregator that already consumes SARIF from other scanners.
  • You want per-finding inline annotations on the PR’s Files changed view.

Generate one

Or regenerate from a stored scan:
The SARIF emitter validates the payload against the bundled SARIF 2.1.0 schema before writing. A malformed payload raises ReportError rather than landing on disk silently broken.

The SARIF shape

One runs[] entry per scan. Each run carries one tool.driver (the AgentGuardian metadata), one rules[] entry per triggered probe, and one results[] entry per finding.

How severity maps

SARIF only has three levels (error, warning, note). AgentGuardian has four (critical, high, medium, low). The mapping folds critical + high into error and the four-tier value goes into properties.aivss_severity for downstream tools that want the full resolution. GitHub Code Scanning, Sonar, and the major static-analysis UIs all render error distinct from warning distinct from note. The aivss_severity property is what lets a custom dashboard re-split error into critical vs high.

The mapping triple inside SARIF

Every finding carries the same OWASP / MITRE / CSA triple as the JSON emitter — propagated through properties so a SARIF consumer can group findings by ASI without ever loading the JSON:

Redaction

The SARIF emitter routes every finding through the shared redact_finding helper before serialisation — same scrubbing the JSON emitter applies. message.text, properties.trigger_prompt (if present), and any embedded transcripts are scrubbed of PII and credential shapes (OpenAI / AWS / GitHub / Google keys, JWTs, bearer tokens, password= assignments). This is not a knob. A security scanner must never re-emit a captured secret into a SARIF that gets uploaded to a public PR.

Schema validation

The SARIF emitter validates against the bundled SARIF 2.1.0 schema before writing the file. A schema violation raises ReportError with the offending JSON Pointer. The bundled schema is the published draft from oasis-tcs/sarif-spec. This catches the failure modes a downstream consumer (GHAS, Sonar) would silently reject:
  • Missing required version, runs[], tool.driver.name.
  • A results[].ruleId that doesn’t match any rules[].id.
  • An out-of-enum level value.

Uploading to GitHub Code Scanning

The official action handles the upload — see Upload SARIF to GitHub for the full walk-through. The minimal shape:
Two non-obvious GHAS rules:
  1. Your job needs permissions: security-events: write at the workflow or job level.
  2. Use if: always() so a failed --fail-under gate still uploads the SARIF — otherwise reviewers lose the annotations on the PR that needs them most.

Anti-patterns

Don’t rely on the SARIF level field to distinguish critical vs high findings. Both fold into error. Read properties.aivss_severity for the four-tier resolution.
Don’t assume results[].ruleId is unique per probe. A probe can produce multiple findings on one scan (one per landed turn) — each finding has its own results[] entry but shares the ruleId with every other finding from the same probe. Group by properties.finding_id if you need uniqueness.
Don’t upload an unredacted SARIF to a public Code Scanning surface. The emitter redacts by default; if you wrap it in your own script that re-fetches the bundle, route through redact_finding first.

Next step

Upload SARIF to GitHub

The github/codeql-action/upload-sarif@v3 walk-through.

GitHub Actions

The full workflow that produces + uploads the SARIF.

JSON export

The signed canonical artifact every other emitter is derived from.

Report schema

Field-by-field reference for the JSON + SARIF outputs.