skip to content

How do you get results from a non-CodeQL scanner into GitHub code scanning?

level: middleimportance: should knowfreq 41%

answer

  1. The format is the contract, not the engine
  2. One permission gates the upload
  3. Two tools, one label, mutual erasure
  4. Fingerprints keep an alert the same alert

basics

~10 s

Have the tool emit SARIF 2.1.0 and upload it — the github/codeql-action/upload-sarif action, or the code scanning SARIF API from external CI. The job needs security-events: write, and each tool needs its own category.

solid answer

~50 s

GitHub code scanning stores SARIF, so any scanner that can emit SARIF 2.1.0 becomes a first-class producer of alerts. In GitHub Actions you run the tool, then add a `github/codeql-action/upload-sarif` step with `sarif_file` pointing at the output and a `category` naming the tool; the job needs `security-events: write`. From CI outside GitHub, you post the SARIF to the code scanning SARIF API with a token that has the same permission. Two details separate a working integration from a broken one. First, **`category`**: each upload replaces the previous results for its category, so two tools sharing one category will erase each other's alerts on every run. Second, **result fingerprints**: SARIF's `partialFingerprints` are what let GitHub match a finding across commits. Without them, alerts churn — the same finding closes and reopens as lines shift. Rule metadata matters too: a `security-severity` property on the rule is what drives the alert's severity.

code

yaml · 13 lines
yaml
jobs:
  scan:
    runs-on: ubuntu-latest
    permissions:
      security-events: write
      contents: read
    steps:
      - uses: actions/checkout@v4
      - run: ./run-scanner.sh --format sarif --output results.sarif
      - uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: results.sarif
          category: my-scanner

go deeper

for a junior

Know that GitHub code scanning is not CodeQL-only: a scanner that writes SARIF can be uploaded so its findings appear as ordinary alerts on the pull request.

for a middle

Explain the upload mechanics — the SARIF file, the upload-sarif step or the SARIF API, and the security-events: write permission the job needs.

for a senior

Demonstrate the failure modes you have hit: category collisions wiping alerts, missing fingerprints causing churn, fork pull requests unable to upload.

for a principal

Argue the consolidation case — one alert list and one triage and dismissal workflow across every scanner, so policy attaches in one place instead of per tool.

## Code scanning is a SARIF store, not a CodeQL store The important design fact is that GitHub's alert model is defined by the file format, not the engine. SARIF — Static Analysis Results Interchange Format, an OASIS standard, version 2.1.0 — describes tools, rules, results, locations and severities. Code scanning ingests SARIF and renders it as alerts. CodeQL happens to emit SARIF; so do many linters and scanners. Consequently the answer to "can we see our other scanner's findings in the pull request?" is almost always yes, provided it can emit SARIF or you can convert its output. ## The Actions path Inside a workflow the sequence is: run the tool so it writes a SARIF file, then upload it. ``` - run: ./run-scanner.sh --format sarif --output results.sarif - uses: github/codeql-action/upload-sarif@v3 with: sarif_file: results.sarif category: my-scanner ``` The action is published in the `github/codeql-action` repository but is not CodeQL-specific — `upload-sarif` is the generic ingestion step. The job requires `security-events: write` on its token; that permission, not repository access alone, is what authorises writing alerts. `sarif_file` accepts a directory as well as a file, which is convenient when a tool shards output per module. ## The API path When the analysis happens somewhere GitHub Actions is not — an on-premises Jenkins, a nightly job on a build farm — you upload through the code scanning SARIF endpoint instead, sending the SARIF gzipped and base64-encoded along with the commit SHA and ref it describes. The credential needs the same code-scanning write capability. The result is indistinguishable in the UI from an Actions upload: same alert list, same annotations. GitHub applies documented size and result-count limits per upload, so very large result sets need splitting or filtering at the tool. ## Category: the field people get wrong Every upload is scoped to a `category` (for the API, an equivalent field in the SARIF run's automation details). GitHub treats an upload as the complete, current result set *for that category on that ref*. Anything previously reported under the same category and no longer present is marked fixed. The failure mode follows directly: run two different tools and upload both without categories, and each run wipes the other's alerts. Fixed alerts flip back to open, and open alerts flip to fixed, on alternate runs. Distinct categories per tool — and per language or per shard when one tool is run several times — is the fix. ## Fingerprints and alert stability SARIF results may carry `partialFingerprints`. GitHub uses them to decide whether a result in today's upload is the *same alert* as one from last week, even though the file has been edited and line numbers moved. A tool that omits fingerprints leaves GitHub matching on weaker signals, and the symptom is alert churn: a dismissal seems not to stick, alert counts jump around, and the pull request annotates findings the team already triaged. If you write the SARIF conversion yourself, generating a stable fingerprint per finding is the highest-value thing you can do. ## Severity and presentation SARIF's own `level` (error, warning, note) drives whether the code scanning check fails. Security severity — critical, high, medium, low — comes from a `security-severity` property on the rule, which is what a severity-based merge gate will read. Rule metadata such as a name, full description and help text is what makes the alert readable; a bare `ruleId` with no help text produces alerts nobody can act on, which is the fastest route to a muted scanner. ## Constraints worth naming - **Fork pull requests.** A workflow triggered by a pull request from a fork runs with a read-only token, so it cannot upload results. Teams handle this by running the analysis on the base repository's own events, and accepting that fork contributions are scanned after merge or through a separately privileged flow. - **Licensing.** Third-party SARIF upload on private repositories sits behind the same paid code-security capability as CodeQL; it is free on public repositories. - **Ref correctness.** The upload names a commit and ref. Get those wrong — a common bug in hand-rolled API integrations — and alerts attach to the wrong branch and never annotate the pull request. ## Why interviewers ask it It separates people who think GitHub security means "turn CodeQL on" from people who have consolidated several scanners into one triage surface. The consolidation argument is the real content: one alert list, one dismissal workflow, one place branch policy points at, regardless of how many tools produce the findings.

  • Can a pull request opened from a fork upload SARIF results?
    No. Workflows triggered by a fork's pull request run with a read-only token, so the upload step cannot write alerts. Teams either scan on events in the base repository, accept that fork contributions are analysed after merge, or route them through a separately privileged flow that never runs untrusted code with a write token.
  • How does GitHub decide an uploaded alert's severity?
    SARIF's result level — error, warning, note — determines whether the code scanning check fails. Security severity, used by severity-based gating, comes from a security-severity property on the rule in the SARIF. A tool that emits neither leaves every alert looking equally, and unhelpfully, important.

saying these in an interview costs you the question

  • Believing only CodeQL can create code scanning alerts
  • Uploading several tools under one category
  • Omitting partialFingerprints and blaming GitHub for churn
  • Expecting a fork pull request to upload results
  • Thinking a job token gets upload rights automatically

context