Skip to main content

pip-compile wrapper with CVE awareness

Project description

safe-pip-compile

PyPI Python License: MIT

safe-pip-compile is a drop-in pip-compile wrapper that avoids pinning Python packages with known CVEs.

pip-compile is excellent at resolving repeatable dependency sets, but it does not know whether a resolved version has a published vulnerability. safe-pip-compile adds that missing safety loop: compile, audit against OSV.dev, constrain vulnerable versions out of the result, and retry until the lock file is clean or the configured limit is reached.

Why use it?

  • Keep the familiar pip-compile workflow.
  • Block vulnerable package versions before they land in requirements.txt.
  • Use severity thresholds, allowlists, JSON reports, and CI-friendly exit codes.
  • Cache OSV results locally so repeated runs stay fast.
  • Pass normal pip-compile flags through when you need them.

Installation

pip install safe-pip-compile

Project page: https://pypi.org/project/safe-pip-compile/

Quick start

safe-pip-compile requirements.in -o requirements.txt

Input:

django
requests

Output:

# Generated by safe-pip-compile
# Vulnerable versions are excluded when OSV.dev reports a blocking CVE.
django==...
requests==...

How it works

requirements.in
  -> pip-compile
  -> parse resolved packages
  -> check local cache or query OSV.dev
  -> filter by severity and allowlist
  -> add temporary constraints for vulnerable versions
  -> repeat until clean, stuck, or max iterations is reached
  -> requirements.txt

When a vulnerable package is found, safe-pip-compile asks the resolver for a safe alternative by adding constraints such as django>=3.2.25. It keeps the dependency resolver in charge instead of hand-editing pinned output.

CLI flags

Flag Description Default
-o, --output-file PATH Output requirements.txt path requirements.txt
--min-severity LEVEL Only block CVEs at this level or above: critical, high, medium, low low
--allow-list PATH YAML file of accepted CVEs to skip none
--max-iterations INT Maximum compile/audit loops before stopping 10
--strict / --no-strict Exit with code 1 if unresolved CVEs remain --strict
--dry-run Preview actions without writing output files off
--json-report PATH Write a machine-readable JSON vulnerability report none
--cert PATH CA bundle for SSL verification behind corporate proxies auto-detect from env
--no-cache Disable the local CVE cache and always query OSV.dev cache enabled
--refresh-cache Clear cached CVE data and re-fetch from OSV.dev, then run normally off
--clear-cache Delete the entire cache directory and exit (useful before uninstalling) off
-v, --verbose Increase output detail. Use -v or -vv quiet

All other flags after -- are passed through to pip-compile.

safe-pip-compile requirements.in -- --generate-hashes --allow-unsafe

Examples

Block only high and critical vulnerabilities:

safe-pip-compile requirements.in --min-severity high

Accept specific CVEs through an allowlist:

safe-pip-compile requirements.in --allow-list cve-allowlist.yaml

Generate a JSON report and fail CI on unresolved CVEs:

safe-pip-compile requirements.in --json-report audit.json --strict

Preview without writing files:

safe-pip-compile requirements.in --dry-run -v

Bypass or refresh the local cache:

safe-pip-compile requirements.in --no-cache
safe-pip-compile requirements.in --refresh-cache

# Wipe the entire cache directory (e.g. before uninstalling)
safe-pip-compile --clear-cache

Allowlist format

Create cve-allowlist.yaml when your team has reviewed and accepted a specific risk:

allowed_cves:
  - id: CVE-2024-12345
    reason: "Not applicable; we do not use the affected feature"
    expires: 2025-06-01

  - id: GHSA-xxxx-yyyy-zzzz
    reason: "Accepted risk, tracked in JIRA-789"

Allowlist entries are matched against the vulnerability ID and aliases such as CVE, PYSEC, and GHSA identifiers.

pyproject.toml config

Every CLI flag can be set as a project-level default in pyproject.toml. CLI flags always take precedence over file settings.

Option reference

pyproject.toml key CLI equivalent Example value
max-iterations --max-iterations INT 10
min-severity --min-severity LEVEL "high"
allowlist --allow-list PATH "cve-allowlist.yaml"
strict --strict / --no-strict true
output-file -o / --output-file PATH "requirements.txt"
json-report --json-report PATH "audit.json"
dry-run --dry-run false
cert --cert PATH "/etc/ssl/certs/corp-ca.pem"
no-cache --no-cache false
refresh-cache --refresh-cache false
verbose -v / -vv 1

pyproject.toml

[tool.safe-pip-compile]
# ── Core resolution ────────────────────────────────────────
max-iterations = 10          # Maximum compile/audit loops (default: 10)
min-severity   = "high"      # Minimum blocking severity: critical/high/medium/low
allowlist      = "cve-allowlist.yaml"  # Path to CVE allowlist YAML
strict         = true        # Fail on unresolved CVEs (default: true)

# ── Output / reporting ─────────────────────────────────────
output-file  = "requirements.txt"   # Default output file (-o)
json-report  = "audit.json"         # Write JSON vulnerability report
dry-run      = false                # Preview without writing files

# ── Network / SSL ──────────────────────────────────────────
cert = "/etc/ssl/certs/corporate-ca.pem"  # CA bundle path (--cert)

