-
Notifications
You must be signed in to change notification settings - Fork 0
CI Templates
postmortem ships a GitHub Action, and generates ready-to-commit pipelines for the other three major platforms:
postmortem ci gitlab > .gitlab-ci.yml
postmortem ci azure > azure-pipelines.yml
postmortem ci jenkins > Jenkinsfile
postmortem ci github > .github/workflows/postmortem.ymlThe templates are generated, not committed. A checked-in YAML file drifts the first time a release URL or a flag name changes, and the person who finds out is a user whose pipeline broke. Generating them means the install snippet lives in exactly one place, and the pinned version is always the version of the binary that printed it — a template can never reference a release that does not exist.
Pin a different release with --version:
postmortem ci gitlab --version v2.0.0Installing the binary and running the gate are the same everywhere — plain shell. The only real difference is how each platform ingests the report.
| Platform | Format | Ingestion |
|---|---|---|
| GitHub | SARIF | Code Scanning (upload-sarif) |
| Azure DevOps | SARIF | the CodeAnalysisLogs artifact, read by the SARIF SAST Scans Tab extension |
| Jenkins | SARIF | the Warnings Next Generation plugin's SARIF parser |
| GitLab | its own schema | artifacts:reports:dependency_scanning |
This is the one that catches people out. GitLab defines its own Dependency Scanning report format and ignores SARIF entirely — a job that publishes SARIF to GitLab produces a green pipeline with an empty security widget, which is the worst possible failure mode: it looks like nothing was found.
So postmortem emits GitLab's native format:
postmortem audit . --online --vulns --gitlab -o gl-dependency-scanning-report.json--gitlab is available on both audit and tree. The generated template uses
audit, because it does both jobs in one pass: it writes the report the
merge-request widget reads, and its exit code is the gate.
Findings land as vulnerabilities[], keyed by advisory + package + version so
GitLab tracks a finding across pipelines instead of re-raising it each run.
Identifiers are typed (cve, ghsa, rustsec, osv) so GitLab can
deduplicate against other scanners.
The upgrade target from fix is reported as the finding's solution.
Not as remediations — the schema requires that block to carry a diff, an
actual patch GitLab can apply from the merge request. postmortem deliberately
never writes to a manifest, so it has no patch to offer, and emitting the field
without one would fail validation and take the whole report down. solution is
free text and can hold the advice honestly.
A graph postmortem could not fully resolve is reported as scan.status: "failure" rather than a clean pass — the same rule the
diagnostics follow everywhere else: unknown must never
read as clean.
A tripped gate exits non-zero, and on every one of these platforms the default is to abandon the job at that point — including the step that publishes the report. That is exactly backwards: the run you most need the findings from is the one that failed.
Every generated template forces the publish to happen anyway:
| Platform | How |
|---|---|
| GitHub | if: always() |
| GitLab | artifacts.when: always |
| Azure | condition: succeededOrFailed() |
| Jenkins | post { always { … } } |
If you write your own pipeline instead of generating one, this is the thing to remember.
--online reads $GITHUB_TOKEN for the repo-reputation lookups. Without one
you will hit the unauthenticated GitHub API rate limit on any real dependency
set. Each template wires it up in that platform's idiom — a masked CI/CD
variable on GitLab, a secret pipeline variable on Azure, a credential binding on
Jenkins, and the built-in secrets.GITHUB_TOKEN on GitHub.
The templates are covered by tests asserting their content: that they parse as
YAML, that they pin a real version, that each declares its report where its
platform looks for it, that the publish survives a failed gate, and that the
install snippet stays in sync with action.yml.
They are not executed against a live GitLab, Azure or Jenkins instance the
way the GitHub Action is dogfooded by self-scan.yml. Treat them as a
well-checked starting point, not as a pipeline verified end-to-end.
Every template ships the same starting thresholds:
--max-high 0 --fail-on-vuln high
See CI gate for the full set, and Allowlist for suppressing a finding you have decided to accept.