Skip to content
Canopy is in pre-release. These docs describe the product at its public launch — commands, tool names, and integration examples reflect what you'll see once binaries ship. Join the waitlist →

Use Canopy in CI

Canopy automatically detects CI environments and activates in ephemeral mode — no seat is reserved, and the activation is gone when the runner terminates.

You need one repository secret: CANOPY_LICENSE_KEY.

The check itself is one command. canopy ci indexes the repo, runs every health check (built-in plus any plugins in .canopy/plugins/), and emits findings as annotations — --format auto (the default) detects GitHub Actions, GitLab, and Azure Pipelines from the environment, and --format sarif emits SARIF 2.1.0 for GitHub Code Scanning upload. Pass --fail-on-p0 to fail the build when a P0 finding is present, and --changed-only to restrict findings to files touched by the current PR. CI mode requires a Pro tier license or higher.

When Canopy detects a CI environment (CI=true plus a vendor-specific variable), it skips machine fingerprint binding entirely. Your CI pipelines can run on any number of parallel runners without burning through seats. All ephemeral usage is logged in the admin portal for your records.

.github/workflows/canopy-check.yml
name: Canopy CI check
on:
push:
branches: [main]
pull_request:
jobs:
canopy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Canopy
run: |
# CANOPY_DOWNLOAD_URL is provided to license holders — see /docs/getting-started/install-canopy/.
curl -fsSL "$CANOPY_DOWNLOAD_URL/canopy-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m)" \
-o /usr/local/bin/canopy
chmod +x /usr/local/bin/canopy
- name: Activate license (ephemeral — no seat consumed)
run: canopy activate "$CANOPY_LICENSE_KEY"
env:
CANOPY_LICENSE_KEY: ${{ secrets.CANOPY_LICENSE_KEY }}
- name: Run Canopy CI check
run: canopy ci --fail-on-p0

Canopy detects GITHUB_ACTIONS=true automatically — findings appear as PR annotations with no extra configuration.

.gitlab-ci.yml
canopy-check:
image: ubuntu:24.04
variables:
# CANOPY_LICENSE_KEY is a protected CI/CD variable set in Settings → CI/CD → Variables
CANOPY_LICENSE_KEY: $CANOPY_LICENSE_KEY
script:
- curl -fsSL "$CANOPY_DOWNLOAD_URL/canopy-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m)" -o /usr/local/bin/canopy
- chmod +x /usr/local/bin/canopy
- canopy activate "$CANOPY_LICENSE_KEY"
- canopy ci --fail-on-p0
.circleci/config.yml
version: 2.1
jobs:
canopy-check:
docker:
- image: cimg/base:2024.01
steps:
- checkout
- run:
name: Install and activate Canopy
command: |
sudo curl -fsSL "$CANOPY_DOWNLOAD_URL/canopy-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m)" \
-o /usr/local/bin/canopy
sudo chmod +x /usr/local/bin/canopy
- run:
name: Run Canopy CI check
command: |
canopy activate "$CANOPY_LICENSE_KEY"
canopy ci --fail-on-p0

Store CANOPY_LICENSE_KEY in CircleCI’s Project Settings → Environment Variables.

pipeline.yml
steps:
- label: "Canopy CI check"
command:
- sudo curl -fsSL "$CANOPY_DOWNLOAD_URL/canopy-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m)" -o /usr/local/bin/canopy
- sudo chmod +x /usr/local/bin/canopy
- canopy activate "$$CANOPY_LICENSE_KEY"
- canopy ci --fail-on-p0
env:
CANOPY_LICENSE_KEY: # Set in Buildkite's environment hooks or Pipeline secrets
VariableEffect
CANOPY_EPHEMERAL=1Force ephemeral mode (useful for testing)
CANOPY_EPHEMERAL=0Force persistent mode even in CI (seat IS consumed)

Setting CANOPY_EPHEMERAL=0 is the escape hatch if you run a persistent long-lived CI agent that should own a dedicated seat.