SARIF is how Shipmoor Scan findings become annotations on the PR diff and entries in the Security tab. Current self-managed CI supports Scan only and requires a scan-scoped SHIPMOOR_TOKEN.
Producing SARIF
Add --sarif and point --output at a file:
shipmoor scan --diff origin/main...HEAD --sarif --output report.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 into another tool.
Suppressions stay in parity. A finding you’ve dismissed with an inline
shipmoor:ignoredirective is removed before the gate runs and before either machine format is written, so the SARIF omits exactly the same suppressed findings the JSON does. The editor, the JSON contract, and code scanning all agree on what was suppressed.
Uploading to GitHub code scanning
Expose SHIPMOOR_TOKEN through the job environment. The token authorizes Scan; it must not be printed, written to disk, or placed in a command-line argument.
Hand the SARIF file to the official upload action:
- name: Run Shipmoor
run: |
"$HOME/.shipmoor/bin/shipmoor" scan --diff origin/main...HEAD \
--sarif --output report.sarif --fail-on high
- name: Upload SARIF
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: report.sarif
Two details do the heavy lifting:
security-events: write: the job needs this permission for the upload to succeed. Declare it on the job alongsidecontents: read:
jobs:
shipmoor:
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
if: always(): the upload step 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, so you cannot let exit1short-circuit the upload.
The full token-authenticated workflow is in GitHub Actions.
Exit codes: gate signal vs. error
The scan’s exit code and the SARIF are designed to be consumed together. A gate firing is not a tooling failure; the report is complete and worth uploading.
| Code | What happened | Is the SARIF valid? |
|---|---|---|
0 | Clean; no gate fired | Yes, complete (and empty of findings) |
1 | Findings met the --fail-on gate | Yes, complete. This is the gate working, not an error. |
2 | Usage or config error | No report produced |
3 | Scan failed | No report produced |
So the correct CI shape is: let exit 1 fail the check (that is its job) while still uploading the report, and reserve “tooling broke” alerts for 2 and 3, where no report exists.
Uploading even when the gate fails
If you want SARIF in code scanning on every run, including the ones where a blocking finding fired the gate, make sure the failing exit code does not abort the job before the upload:
- Simplest: keep
--fail-on highon the scan step and mark the upload stepif: always(), as above. The scan step still fails the job (so the check goes red), but the always-run upload step delivers the report first. - Decoupled: run the scan in a step that does not abort the job (capture its exit code), upload the SARIF, then fail the job yourself on the captured code:
- name: Run Shipmoor (don't abort on a blocking finding)
id: scan
run: |
"$HOME/.shipmoor/bin/shipmoor" scan --diff origin/main...HEAD \
--sarif --output report.sarif --fail-on high \
|| echo "code=$?" >> "$GITHUB_OUTPUT"
- name: Upload SARIF
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: report.sarif
- name: Enforce the gate
if: steps.scan.outputs.code == '1'
run: exit 1
If you instead want code-scanning evidence with no blocking check at all, run with --fail-on none; you get full SARIF and a 0 exit on any successful scan.
Beyond GitHub
The SARIF is standard SARIF 2.1.0. Uploading it to GitHub, GitLab, Azure DevOps, or another configured provider is an explicit action outside Shipmoor’s default service contacts. Shipmoor does not upload source, diffs, repository content, findings, or SARIF by default.
Next
- GitHub Actions: the full token-authenticated Scan workflow.
- Output formats & exit codes: the complete output contract.