SARIF & code scanning

Shipmoor Team
June 11, 2026
3 min read

SARIF is how Shipmoor findings become first-class citizens of your code-review surface: annotations on the PR diff, entries in the Security tab, and a history of what was found when. Shipmoor emits standard SARIF 2.1.0 from the same evidence as its human and JSON output.

Producing SARIF

shipmoor scan --diff origin/main...HEAD --sarif --output shipmoor.sarif

Every finding carries its rule ID (e.g. python.phantom_import), severity, location, message, and remediation text, plus a stable fingerprint — so code scanning can track a finding across pushes instead of re-opening it as new each time. Rule metadata links back to the rule’s documentation.

When --sarif writes to stdout instead of a file, stdout contains only the SARIF document (diagnostics go to stderr), so it pipes cleanly.

Uploading to GitHub code scanning

      - name: Run Shipmoor
        run: |
          shipmoor scan --diff origin/main...HEAD \
            --sarif --output shipmoor.sarif --fail-on high
      - name: Upload SARIF
        if: always()
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: shipmoor.sarif

Two details do the heavy lifting:

  • if: always() — the upload must run even when the scan step failed the job. The runs you most want in the Security tab are exactly the ones where the gate fired.
  • security-events: write — the job needs this permission for the upload.

The full workflow (and the composite-action form) is in GitHub Actions.

Exit codes: gate signal vs. error

The scan’s exit code and the SARIF are designed to be consumed together:

CodeWhat happenedIs the SARIF valid?
0CleanYes — complete (and empty of findings)
1Findings met the --fail-on gateYes — complete. This is the gate working, not an error.
2Usage or config errorNo report produced
3Scan crashedNo report produced

So the correct CI shape is: let exit 1 fail the check (that’s its job) while still uploading the report; reserve “tooling broke” alerts for 2 and 3, where no report exists.

If you want code-scanning evidence without a blocking check, run with --fail-on none — full SARIF, always exit 0 on a successful scan.

Beyond GitHub

The SARIF is standard: GitLab, Azure DevOps, and most code-quality dashboards ingest SARIF 2.1.0 directly. For systems that prefer raw data, the JSON contract (shipmoor.scan.v1) carries everything the SARIF does and more (subtypes, change_status, fingerprints).

Next

Last updated on June 11, 2026

Was this article helpful?

Your response is saved on this device.