Skip to main content
The Selo release gate ships as a composite GitHub Action. It runs the same selo CLI as your terminal, in three modes: a free preflight, a paid test, and an offline verify of a signed verdict. A FAIL, an INCONCLUSIVE, an unconfirmed payment, an expired authorization or a missing report fails the job, and the promote job never runs.

Reference the action

The action lives in the Selo repository at .github/actions/release-gate:
Pin the action to a full commit SHA of the Selo repository that you have reviewed, instead of @main. The action installs the CLI from the same checkout, so the SHA pins the code that handles your wallet.
On every run the action sets up Node 24, installs the CLI from its own checkout with npx --yes pnpm@10.33.0 install --frozen-lockfile --filter "@selo/cli...", and runs packages/cli/bin/selo.js. Relative paths such as selo/contract.json resolve from your workspace.

The three modes

Free. Needs no wallet and spends nothing. It checks the authorization, your endpoint’s 402, the network, the asset and the price.

Inputs

Every input except mode maps to the CLI flag of the same name; approve-mainnet: "true" adds --approve-mainnet. See GitHub Action reference and selo test.

Set up a gated release

1

Create a dedicated payer wallet

An Algorand account opted in to USDC (ASA 31566704), funded with only what a few release tests cost. A release test costs Selo’s price, 1.00 USDC. Selo pays your endpoint’s own price from its wallet.
2

Authorize the staging route

Run selo auth create for the exact staging URL and method, serve the printed line at https://<staging origin>/.well-known/selo-verification.txt, then run selo auth verify. An authorization lasts 24 hours after verification, so authorize again before a release window. See Authorize your endpoint.
3

Add the configuration

In Settings → Environments, create selo-paid-release, add required reviewers, limit it to the main branch, and add the secret there.
4

Commit the contract, the body and the keys

The promote job verifies the signed attestation against the committed keys, so it promotes only a PASS that Selo signed for this commit, URL and method.
5

Add the workflow

Copy the workflow below and replace the build and deploy scripts with your own.

A complete workflow

This is examples/github-actions/release-gate.yml from the Selo repository. ./scripts/build-and-test.sh and ./scripts/deploy.sh stand for your own build and deploy steps.
.github/workflows/release-gate.yml
What each job does: The job summary of paid-gate shows the verdict, each check, the job id and both transaction ids, because the CLI appends a Markdown table to GITHUB_STEP_SUMMARY.

How the wallet stays safe

paid-gate runs only on a push to main or a manual dispatch, inside the protected selo-paid-release environment, so it waits for a reviewer. The mnemonic is an environment secret, available only to jobs in that environment.
Pull requests, including those from forks, never reach the paid job. Do not add pull_request_target to this workflow: it runs with access to your repository’s secrets on behalf of pull request events, and the paid job must never run for code you have not reviewed.
The action never interpolates an input into its shell script. Every input is passed as an environment variable (SELO_MODE, SELO_URL, SELO_RELEASE and so on), and the script reads those variables, so a value that contains shell syntax is treated as data, not as code.
max-usdc caps what one run may pay Selo. The CLI refuses a 402 on another network, a different payee, or a Mainnet payment without approve-mainnet, all before signing. Selo, in turn, spends at most 0.50 USDC on your endpoint per job.
cancel-in-progress: false keeps a newer push from cancelling a paid run in flight. The CLI never retries a payment. If the outcome is unconfirmed it exits 2 with a warning. Do not re-run the job blindly: the run state lives in the runner’s workspace, which a re-run does not keep, so a re-run starts a new paid test. Check the payer account for the expected transaction id printed in the log first. See Recover an interrupted run.
Logs, the job summary and the uploaded selo-gate.json and selo-attestation.json contain no mnemonic, no signed payment and no private report token. Do not upload the .selo/ directory: it holds the private report link.

Proof: a blocked and a promoted release

The Selo repository runs the Release gate demo workflow (.github/workflows/release-gate-demo.yml). You choose a release of the demo merchant, broken-v1 or fixed-v2, and it verifies the signed Mainnet attestation of that release against the pinned key before a promote job may run. Its two jobs:
.github/workflows/release-gate-demo.yml
On 26 October 2026 it ran once for each release: The attestations it verified come from the paid Mainnet runs described in Proof on Algorand Mainnet.

Troubleshooting

Next

Verify a signed verdict

What verify mode checks, and how to check it yourself.

GitHub Action reference

Every input and output in one place.