CLI dependency risk scanner for Python projects.
Project description
snake-guard
snake-guard is a CLI dependency risk scanner for Python projects. It helps
developers detect vulnerable, suspicious, or risky packages before they become
part of a project or CI pipeline.
It aggregates known vulnerability scanners and package-risk checks, then unifies their results into one easy-to-use command-line interface. It builds an inventory from common Python manifests and reports vulnerabilities, suspicious package signals, provenance issues, and safe remediation guidance in one place.
Table of Contents
Features
- Full project scans for known vulnerabilities using multiple scanners and package-risk checks.
- Isolated package sandboxing to probe, import, or run commands before trusting a dependency in your local environment.
- Automatic dependency fix plans for vulnerable direct dependencies, with conservative project edits where safe.
- Safer install wrapper that scans before installation, sandboxes risky packages, and verifies the project after install.
- Per-engine pass or fail status so missing tools, scanner errors, and findings are visible instead of hidden behind a clean-looking result.
Installation
Install snake-guard from PyPI:
pip install snake-guard
For local development, install this repository in editable mode:
python -m pip install -e .
Sandbox commands use a container runtime. Docker is the default runtime:
docker --version
Other Docker-compatible runtimes may work when passed with --runtime, but the
sandbox command arguments are Docker-style today.
Usage
Scan the current project:
snake-guard scan
Emit JSON for scripts or CI:
snake-guard scan --json
Use verify mode as a policy gate. It exits non-zero when high-risk findings are present:
snake-guard scan --verify
Preview remediation without editing files:
snake-guard fix --plan
Apply available fixes:
snake-guard fix
Run against an example project:
snake-guard scan --root examples/pip_project
snake-guard scan --root examples/poetry_project
snake-guard scan --root examples/uv_project
Use --no-cache when you want a fresh scan, fix, or install run without reusing
cached scan results:
snake-guard scan --no-cache
snake-guard fix --no-cache
snake-guard install --no-cache
Fix Plans
snake-guard fix separates real fixes from recommendations:
- Fix actions are generated for vulnerable packages when a safe target version is known.
- Pinning recommendations are shown for direct dependencies that use ranges or compatible-release specifiers.
- Engine status is shown next to the plan, so a clean plan does not hide a failed scanner.
Example:
snake-guard fix --plan
If no actions are required and every engine passed, the output says the project is good to go. If no actions are generated but an engine failed, the output makes that explicit so the result is not treated as clean.
Cache
snake-guard stores scan results in a small JSON cache so repeated scans of the
same dependency set can skip engines that already finished.
The cache lives under:
~/.cache/snake-guard/scan-cache.json
If XDG_CACHE_HOME is set, the cache file is stored there instead.
Useful cache commands and flags:
snake-guard cache clear
snake-guard scan --no-cache
snake-guard fix --no-cache
snake-guard install --no-cache
cache cleardeletes the persisted scan cache file.--no-cachebypasses the scan cache for a single run.installandfixpass the cache setting through to their internal scans, so the full workflow can also run fresh when needed.
Install Wrapper
The installation wrapper runs a pre-scan, optionally sandboxes risky packages, and then delegates to the real installer.
snake-guard install --root examples/pip_project
snake-guard install -r requirements.txt
snake-guard install --dry-run
snake-guard install --manager poetry -- --with dev
snake-guard install --manager uv -- --frozen
snake-guard install --package requests --package flask
Use --dry-run to see what would happen without running sandbox checks or the
underlying installer.
Sandbox
Sandbox mode is useful when you want to inspect a package before installing it in your real environment. By default, direct sandbox commands disable networking inside the container.
snake-guard sandbox probe Django --force
snake-guard sandbox exec Django --force -- python -c "import django; print(django.get_version())"
snake-guard sandbox shell Django --force
Available sandbox modes:
probe: install a package and attempt a basic import in an isolated container.exec: install a package and run a command inside the sandbox.shell: install a package and open an interactive shell inside the sandbox.
Useful sandbox options:
--allow-networkenables container networking during package installation.--no-pull-imagerequires the sandbox image to already exist locally.--imagechanges the Python container image.--runtimechanges the container runtime executable.--docker-argpasses extra Docker-style arguments to the sandbox run.
JSON Output
Most commands support --json for automation:
snake-guard scan --json
snake-guard fix --plan --json
snake-guard sandbox probe requests --force --json
The JSON report includes the dependency inventory, package findings, engine statuses, fix actions, and recommendations where applicable.
Scheduled CI Scans
Dependency risk changes over time. A package that looked clean during install can
receive a new advisory or suspicious signal later. You can run snake-guard on a
schedule in CI to keep checking the project.
This repository includes a reusable GitHub Actions example at
.github/workflows/snake-guard.yml:
Supported Package Managers
snake-guard currently reads these dependency sources:
requirements.txtpyproject.tomlpoetry.lockuv.lock
The installation wrapper can detect or run these package managers:
pippoetryuv
snake-guard fix can update vulnerable direct dependencies in requirements.txt or
pyproject.toml when a safe replacement is known. For Poetry and uv projects,
it rewrites the direct dependency specifier first, then runs poetry lock or
uv lock so the checked-in lock file matches the manifest. Use
snake-guard fix --plan to preview the manifest diff and the lock refresh
command before editing files.
Built With
The core CLI is written in Python and uses:
Typerfor the command-line interface.packagingfor version and requirement handling.tomlion older Python versions for TOML parsing.
Under the hood, scans use these engines:
pip-auditfor Python vulnerability advisories.guarddogfor PyPI malware and suspicious-package heuristics.- Built-in provenance checks against PyPI JSON and Integrity APIs.
pip-audit and guarddog are installed with snake-guard.
Contributing
Contributions are welcome, especially around parser coverage, remediation safety, test fixtures, and clearer reporting. Keep changes focused and include an example or test fixture when behavior changes.
Before opening a change, run at least:
python -m compileall -q snake_guard
If your change depends on scan engines, also test real pip-audit and guarddog
runs so engine status and failure handling stay accurate.
License
This project is licensed under the Apache License 2.0. See LICENSE for the
full license text.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file snake_guard-0.1.0.tar.gz.
File metadata
- Download URL: snake_guard-0.1.0.tar.gz
- Upload date:
- Size: 65.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
877a9f509c0cf964d0304280c6aefa9624ea1e643fea334e9759d74d5c9fd71e
|
|
| MD5 |
cf9d30a9390a1f04d02db87639400713
|
|
| BLAKE2b-256 |
66023486fbbf7f44a8bf29d9887fcbddffdf8d3ca611f844c8a56e0495433908
|
Provenance
The following attestation bundles were made for snake_guard-0.1.0.tar.gz:
Publisher:
release.yml on Artemooon/snake-guard
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
snake_guard-0.1.0.tar.gz -
Subject digest:
877a9f509c0cf964d0304280c6aefa9624ea1e643fea334e9759d74d5c9fd71e - Sigstore transparency entry: 1340615616
- Sigstore integration time:
-
Permalink:
Artemooon/snake-guard@57eb8704baa4330c4dac2eb0d833c8f01dfed749 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/Artemooon
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@57eb8704baa4330c4dac2eb0d833c8f01dfed749 -
Trigger Event:
push
-
Statement type:
File details
Details for the file snake_guard-0.1.0-py3-none-any.whl.
File metadata
- Download URL: snake_guard-0.1.0-py3-none-any.whl
- Upload date:
- Size: 49.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2a681bda79faaa40ccd5028f8fb89da817f9d268d02dc789dc315d9c3a3f5066
|
|
| MD5 |
8bdd8e2a10ea786f958f7188497e0913
|
|
| BLAKE2b-256 |
96270a761351d57450d894e3dcef24eb0e3922af2c9bfbc3a86bde49a991ce2e
|
Provenance
The following attestation bundles were made for snake_guard-0.1.0-py3-none-any.whl:
Publisher:
release.yml on Artemooon/snake-guard
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
snake_guard-0.1.0-py3-none-any.whl -
Subject digest:
2a681bda79faaa40ccd5028f8fb89da817f9d268d02dc789dc315d9c3a3f5066 - Sigstore transparency entry: 1340615618
- Sigstore integration time:
-
Permalink:
Artemooon/snake-guard@57eb8704baa4330c4dac2eb0d833c8f01dfed749 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/Artemooon
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@57eb8704baa4330c4dac2eb0d833c8f01dfed749 -
Trigger Event:
push
-
Statement type: