Continuous Integration
Gate your CI builds on squirrelscan audits: GitHub Actions, GitLab, and generic runners
Run squirrelscan in CI to catch audit problems (performance, security,
content, and more) before they ship. Set thresholds with --fail-on and the
audit exits non-zero when one trips, so your pipeline fails like any other
check.
--fail-on compares each run against the thresholds you set, not against an
earlier audit. There is no baseline gating: the build does not fail because a
score dropped since the last run, only because it is below your threshold. To
see what changed between two audits, use
squirrel report --regression-since, which prints the
comparison but does not set a failing exit code.
Exit codes
squirrel audit uses distinct exit codes so CI can tell a tripped threshold
apart from a broken run:
| Code | Meaning |
|---|---|
0 | Audit ran and every --fail-on threshold passed |
2 | Audit ran but a --fail-on threshold tripped |
1 | Operational error (bad flags, a crash, a site that answered with an error, etc.) |
3 | The audited page was blocked (a WAF or bot manager, or a bare 403 or 429), so nothing was audited. See blocked by a WAF or bot manager |
5 | The start URL could not be reached (DNS, timeout, connection or TLS failure), so nothing was audited. See unreachable start URLs |
Gate your build with --fail-on; quote each expression, since
shells treat bare </> as redirection:
squirrel audit https://example.com --fail-on 'score<90' --fail-on 'severity>=error'GitHub Actions
The quickest path is the official squirrelscan audit action, available on the GitHub Marketplace:
name: Audit
on: [pull_request]
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: squirrelscan/audit-action@v1
with:
url: https://staging.example.com
fail-on: "score<90,severity>=error"
token: ${{ secrets.SQUIRRELSCAN_API_KEY }} # optional
github-token: ${{ secrets.GITHUB_TOKEN }} # optional PR commentPrefer no action? Install the CLI directly:
- run: |
curl -fsSL --connect-timeout 10 --max-time 120 https://install.squirrelscan.com | bash
echo "$HOME/.local/bin" >> "$GITHUB_PATH" # resolve squirrel in later steps (self-hosted)
- run: squirrel audit https://staging.example.com --fail-on 'score<90'
env:
SQUIRRELSCAN_API_KEY: ${{ secrets.SQUIRRELSCAN_API_KEY }}GitLab CI
audit:
image: ubuntu:latest
script:
- apt-get update && apt-get install -y curl
- curl -fsSL --connect-timeout 10 --max-time 120 https://install.squirrelscan.com | bash
- export PATH="$HOME/.local/bin:$PATH"
- squirrel audit "$AUDIT_URL" --fail-on 'score<90,severity>=error'
variables:
AUDIT_URL: "https://staging.example.com"
SQUIRRELSCAN_API_KEY: $SQUIRRELSCAN_API_KEY # optional, set in CI/CD variablesGeneric runners
Any runner that can run a shell works:
curl -fsSL --connect-timeout 10 --max-time 120 https://install.squirrelscan.com | bash
export PATH="$HOME/.local/bin:$PATH"
# JSON report on stdout stays clean — the gate summary goes to stderr.
squirrel audit https://example.com \
--format json --output report.json \
--fail-on 'score<90,score:perf<80'The command exits 2 if a threshold trips, so the script stops there.
Authentication
Cloud features require a token. The recommended approach is an API
key (mint one with squirrel keys create) stored as a CI secret
and exposed as SQUIRRELSCAN_API_KEY:
- GitHub Actions: repo/org secret →
env: SQUIRRELSCAN_API_KEY: ${{ secrets.SQUIRRELSCAN_API_KEY }} - GitLab: masked CI/CD variable
SQUIRRELSCAN_API_KEY - Other: export
SQUIRRELSCAN_API_KEYin the job environment
When SQUIRRELSCAN_API_KEY is set, the CLI uses it automatically (the older
SQUIRREL_API_TOKEN name still works as a back-compat alias). Without either,
the audit still runs deterministically; it just skips cloud enrichment.
What an API-key audit costs
An audit signed in with an org API key is not registered as a cloud run, so it
is billed differently from a squirrel auth login audit:
- No audit or page charge. It pays no 50-credit audit base and no per-page charge.
- Links checked on the runner, free. Its external links are always checked from the CI machine, never by the cloud’s link checker, and cost nothing. Expect more false positives from sites that block automated traffic.
- Cloud renders are billed. A page it renders in the cloud is billed as a
standalone render, 2 credits per page. An HTTP-only audit (
--http) renders nothing.
This is deliberate. A CI audit gates a build, and the full billed audit is a
signed-in squirrel audit or a cloud audit. See
Credits and pricing.