CI Integration
pydepgate integrates with CI pipelines in three ways: direct invocation via the CLI, the Docker image for containerized pipelines, and pre-commit hooks for commit-time scanning. This page covers all three.
Exit code contract
All three integration paths depend on pydepgate’s exit codes:
| Code | Meaning |
|---|---|
0 | Clean. No findings at or above --min-severity. |
1 | Findings present, none HIGH or CRITICAL. |
2 | At least one HIGH or CRITICAL finding. |
3 | Tool error. Scan could not complete. |
The standard CI pattern is to fail the build on exit code 2. Exit code 1 represents findings below the blocking threshold and does not fail the build unless you use --strict-exit, which treats any finding as blocking regardless of severity.
Direct CLI invocation
GitHub Actions
name: pydepgate scan
on: [push, pull_request]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Build wheel
run: |
pip install build
python -m build --wheel
- name: Install pydepgate
run: pip install pydepgate
- name: Scan wheel
run: pydepgate scan --ci --min-severity high dist/*.whl
--ci is a CI-output mode flag, not a severity filter. When set, it forces --format json if format is not already set, and forces --color never if color is currently auto. It does not change --min-severity. Pair it with --min-severity high (as above) when you want CI to block only on HIGH and CRITICAL findings.
To scan an installed package instead of a wheel:
- name: Install target package
run: pip install some-package
- name: Scan installed package
run: pydepgate scan --ci --min-severity high some-package
GitLab CI
stages:
- build
- scan
build-wheel:
stage: build
image: python:3.12-slim
script:
- pip install build
- python -m build --wheel
artifacts:
paths:
- dist/
scan-wheel:
stage: scan
image: python:3.12-slim
script:
- pip install pydepgate
- pydepgate scan --ci --min-severity high dist/*.whl
dependencies:
- build-wheel
Docker image
The official Docker image is at ghcr.io/nuclear-treestump/pydepgate. It is a multi-stage Alpine build under 50 MB, runs as non-root (uid 1000), and is published for linux/amd64 and linux/arm64.
docker pull ghcr.io/nuclear-treestump/pydepgate:latest
docker pull ghcr.io/nuclear-treestump/pydepgate:0.4.0
docker pull ghcr.io/nuclear-treestump/pydepgate:0.4
Scan a wheel from the host filesystem:
docker run --rm \
-v "$(pwd):/scan" \
ghcr.io/nuclear-treestump/pydepgate:latest \
scan --ci --min-severity high some-package.whl
The container’s working directory is /scan, so paths are resolved against the bind-mounted directory.
GitHub Actions with Docker
- name: Scan wheel with pydepgate
run: |
docker run --rm \
-v "$/dist:/scan" \
ghcr.io/nuclear-treestump/pydepgate:0.4 \
scan --ci --min-severity high /scan/*.whl
Or using the container directive:
- name: Scan wheel with pydepgate
uses: docker://ghcr.io/nuclear-treestump/pydepgate:0.4
with:
args: scan --ci --min-severity high dist/*.whl
GitLab CI with Docker
scan-wheel:
stage: scan
image:
name: ghcr.io/nuclear-treestump/pydepgate:0.4
entrypoint: [""]
script:
- pydepgate scan --ci --min-severity high dist/*.whl
dependencies:
- build-wheel
The entrypoint: [""] line overrides the image’s pydepgate entrypoint so GitLab can run its own shell wrapper before the script section executes.
Multi-stage Dockerfile
For projects that already containerize their build, reference the pydepgate image as a build stage:
FROM python:3.12-slim AS build
WORKDIR /src
COPY . .
RUN pip install build && python -m build --wheel
FROM ghcr.io/nuclear-treestump/pydepgate:0.4 AS scan
COPY --from=build /src/dist/*.whl /scan/
RUN pydepgate scan --ci --min-severity high /scan/*.whl
The pydepgate stage fails the build if blocking findings are present, stopping the pipeline before any downstream stage receives the artifact.
Environment variables in Docker
All PYDEPGATE_* variables work inside the container:
docker run --rm \
-v "$(pwd):/scan" \
-e PYDEPGATE_PEEK=1 \
-e PYDEPGATE_MIN_SEVERITY=high \
-e PYDEPGATE_FORMAT=json \
ghcr.io/nuclear-treestump/pydepgate:latest \
scan some-package.whl
pre-commit hooks
pydepgate ships two pre-commit hook IDs that integrate with pre-commit.
Hook IDs
pydepgate runs pydepgate scan --single against every staged .py file. It defaults to --min-severity high so commits are not blocked by informational findings. The threshold is tunable via args.
pydepgate-pth runs the same scanner against staged .pth files with no severity filter. .pth files have no legitimate use case for any pattern pydepgate detects, so even an INFO finding there warrants a human look.
Adding to your project
In your project’s .pre-commit-config.yaml:
repos:
- repo: https://github.com/nuclear-treestump/pydepgate
rev: v0.4.0
hooks:
- id: pydepgate
- id: pydepgate-pth
Install and run an initial scan:
pre-commit install
pre-commit run --all-files
Tuning
Lower the threshold to catch MEDIUM and above:
- id: pydepgate
args: [--min-severity, medium, --no-color]
Enable payload peeking during the hook run:
- id: pydepgate
args: [--min-severity, high, --no-color, --peek]
Exclude generated or vendored directories:
- id: pydepgate
exclude: ^(generated/|vendor/|third_party/)
pre-commit in CI
The hook configuration also works under pre-commit run --all-files in CI:
GitHub Actions:
- uses: pre-commit/action@v3.0.1
GitLab CI:
pre-commit:
image: python:3.12-slim
script:
- pip install pre-commit
- pre-commit run --all-files
Recommended thresholds
| Context | Recommended flag | Rationale |
|---|---|---|
| CI artifact scan | --ci --min-severity high | JSON output, no color, blocking only on HIGH/CRITICAL |
pre-commit .py hook | --min-severity high | Avoids blocking commits on density informational signals |
pre-commit .pth hook | (no filter) | All findings on .pth files warrant review |
| Interactive investigation | --min-severity low or no filter | Full signal visibility |
| Strict CI (zero tolerance) | --strict-exit | Any finding blocks the build |
JSON output for downstream processing
To consume pydepgate output in a downstream step rather than failing the pipeline directly:
pydepgate scan --format json dist/*.whl > scan-results.json || true
The || true prevents the shell from stopping on a non-zero exit. Parse scan-results.json to apply custom logic. Exit code is still set correctly; use $? if you need it after the redirect.
See Output Formats for the JSON schema.