Skip to main content
The SARIF emitter (--output sarif) produces a schema-validated SARIF 2.1.0 file. Hand it to github/codeql-action/upload-sarif@v3 and every finding appears as an inline annotation on the PR’s Files changed view + a row in Security → Code scanning.

When to use this page

  • You already have an AgentGuardian GitHub Actions workflow running and want the findings visible on the PR diff.
  • You’re using GitHub Advanced Security (or a public repo) and want the per-rule trend graphs that Code Scanning gives you for free.
  • You want the SARIF to ride along on a failed --fail-under gate so reviewers can triage what failed without re-running locally.

The minimal recipe

Add one extra step after the agent-guardian scan step. The if: always() is non-optional — without it a failed --fail-under gate would suppress the upload and you’d lose the annotations on the PR that needs them most.
.github/workflows/agent-guardian.yml
That’s it. After the next push:
  1. The check appears in the PR conversation.
  2. Inline annotations land on the Files changed tab.
  3. Each finding appears in Security → Code scanning with a per-rule trend.

The four non-obvious GHAS rules

1. permissions: security-events: write

Code Scanning rejects uploads from a job that doesn’t carry the security-events: write permission. Set it at the workflow level (applies to every job) or per-job. Without it the upload fails with HTTP 403.
On a public repo that doesn’t have GitHub Advanced Security, Code Scanning is still available for free — the upload still works. Private repos without Advanced Security can’t upload SARIF.

2. if: always() keeps the upload alive

agent-guardian scan exits non-zero when --fail-under fires (EXIT_FAIL_UNDER, 1). Without if: always(), GitHub Actions skips every step after a failed step — and the upload step would never run. That defeats the purpose: the PR that failed the gate is exactly the PR that needs the annotations.

3. category separates parallel scans

If a single workflow runs more than one scan (e.g. two agents, or one scan for each --tier), pass category to keep their findings distinct in Code Scanning:
Without category, the second upload overwrites the first on the PR.

4. The action runs sarif_file through its own validator

The upload action validates the SARIF against the GHAS schema again on the server. AgentGuardian’s emitter already validates against the SARIF 2.1.0 schema before write — so a successful local emit is almost always a successful upload. The cases where the server-side validator still rejects:
  • A results[].ruleId that doesn’t match any rules[].id. AgentGuardian’s emitter checks this, but a hand-edited SARIF can drift.
  • A level value outside error / warning / note.
  • A non-UTF-8 file (shouldn’t happen unless the SARIF was re-encoded).

How findings render

The four-tier severity travels in properties.aivss_severity for tools that want it. See SARIF export.

Resolving / dismissing findings

GitHub Code Scanning lets reviewers dismiss findings inline with one of three reasons: Dismissed findings stay dismissed across re-uploads as long as the ruleId + location are stable. AgentGuardian uses the stable probe_id as ruleId, so the dismissal persists across scans — re-triggering the same probe doesn’t surface the dismissed finding again.

Trend tracking

Code Scanning’s per-rule trend graph reads off the rules[] entries across scans. Because the rule id is the probe id, you get a stable trend per probe — “we used to land ASI01-GH-005 every PR, then we fixed the system prompt, now we don’t” shows up as a clean drop. If you want a per-ASI trend instead of per-probe, use the scan.json and feed asi_scores into a dashboard — the SARIF surface is designed around per-rule resolution.

Anti-patterns

Don’t upload SARIF from a --mode fast or --mode smart scan to Code Scanning. mode_authoritative=false runs are smoke checks — surfacing those findings on the PR pollutes the trend graph with noise from runs that haven’t actually exercised the agent.
Don’t strip the properties.aivss_severity field thinking SARIF only needs level. Many AgentGuardian tools rely on it to split the SARIF error level back into critical vs high.
Don’t upload from a forked-PR run on a private repo. Forked PRs don’t get security-events: write even when the workflow asks for it. Run the scan on a separate workflow_run trigger instead.

Next step

GitHub Actions

The full workflow YAML that produces the SARIF.

SARIF export

What’s inside the file the action uploads.

Fail builds on high risk

Add a finding gate on top of the score gate.

GitLab CI

GitLab’s artifacts.reports.sast is the equivalent contract.