> ## Documentation Index
> Fetch the complete documentation index at: https://docs.roboticks.io/llms.txt
> Use this file to discover all available pages before exploring further.

# SARIF 2.1.0 Ingest

> Ingest any SARIF 2.1.0-compliant static-analysis tool — Bandit, Semgrep, CodeQL, Snyk, ESLint, Brakeman. Findings flow into the matrix and evidence pack.

# SARIF 2.1.0 ingest

**SARIF** (Static Analysis Results Interchange Format) is the OASIS-standard JSON format for static-analysis output. Roboticks ingests **SARIF 2.1.0** for any tool that emits it, so you don't need a bespoke connector for every new scanner.

Common SARIF-emitting tools that work out of the box:

| Tool                                                  | Domain                       |
| ----------------------------------------------------- | ---------------------------- |
| **Bandit**                                            | Python security              |
| **Semgrep**                                           | Multi-language patterns      |
| **CodeQL** (GitHub Code Scanning)                     | Multi-language deep analysis |
| **Snyk Code**                                         | Multi-language security      |
| **ESLint**                                            | JS/TS lint                   |
| **Brakeman**                                          | Ruby/Rails security          |
| **Trivy**                                             | Container vulnerability      |
| **Checkov**                                           | IaC security                 |
| **PMD**, **SpotBugs**                                 | Java                         |
| **Gosec**                                             | Go security                  |
| **Cargo audit** (with `--format json` + post-process) | Rust                         |

The bundled OSS scanners (Bandit, Semgrep, trivy, syft) emit SARIF natively — see [OSS scanners](/integrations/oss-scanners).

## Why this exists

Before SARIF, every static-analysis tool had its own report format. Now most modern tools emit SARIF, and you can plug a new scanner in without us writing a custom parser.

## Upload a SARIF file

```bash theme={null}
rbtk findings upload --tool <name> findings.sarif
```

The CLI auto-detects SARIF by JSON structure (`$schema` field or `runs[].tool.driver`). The `--tool` label is free-form — used in the dashboard to group findings by source.

## Wire it to your tool

<Tabs>
  <Tab title="Bandit">
    ```bash theme={null}
    bandit -r . -f sarif -o bandit.sarif
    rbtk findings upload --tool bandit bandit.sarif
    ```
  </Tab>

  <Tab title="Semgrep">
    ```bash theme={null}
    semgrep --config=auto --sarif --output semgrep.sarif .
    rbtk findings upload --tool semgrep semgrep.sarif
    ```
  </Tab>

  <Tab title="CodeQL">
    ```bash theme={null}
    codeql database create db --language=cpp
    codeql database analyze db cpp-security-and-quality.qls \
      --format=sarif-latest --output=codeql.sarif
    rbtk findings upload --tool codeql codeql.sarif
    ```
  </Tab>

  <Tab title="Snyk Code">
    ```bash theme={null}
    snyk code test --sarif-file-output=snyk.sarif
    rbtk findings upload --tool snyk snyk.sarif
    ```
  </Tab>

  <Tab title="Trivy">
    ```bash theme={null}
    trivy fs --format sarif --output trivy.sarif .
    rbtk findings upload --tool trivy trivy.sarif
    ```
  </Tab>
</Tabs>

## What the connector reads

For each `run` in the SARIF file, Roboticks extracts:

| SARIF field                                                    | Roboticks finding field      |
| -------------------------------------------------------------- | ---------------------------- |
| `tool.driver.name`                                             | source tool name             |
| `tool.driver.version`                                          | tool version                 |
| `results[].ruleId`                                             | rule ID                      |
| `results[].level`                                              | severity (mapped, see below) |
| `results[].message.text`                                       | message                      |
| `results[].locations[0].physicalLocation.artifactLocation.uri` | source file                  |
| `results[].locations[0].physicalLocation.region.startLine`     | line number                  |
| `results[].fingerprints` (or `partialFingerprints`)            | deduplication key            |
| `results[].suppressions`                                       | suppression status           |

Multi-location results (data-flow / taint paths) are preserved — the first location is the primary, the rest appear under **Code flow** in the finding detail view.

## Severity mapping

SARIF defines `level: none | note | warning | error`. Roboticks maps:

