CI checks
Block unreviewed permission and coverage drift in GitHub Actions.
CI should reproduce the same named scenarios and compare them with the
committed granttrace.lock.json.
GitHub Actions example
name: GrantTrace
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
jobs:
permission-contract:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020
with:
node-version: 22
- run: npm ci
- run: >-
npx granttrace record --no-review issue-triage --
npm test -- issue-triage
- run: >-
npx granttrace record --no-review release-read --
npm test -- release-read
- run: npx granttrace check --github-step-summaryThe example pins reviewed third-party actions to full commit SHAs. Re-review those revisions deliberately when upgrading them. It uses npm for portability; keep your project's existing package manager and lockfile if you use pnpm or Yarn instead.
Never accept in CI
--no-review is important when CI records multiple scenarios: it prevents the
first recording from comparing an intentionally incomplete aggregate against
the committed contract. Use it only when a final granttrace check is
guaranteed.
Without --no-review, record detects the noninteractive environment, prints
the diff, never prompts, and never accepts it. check --accept is refused when
CI is enabled or GITHUB_ACTIONS=true, before the contract or local operation
state can be written. The same guard refuses frontier select and manual-keep
mutation; their read-only list operations remain available. Exit 6 from the
final check is the intended signal that a human must review permission or
coverage drift locally and commit the resulting lockfile deliberately.
--github-step-summary is explicit opt-in. It appends a safe Markdown report to
the absolute runner-provided GITHUB_STEP_SUMMARY file while preserving the
normal text and exit code. Container jobs may mount that file outside
RUNNER_TEMP; GrantTrace validates the target itself. For machine processing
instead, use --format json; structured output always goes to stdout,
including when the check exits 6 or 7.
Structured reports omit free-form reasons, scenario names, concrete URLs and paths, errors, and credentials. Permission identifiers remain visible because they are the machine-readable contract, including user-supplied manual-keep keys. Do not encode identities or secrets in a permission name.
This also applies when a previously selected permission-frontier candidate is no longer valid. CI reports the proposed deterministic fallback as a normal contract diff and never persists a replacement selection.
Exit 7 means the evidence is unknown, unsupported, malformed, or
contradictory. Fix the scenario or contribute an official-docs-backed catalog
change; do not guess a permission and force the pipeline green.
Keep live proof separate
The deterministic record-and-check workflow can run without GitHub App broker credentials when your scenarios use controlled responses. Optional live proof belongs in a trusted, explicitly triggered workflow against a disposable fixture. Never expose fixture credentials to untrusted pull requests.
See CLI reference for all exit codes.