Skip to content
Docs · Gate deploys in CI

Guides

Gate deploys in CI

Fail a GitHub Actions job on a held release, make a deploy wait for the verdict, and send findings to GitHub's Security tab.

Every push is already checked through the GitHub App. These steps make your CI act on the verdict. They use the Stableship CLI, which needs Node 22 or newer.

Make a token for CI

In Stableship open Settings, then Connections, open API tokens and connected apps, and choose Create token. Give each job its own token, with only what it needs:

  • Waiting for a verdict or reading findings: Read findings and rules.
  • Starting a check: also Start checks and verify fixes.

Add it to the GitHub repository as a secret named STABLESHIP_TOKEN.

Hold a deploy until Stableship decides

For hosts that deploy from GitHub Actions or wait for CI (Railway, Fly and others), add a job that waits for Stableship's decision on the commit, and make the deploy depend on it:

jobs:  gate:    runs-on: ubuntu-latest    timeout-minutes: 115    steps:      - uses: actions/setup-node@v4        with: { node-version: 22 }      - run: npx --yes @stableship/cli@1 wait --sha "$GITHUB_SHA"        env:          STABLESHIP_TOKEN: ${{ secrets.STABLESHIP_TOKEN }}  deploy:    needs: gate    # your deploy

On Railway, you can instead turn on Wait for CI for the service, so Railway deploys only after the workflow's checks pass.

Stableship saysThe jobThe deploy
Passed, warned, skipped, or a person shipped it anywaySucceedsGoes out
A problem blocks the releaseFailsWaits: fix it, or ship anyway in Stableship and run the job again
Stableship could not finish, and the change is low-riskSucceedsGoes out
Stableship could not finish, and the change touches sign-in, data or paymentsFailsWaits for a person
No check started for the commit within 20 minutesSucceeds, with a warningGoes out

While it waits, the Stableship check on the commit shows what is being tested and roughly how long is left.

Fail a job on a held release

To start a check from CI and wait for its verdict:

- name: Stableship  run: npx --yes @stableship/cli@1 check --ref "$GITHUB_SHA" --wait --timeout 900  env:    STABLESHIP_TOKEN: ${{ secrets.STABLESHIP_TOKEN }}
Exit codeMeaning
0Passed, passed with warnings, skipped or shipped anyway. Also 0 when Stableship itself failed: the CLI prints a warning.
1Held: a problem blocks the release.
2Could not run: a usage error, a missing or rejected token, an API error, or the wait ran past --timeout.

To fail the step only on a held release, not when it could not run, add || [ $? -eq 2 ] after the command.

The CLI finds your app from the repository's origin. Pass --project <id> (from stableship status) to choose one.

Findings in GitHub's Security tab

- run: npx --yes @stableship/cli@1 findings --sarif > stableship.sarif  env:    STABLESHIP_TOKEN: ${{ secrets.STABLESHIP_TOKEN }}- uses: github/codeql-action/upload-sarif@v3  with: { sarif_file: stableship.sarif, category: stableship }

The job needs permissions: security-events: write.

A pre-push hook

stableship hook install adds a Git pre-push hook: a push to your default branch prints the open blocking problems first. With --strict it refuses the push while something blocks, unless the commit has a Gate: trailer. The hook never stops a push because Stableship could not be reached. stableship hook uninstall removes it.

For your coding agent: this page as Markdown