| SARIF level | Roboticks severity |
| ----------- | ------------------ |
| `error`     | `error`            |
| `warning`   | `warning`          |
| `note`      | `info`             |
| `none`      | suppressed         |

Some tools (Snyk, Semgrep) emit a `rank` (0–100) instead — Roboticks reads `properties.security-severity` if present and overrides the mapping:

| security-severity | Roboticks severity |
| ----------------- | ------------------ |
| ≥ 9.0             | `critical`         |
| 7.0–8.9           | `error`            |
| 4.0–6.9           | `warning`          |
| \< 4.0            | `info`             |

## Suppressions

SARIF `suppressions` round-trip:

```json theme={null}
"suppressions": [{
  "kind": "external",
  "justification": "false positive — input is sanitised in middleware"
}]
```

Findings with `kind: external` or `kind: inSource` (e.g., a `# nosec` comment) appear as **dismissed** in Roboticks and don't gate PR Check Runs.

## CI recipe (generic)

```yaml theme={null}
# .github/workflows/sarif-scan.yml
name: Static analysis (SARIF)
on: { pull_request: {} }

jobs:
  scan:
    runs-on: ubuntu-latest
    permissions: { id-token: write, contents: read }
    steps:
      - uses: actions/checkout@v4

      - name: Run scanners
        run: |
          pip install bandit semgrep
          bandit -r . -f sarif -o bandit.sarif || true
          semgrep --config=auto --sarif --output semgrep.sarif . || true

      - run: pipx install roboticks-cli
      - run: rbtk auth oidc-from-github

      - name: Upload SARIF
        run: |
          rbtk findings upload --tool bandit  bandit.sarif
          rbtk findings upload --tool semgrep semgrep.sarif
```

## Where findings appear

* **Traceability matrix** — findings link to requirements via the source file's `@confirms`-annotated test.
* **Findings view** — filterable by tool, severity, suppression state, and rule ID.
* **Release evidence pack** — SARIF Findings appendix in the PDF; raw SARIF JSON files in the ZIP.
* **PR Check Run** — `Roboticks · Findings` summarises new/resolved across all SARIF tools.

## Validating a SARIF file

If your tool emits malformed SARIF (it happens), validate before upload:

```bash theme={null}
pip install sarif-tools
sarif-validate findings.sarif
```

Or use the [SARIF Multitool](https://github.com/microsoft/sarif-sdk):

```bash theme={null}
dotnet sarif validate findings.sarif
```

Roboticks rejects deliveries that fail JSON-schema validation against the SARIF 2.1.0 spec.

## Multi-run SARIF files

A SARIF file may contain multiple `runs[]` (one tool per run). Roboticks handles them — each run becomes a separate finding source. Useful when one CI step bundles several scanners.

## Limitations

* **Result kind `pass`** is recorded as a passing check but not surfaced in the matrix. Most tools don't emit these; if yours does, the data is preserved in the ZIP.
* **Inline taxonomies** (e.g., `taxonomies[]`) are stored verbatim and queryable via API but not rendered specially in the UI.
* **SARIF 1.0 / 2.0** — convert via the SARIF Multitool to 2.1.0 first.

## Troubleshooting

<AccordionGroup>
  <Accordion title="`SARIF schema validation failed`">
    Run `sarif-validate` locally to see the specific violation. Common culprit: missing required `$schema` or `version` fields.
  </Accordion>

  <Accordion title="Findings have no source file linkage">
    The `physicalLocation.artifactLocation.uri` is relative; Roboticks resolves it against the commit's repo root. If the tool emits absolute paths from the build host, post-process with `jq` to strip the host prefix before uploading.
  </Accordion>

  <Accordion title="Same finding reported on every PR">
    Most likely the tool isn't emitting `partialFingerprints`, so Roboticks can't dedupe across runs. CodeQL and Snyk emit them by default; for Semgrep, enable `--metrics=on` and check that the SARIF output has `partialFingerprints` populated.
  </Accordion>
</AccordionGroup>

## Next

<CardGroup cols={2}>
  <Card title="OSS scanners" icon="shield-check" href="/integrations/oss-scanners">
    The bundled SARIF-emitting tools shipped in paid tiers.
  </Card>

  <Card title="BYO connectors" icon="microscope" href="/integrations/byo-connectors">
    When a custom commercial connector beats generic SARIF.
  </Card>
</CardGroup>
