# Run Lockpick in CI

Check your site with a Pulse when you ship a release, and fail the build when serious findings are open.

The CLI runs in any CI that has Node.js 20.9 or later. A Pulse in CI uses one Pulse scan from your monthly allowance each time, the same as starting it in Lockpick, so run it when you ship rather than on every push.

## Write the workflow

From your repository, with the CLI signed in:

```bash title="Terminal"
lockpick ci init <site>
```

It writes `.github/workflows/lockpick.yml`. The workflow runs when you publish a release and when you start it from the Actions tab. It runs a Pulse on the site, waits for the result, and fails when open findings are `high` or more severe. It pins the CLI version it was written with.

* `--fail-on critical`, `high`, `medium` or `low` sets the line.
* `--dry-run` prints the workflow without writing it.
* `--file <path>` writes it somewhere else, and `--force` replaces an existing file.

If the CLI is signed in to a local address, `ci init` warns you: GitHub's runners can only reach a public Lockpick address. Pass `--host` with that address.

## Add the key

The workflow reads its key from the repository secret `LOCKPICK_KEY`. Use a key allowed to start Pulse scans.

```bash title="Terminal"
gh secret set LOCKPICK_KEY
```

> **Careful**
>
> A key can do what you allowed when you signed in. Keep it in your CI's
> secret store, never in your repository, and revoke it in Lockpick under
> **Add to your AI**, on the **CLI and keys** tab, when you no longer need it.

## Fail on findings anywhere

`--fail-on` works on any command that ends with a finished scan: `lockpick pulse`, `lockpick recheck`, `lockpick watch`, `lockpick deep start` and `lockpick findings`. `lockpick ci check <run-id>` applies it to a scan that already finished, without starting one or using your allowance, and can also fail on its age (`--max-age-hours`) or coverage (`--min-coverage`). When open findings reach the line, the command exits with code 8, so any CI can stop the build:

```bash title="Terminal"
lockpick pulse <site> --fail-on high --timeout 900
```

In CI the CLI prints one line each time a scan's state changes instead of a live progress line, and `--json` prints only the result. Set `FORCE_COLOR=1` for colour in a log that shows it.

## CLI and release-scan script exit codes

The CLI and the standalone [release-scan script](/docs/protect/release-scans) use different exit contracts. Check which one your job runs.

| Result                                 | `lockpick` CLI                                     | Standalone release-scan script |
| -------------------------------------- | -------------------------------------------------- | ------------------------------ |
| Completed within the finding threshold | 0                                                  | 0                              |
| Open findings reached the threshold    | 8                                                  | 1                              |
| Scan failed or another error occurred  | See [CLI exit codes](/docs/cli/install#exit-codes) | 1                              |

The release-scan script uses a site-scoped CI key (`LOCKPICK_CI_KEY`); the CLI uses `LOCKPICK_KEY` and its approved permissions.