# ── Cache ──────────────────────────────────────────────────
no-cache      = false   # Always query OSV.dev, skip local cache
refresh-cache = false   # Clear cache before run

# ── Verbosity ──────────────────────────────────────────────
verbose = 1             # 0 = quiet, 1 = -v, 2 = -vv

CLI equivalent commands

# Core resolution
safe-pip-compile requirements.in --max-iterations 10
safe-pip-compile requirements.in --min-severity high
safe-pip-compile requirements.in --allow-list cve-allowlist.yaml
safe-pip-compile requirements.in --strict
safe-pip-compile requirements.in --no-strict

# Output / reporting
safe-pip-compile requirements.in -o requirements.txt
safe-pip-compile requirements.in --output-file requirements.txt
safe-pip-compile requirements.in --json-report audit.json
safe-pip-compile requirements.in --dry-run

# Network / SSL
safe-pip-compile requirements.in --cert /etc/ssl/certs/corp-ca.pem

# Cache
safe-pip-compile requirements.in --no-cache
safe-pip-compile requirements.in --refresh-cache
safe-pip-compile --clear-cache     # delete cache directory and exit

# Verbosity
safe-pip-compile requirements.in -v    # verbose
safe-pip-compile requirements.in -vv   # extra verbose

CLI flags override pyproject.toml values.

Exit codes

Code Meaning
0 Clean result: no blocking CVEs found
1 Unresolved CVEs remain in strict mode
2 pip-compile resolution failed
3 Network or configuration error

Local CVE cache

Vulnerability data is cached in a local SQLite database to avoid repeated OSV.dev API calls.

Platform Cache path
Linux ~/.cache/safe-pip-compile/cache.db
macOS ~/Library/Caches/safe-pip-compile/cache.db
Windows C:\Users\Teja\AppData\Local\safe-pip-compile\Cache\cache.db

Cache behavior:

  • Fixed vulnerabilities are cached for 6 months.
  • Vulnerabilities without a fix are not cached permanently, so a newly published fix can be picked up on a later run.
  • pip-compile results are also cached for 30 minutes. If the input files and Python version haven't changed, the resolver is skipped entirely and CVE scanning starts immediately — saving 30-120 s on complex dependency sets.
  • The cache is stored per user and works across virtual environments.
  • SQLite WAL mode allows concurrent readers.

Cache management

Flag What it does
--no-cache Disables both the CVE cache and the pip-compile result cache for this run
--refresh-cache SQL DELETE all cached rows, then runs normally and refills the cache
--clear-cache Deletes the entire cache directory from disk (shutil.rmtree) and exits — useful before uninstalling

Tip: run safe-pip-compile --clear-cache before pip uninstall safe-pip-compile to remove the leftover cache.db file from your user profile.

Corporate proxy and SSL

If your organization performs SSL inspection, OSV.dev requests may fail with a certificate verification error.

Use a custom CA bundle:

safe-pip-compile requirements.in --cert /path/to/corporate-ca-bundle.pem

Or set one of the standard certificate environment variables:

export SSL_CERT_FILE=/path/to/corporate-ca-bundle.pem
export REQUESTS_CA_BUNDLE=/path/to/corporate-ca-bundle.pem

Lookup order:

Lookup order: `--cert` flag > `SSL_CERT_FILE` > `REQUESTS_CA_BUNDLE` > `CURL_CA_BUNDLE` > system default.

Development

pip install -e ".[dev]"
python -m pytest tests -v

Author

Built and maintained by N Venkata Sai Teja.

For more projects, writing, and contact details, visit venkatasaiteja.in or connect on LinkedIn.

License

This project is licensed under the MIT License.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

safe_pip_compile-0.1.9.tar.gz (39.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

safe_pip_compile-0.1.9-py3-none-any.whl (42.2 kB view details)

Uploaded Python 3

File details

Details for the file safe_pip_compile-0.1.9.tar.gz.

File metadata

  • Download URL: safe_pip_compile-0.1.9.tar.gz
  • Upload date:
  • Size: 39.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for safe_pip_compile-0.1.9.tar.gz
Algorithm Hash digest
SHA256 6aefb5d94e77d97696a178a82f06ff9c0e8798254dbd2ce88e960723c4ac2f74
MD5 59a0fa668cc053f41d03521cf8609808
BLAKE2b-256 e3d5387efa20ea0289cde28ac7c4d266b1f65370309ee366704b56c5bdedb460

See more details on using hashes here.

Provenance

The following attestation bundles were made for safe_pip_compile-0.1.9.tar.gz:

Publisher: publish.yml on sai1027/safe-pip-compile

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file safe_pip_compile-0.1.9-py3-none-any.whl.

File metadata

File hashes

Hashes for safe_pip_compile-0.1.9-py3-none-any.whl
Algorithm Hash digest
SHA256 f254be4f5c4f0e0e1c9665882925598db90dd75d488d8c65517085f3a3e9667d
MD5 1f86e5a55a1e08566631ad61b9a9a3dd
BLAKE2b-256 d0f0bd9b268c0a26951fe418c81d76a9ef8c8b7c69e327c68025e06653bd98c1

See more details on using hashes here.

Provenance

The following attestation bundles were made for safe_pip_compile-0.1.9-py3-none-any.whl:

Publisher: publish.yml on sai1027/safe-pip-compile

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page