Skip to content

pysentry — dependency vulnerability scanner

What it is

  • PySentry audits a Python project’s dependencies for known vulnerabilities by reading dependency/lock files and cross-referencing multiple vulnerability sources (PyPA advisory DB, PyPI JSON API, OSV).
  • It’s written in Rust and emphasizes speed + caching.
  • It supports multiple input formats (including uv.lock, poetry.lock, Pipfile.lock, requirements.txt, pyproject.toml).

Key value (why teams adopt it)

  • Enforces a repeatable “dependency risk check” in dev/CI without relying on ad-hoc manual audits.
  • Especially useful when:
    • you have multiple dependency sources (poetry + requirements files)
    • you want SARIF output to integrate with code scanning tooling.

Installation and command naming (pitfall: there are two names)

PySentry exposes different command names depending on install method:

  • Rust binary (cargo / release binaries): pysentry
  • Python package (pip / uvx): pysentry-rs (also python -m pysentry)

Practical advice:

  • In docs/scripts, prefer invoking the installed entrypoint explicitly (e.g. pysentry-rs) to avoid confusion across environments.

What files it scans and precedence rules

PySentry auto-detects project type by looking for these files (typical precedence/priority):

  • uv.lock
  • poetry.lock
  • Pipfile.lock
  • pyproject.toml
  • Pipfile
  • requirements.txt

Best practice:

  • Prefer lockfiles (uv.lock / poetry.lock / Pipfile.lock) for deterministic results.
  • Treat “constraints-only” inputs (requirements.txt with ranges) as higher-noise unless you also use a resolver ( below).

Resolver model (critical to understand for requirements.txt)

Why a resolver is needed

  • Vulnerability checking needs concrete versions.
  • If you only have version constraints (e.g. flask>=2,<3), PySentry must resolve them into exact versions before scanning.

Supported resolvers and selection

  • PySentry integrates with external resolvers:
    • uv (preferred; Rust-based)
    • pip-tools (alternative)
  • Auto-detection prefers: uv > pip-tools.
  • Without a resolver present, it can still scan lockfiles like uv.lock and poetry.lock, but requirements.txt scanning will fail or be limited.

Common pitfall:

  • Running PySentry in an environment where uv/pip-tools is not installed (e.g., slim CI image) → “No dependency resolver found”.

Core CLI options you’ll actually use

Target path

  • Scan current directory or a given path:
    • pysentry /path/to/project

Force a specific resolver

  • pysentry --resolver uv /path/to/project
  • pysentry --resolver pip-tools /path/to/project

Scope control (extras/dev deps)

  • pysentry --exclude-extra
    • Interprets as “main only” dependencies (exclude optional/extras/dev-ish scopes).

Pitfall:

  • Teams sometimes unknowingly scan only main deps and miss risk in build/test tooling that is still present in many environments. Decide explicitly.

Severity filtering

  • pysentry --severity high (example: show only high/critical).

Best practice:

  • Use severity filters primarily for “human output”; keep the raw report unfiltered for auditing/triage workflows.

Output formats and files

  • Output formats include: human-readable, JSON, SARIF, Markdown.
  • Example:
    • pysentry --format json --output audit-results.json
    • pysentry --format sarif --output security-report.sarif
    • pysentry --format markdown --output security-report.md

Vulnerability sources

  • Uses multiple data sources by default (PyPA, PyPI, OSV).
  • Can select sources explicitly via repeated --sources:
    • --sources pypa --sources osv

Best practices

Make dependency representation deterministic

  • Prefer:
    • uv.lock / poetry.lock / Pipfile.lock
  • Avoid relying on constraint-only requirements.txt unless:
    • you resolve pins as part of the workflow, and/or
    • you accept that “resolved today” may differ from “resolved tomorrow”.

Separate “reporting” from “gating”

  • Reporting run (full output, SARIF/JSON) for triage.
  • Gating run (stricter) for release branches:
    • typically only fail on high/critical, or on fixable known-bad packages (team policy decision).

Treat “transitive vuln” as a workflow problem, not only a scanning problem

  • If most findings are transitive:
    • track upgrade paths (which top-level dep bumps fix it)
    • consider constraints/overrides policy (careful: can break runtime compatibility)

Common pitfalls and how to handle them

Confusing PySentry with “Sentry (error monitoring)”

  • PySentry is a dependency vulnerability scanner.
  • Sentry is application error/performance monitoring (different product/tooling).

“No lock file or pyproject.toml found”

  • Ensure you run it in the project directory or pass the path.

“No dependency resolver found”

  • Install uv or pip-tools in the environment where you run PySentry.
  • In CI, don’t assume your runtime image has it.

Barrel imports / multiple requirements files

  • If you split requirements files, PySentry can include multiple requirements inputs via repeated flags:
    • pysentry --requirements requirements-dev.txt --requirements requirements-test.txt
  • Pitfall: you think you scanned “everything” but only scanned the default detected file.

Performance and caching

PySentry uses caching and provides cache controls; when things look “stuck” or inconsistent:

  • Clear all caches (manual paths vary by OS)
  • Or use CLI:
    • pysentry --clear-resolution-cache
  • Debug:
    • pysentry --verbose
  • Isolate:
    • pysentry --no-cache

Best practice:

  • If you run it frequently, keep caching enabled; only disable when debugging.

Minimal “starter commands” to memorize

  • Default scan:
    • pysentry .
  • Deterministic, lockfile-first workflow:
    • ensure uv.lock or poetry.lock is present, then pysentry .
  • Requirements workflow (resolver explicitly pinned):
    • pysentry --resolver uv .
  • CI-friendly artifacts:
    • pysentry --format sarif --output security-report.sarif .