GitHub Actions
Two lines. The action downloads a pinned release, verifiesSHA256SUMS with cosign against the release workflow’s identity, and runs the gate:
fetch-depth: 0sogit:origin/main:openapi.yamlcan be read from object storage. No checkout of the base branch is needed.- The action sets
safe.directory, runsspec-diffwith--format githubactionsso every finding lands inline on the diff, and always writes the JSON report. Inputsfail-on(defaultERR),format,handoffandversion; outputsfindings,reportandexit-code. Source and the verification script: Pikopod/spec-diff-action. pr commentposts one marker-tagged comment and updates it in place on re-runs. Platform, repository, PR number and head SHA are detected from the Actions environment. The token comes fromGITHUB_TOKENorGH_TOKEN, never from a flag. The binary is on thePATHafter the action ran.
pr comment degrades: it writes the report to the job summary, or to stdout, and exits 0 with a note on stderr.
GitLab CI
pr comment detects GitLab from GITLAB_CI, reads the project and merge request IID from the CI variables, and needs GITLAB_TOKEN with api scope. Job tokens usually cannot post merge request notes.
Container image
The image isFROM scratch and runs as an unprivileged user:
Exit codes in CI
Treat1 and 2 differently. 1 means the provider changed something that breaks you. 2 means the tool could not run: a document did not parse, a $ref was refused, the checkout was unreadable. A gate that collapses them teaches people to ignore both. See Exit codes.
Gating on recorded traffic too
Once an agent has been observing a provider, add the offline replay gate to the same job. It needs thedata_dir (or a copy of it) and no network:
Running the sandbox in CI
Scenario runs need no server:pikopod scenario check builds its own engine in-process. The second action in the same repository imports the spec and runs the scenarios:
scenario check is the gate: it exits 1 on a failed step and 2 when a step could not run, and --format githubactions puts each failure on the pack’s line in the pull request. The second run writes the same result as JUnit for whatever reads test reports in your pipeline; runs are deterministic under a pinned --seed, so the two agree. Pin --seed so transcripts are byte-identical between runs. Packs are looked up in ./scenarios first, then in <data_dir>/scenarios, so a committed scenarios/ directory is the regression suite. See Reports a build can be gated on.