Skip to main content

Package trust and provenance verification for PyPI consumers.

Project description

trustcheck Awesome

CI Source Build CodeQL pip-audit Bandit Semgrep Adversarial fuzzing Windows Defender ClamAV Ruff mypy Coverage PyPI Python 3.11 | 3.12 | 3.13 | 3.14 PyPI Downloads TrustCheck Package Scanner

trustcheck is a Python package and CLI for evaluating the trust posture of PyPI releases before they are installed, promoted, or approved.

It combines PyPI metadata, vulnerability records, provenance availability, cryptographic attestation verification, Trusted Publisher identity hints, and repository matching into a single operator-friendly report.

Packages that publish no provenance are treated as needing review rather than as automatic high-risk findings, while invalid provenance, partial coverage, repository mismatches, and known vulnerabilities remain stronger negative signals.

What it checks

For a selected package version, trustcheck can:

  • fetch project and release metadata from PyPI
  • verify published provenance against artifact digests
  • interpret SLSA v1 build definitions, builders, source materials, commits, workflows, and resolved build dependencies
  • detect mutable workflow references, unpinned build actions, and source-to-artifact inconsistencies
  • surface Trusted Publisher repository and workflow identity hints
  • compare signer, repository, workflow, builder, build type, and source commit evidence across release history
  • compare expected repository input against declared and attested signals
  • flag publisher drift, missing verification, and known vulnerabilities
  • scan requirements files, project TOML, pylock.toml, Pipfile.lock, pip-tools output, and uv.lock, poetry.lock, or pdm.lock
  • resolve complete dependency sets with pip installation reports, including constraints, nested requirements, extras, dependency groups, editable requirements, and VCS references
  • audit the active Python environment or arbitrary site-packages directories
  • resolve against PEP 503/691 private indexes with optional keyring credentials
  • block dependency-confusion collisions across public and private indexes
  • preserve and verify lockfile artifact hashes before trusting downloaded bytes
  • plan, dry-run, apply, or publish the smallest validated secure dependency upgrade set without silently widening declared constraints
  • batch OSV queries, bound concurrent target work, and store responses by verified SHA-256 content digest
  • consume offline advisory snapshots, resume interrupted scans, and load explicitly enabled advisory, index, artifact, policy, or renderer plugins
  • optionally inspect wheel and sdist contents without importing or executing package code
  • score typosquatting, dependency-confusion, package-history, source-code, and native-binary heuristic indicators without claiming a malware verdict
  • emit text, JSON, SARIF 2.1.0, CycloneDX 1.6 JSON/XML, SPDX 2.3 JSON, OpenVEX 0.2.0, or Markdown

Every push also builds standalone Windows and Linux executables. The Windows artifact is scanned with Microsoft Defender's MpCmdRun.exe; the Linux artifact is scanned with ClamAV. Clean binaries, checksums, and scanner reports are retained as workflow artifacts by Binary Security.

Latest benchmark

Provisional historical result: this signed run predates the five-sample, full-truth-coverage publication gate and is not evidence of performance superiority.

Generated 2026-06-21T08:43:40.047949+00:00 on Python 3.14.6 with pip-audit 2.10.0. Corpus 2026.06 covered 112 comparable package entries.

Tool Cold p50 Warm p50 Warm p95 Peak RSS Requests p50 Recall
trustcheck scan --fast 17.08 s 15.70 s 15.70 s 88.3 MiB unknown 1
pip-audit 38.71 s 39.96 s 39.96 s 74.4 MiB unknown 1

Alias-aware agreement: 0.759197 across 109 compared packages and 227 matched advisories. Resolver exact match: True (trustcheck 22, pip-audit 22).

Installation

Install from PyPI:

pip install trustcheck

Install the optional Python keyring provider when private-index credentials are stored in an in-process keyring backend:

pip install "trustcheck[keyring]"

Or install the Snap Store package:

sudo snap install trustcheck

The Snap command is trustcheck. If the shell reports command not found immediately after installation, start a new login session or add Snap's command directory to the current shell:

export PATH="/snap/bin:$PATH"
trustcheck --version

You can always bypass shell PATH lookup with:

snap run trustcheck inspect requests

PyPI installation requirements:

  • Python >=3.11
  • Network access to PyPI

Machine-readable reports currently use JSON schema 1.10.0. Package and report schema versions are independent so documentation-only package releases do not force contract churn.

Pre-commit and monorepos

Trustcheck publishes a first-party hook for changed dependency files:

repos:
  - repo: https://github.com/Halfblood-Prince/trustcheck
    rev: v1
    hooks:
      - id: trustcheck

The hook runs --fast --no-deps --with-osv, preserves lockfile artifact hashes, deduplicates filenames, and merges failures across every changed dependency file. For monorepos, trustcheck-workspace . --format sarif discovers supported files, aggregates repository-relative results, and accepts --baseline plus --policy-overrides for per-project policies.

TrustCheck Package Scanner

Use the TrustCheck Package Scanner action to scan a checked-in dependency file before merge:

steps:
  - uses: actions/checkout@v6
  - uses: Halfblood-Prince/trustcheck@v1
    with:
      target: requirements.txt
      policy: strict

The action installs and runs trustcheck, uploads trustcheck-report.json as a workflow artifact, and fails the job with the CLI's exit code when policy evaluation fails. target also accepts a PyPI package name, pyproject.toml, pylock.toml, Pipfile.lock, uv.lock, poetry.lock, or pdm.lock. Each stable release publishes an immutable full version tag and updates the compatible major action tag used above.

Produce SARIF for GitHub code scanning without repeating the audit:

- uses: Halfblood-Prince/trustcheck@v1
  id: trustcheck
  with:
    target: requirements.txt
    format: sarif

- uses: github/codeql-action/upload-sarif@v4
  if: always()
  with:
    sarif_file: ${{ steps.trustcheck.outputs.report-path }}

See the CI integration guide for custom policies, OSV, dependency traversal, outputs, and report naming.

Quick start

Inspect the latest release:

trustcheck inspect requests

Inspect a specific version:

trustcheck inspect sampleproject --version 4.0.0

Show only known vulnerabilities for a release:

trustcheck scan sampleproject --version 4.0.0 --fast

Scan profiles make the analysis depth explicit. --fast (the default) performs dependency resolution and advisory lookup only. --standard adds provenance, while --full adds static archives, native binaries, release history, and malicious-package heuristics. Artifact breadth defaults to the best compatible wheel for the requested target, with an sdist fallback.

trustcheck scan -f requirements.txt --standard
trustcheck scan sampleproject --version 4.0.0 --full --max-workers 8
trustcheck scan sampleproject --full --artifact-scope all --strict

Use --artifact-scope sdist for source review or --artifact-scope all for a strict whole-release review.

Enrich vulnerability intelligence with OSV and GitHub Advisory Database data:

trustcheck scan jinja2 --version 2.10.0 --with-osv

Merge OSV, Ecosyste.ms, a private OSV-compatible service, CISA KEV, and FIRST EPSS intelligence:

trustcheck scan jinja2 \
  --version 2.10.0 \
  --with-osv \
  --with-ecosystems \
  --osv-url https://advisories.example.com \
  --with-kev \
  --with-epss

Gate only critical, known-exploited, or fixable vulnerabilities:

trustcheck scan -f pylock.toml --fail-on-vulnerability kev

Require verified publishers to belong to an approved organization:

trustcheck inspect sampleproject \
  --version 4.0.0 \
  --trusted-publisher-organization github:pypa

Custom policy files can suppress a specific advisory temporarily, but every suppression must name an owner, justification, and ISO expiration date.

Inspect a package and its direct dependencies:

trustcheck inspect sampleproject --version 4.0.0 --with-deps

Inspect the full transitive dependency tree:

trustcheck inspect sampleproject --version 4.0.0 --with-transitive-deps

Inspect every package listed in a requirements-style file:

trustcheck inspect -f requirements.txt

Resolution uses pip install --dry-run --report and includes transitive packages selected by pip:

trustcheck scan -f requirements.txt \
  --constraint constraints.txt \
  --python-version 3.12 \
  --platform manylinux_2_28_x86_64 \
  --implementation cp \
  --abi cp312

Pip may invoke build-backend metadata hooks even in dry-run mode. Trustcheck can isolate that resolver invocation:

trustcheck scan -f requirements.txt --sandbox auto

--sandbox auto is the default. It prefers Bubblewrap on Linux, then Docker or Podman, and falls back to strict wheel-only resolution when no runtime is available. The full mode set is:

  • warn: explicitly preserve host pip behavior and emit an execution-risk warning
  • off: preserve pip behavior without the warning
  • container: run pip as an unprivileged process in a read-only Docker/Podman container with dropped capabilities and only staged resolver inputs mounted
  • bubblewrap: run pip in low-privilege Linux namespaces with a read-only staged input tree, read-only system paths, and a cleared environment
  • strict: reject editable, VCS, local non-wheel, direct non-wheel, and source archive inputs, ignore user pip configuration, and require wheels for every resolved package; child-process creation is denied so unexpected transitive source hooks and VCS commands fail closed

Container and Bubblewrap modes retain network access for package-index resolution. Requirements, nested includes, constraints, dependency-group files, and referenced local dependencies are copied to a temporary input tree; the project workspace is not mounted. Container images must be pinned by a full SHA-256 digest when supplied with --sandbox-image. Cross-target resolution is always wheel-only.

Inspect dependencies declared in a TOML project file:

trustcheck inspect -f pyproject.toml

Plan the smallest constraint-compatible secure upgrade set:

trustcheck scan -f requirements.txt \
  --with-osv \
  --plan-fixes \
  --remediation-output reports/trustcheck-remediation.json

Generate and validate the exact patch without changing the working tree:

trustcheck scan -f pyproject.toml --with-osv --fix --dry-run

Apply the same transaction only after re-resolution and a complete rescan:

trustcheck scan -f uv.lock --with-osv --fix

Secure versions excluded by a declared range remain blocked unless --allow-constraint-changes is passed. Editable, local-path, direct-archive, and VCS dependencies are reported as requiring human remediation.

Select project extras and dependency groups:

trustcheck scan -f pyproject.toml --extra security --group test

Inspect exact direct and transitive versions from a supported lockfile:

trustcheck inspect -f pylock.toml --with-transitive-deps
trustcheck scan -f Pipfile.lock

Run a bounded, resumable scan and publish an advisory snapshot:

trustcheck scan -f requirements.txt \
  --with-osv \
  --max-workers 8 \
  --resume-state .trustcheck/scan-state.json \
  --write-advisory-snapshot .trustcheck/advisories.json \
  --sign-advisory-snapshot

Signed snapshots include source URLs, generation and expiration times, and a SHA-256 digest of canonical advisory records. Reading one requires the trusted Sigstore certificate identity and accepts snapshots for at most seven days by default; adjust that bound with --max-advisory-age HOURS.

Enable an installed, signed plugin explicitly:

trustcheck scan -f requirements.txt --plugin policy:company-policy

Every plugin must be explicitly allowlisted. Trustcheck verifies its signed trustcheck-plugin.json name, kind, entry point, and API version before using a spawned resource-bounded worker. Optional signer fingerprints live under _trustcheck.trusted_signers in plugin config. Each call is reported in diagnostics.plugin_executions with status, duration, and isolation state.

Hash-pinned pip-tools output is detected automatically. Every retained lockfile hash is emitted in combined JSON and checked against the downloaded artifact. This integrity check does not require --inspect-artifacts.

Resolve and audit from a private PEP 503/691 index:

trustcheck scan -f requirements.txt \
  --index-url https://username@packages.example.com/simple \
  --keyring-provider subprocess

Adding a public fallback is deliberately guarded:

trustcheck scan -f requirements.txt \
  --index-url https://username@packages.example.com/simple \
  --extra-index-url https://pypi.org/simple

If the same normalized project name exists on both indexes, the scan stops with a dependency-confusion error. --allow-dependency-confusion is available for a source collision that has been independently reviewed; the finding remains in combined JSON.

Audit the active environment:

trustcheck environment

Audit one or more explicit site-packages directories:

trustcheck environment --path .venv/lib/python3.12/site-packages

Statically inspect wheel and sdist contents:

trustcheck inspect sampleproject --version 4.0.0 --inspect-artifacts --verbose

Artifact inspection validates wheel RECORD hashes, lists console scripts, parses Python source with ast, detects suspicious capability combinations, and compares wheel and sdist metadata. PE, ELF, and Mach-O files are inspected for imported libraries, embedded signature presence, entropy, and embedded payload signatures. It reads archive bytes only and never imports the inspected package.

Name, index, ownership, repository, and release-cadence heuristics run during normal inspection. Add organization-specific reference names with repeatable --trusted-project:

trustcheck inspect -f requirements.txt \
  --trusted-project internal-sdk \
  --trusted-project internal-auth

Every malicious-package finding is explicitly labeled as a heuristic indicator for review, not proof that a package is malicious.

Require a release to match an expected repository:

trustcheck inspect sampleproject \
  --version 4.0.0 \
  --expected-repo https://github.com/pypa/sampleproject

Emit JSON for another tool:

trustcheck inspect sampleproject --version 4.0.0 --format json

Emit combined JSON for a requirements-style, TOML, or lockfile scan:

trustcheck scan -f requirements.txt --format json

Write SARIF, SBOM, VEX, or Markdown output directly to a file:

trustcheck scan -f requirements.txt \
  --format sarif \
  --output-file reports/trustcheck.sarif

trustcheck scan -f pylock.toml \
  --format cyclonedx-json \
  --output-file reports/trustcheck.cdx.json

Supported industry formats are sarif, cyclonedx-json, cyclonedx-xml, spdx-json, openvex, and markdown. SBOM exports retain package purls, vulnerabilities, provenance coverage, artifact hashes, recommendations, and policy violations.

Emit only vulnerability records as JSON:

trustcheck scan sampleproject --version 4.0.0 --format json

Fail CI when full verification is missing:

trustcheck inspect sampleproject --version 4.0.0 --strict

Use it from Python:

from trustcheck import inspect_package

report = inspect_package("sampleproject", version="4.0.0", include_dependencies=True)
print(report.recommendation)

Documentation

Full documentation: https://halfblood-prince.github.io/trustcheck/

Project support:

License

Trustcheck Personal Use 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

trustcheck-2.1.0.tar.gz (1.1 MB view details)

Uploaded Source

Built Distribution

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

trustcheck-2.1.0-py3-none-any.whl (196.8 kB view details)

Uploaded Python 3

File details

Details for the file trustcheck-2.1.0.tar.gz.

File metadata

  • Download URL: trustcheck-2.1.0.tar.gz
  • Upload date:
  • Size: 1.1 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for trustcheck-2.1.0.tar.gz
Algorithm Hash digest
SHA256 6ca768e9231c885f731051dd658b7a9cfbba68fd00a6d1f82a74fd7b0b5a4e26
MD5 6eff60ec0d642aba483a7e4a052b99e0
BLAKE2b-256 b14c8882a81c4357389cc70860a5db649c02ba0ac57ba3455e3002ec77cb4b98

See more details on using hashes here.

Provenance

The following attestation bundles were made for trustcheck-2.1.0.tar.gz:

Publisher: publish.yml on Halfblood-Prince/trustcheck

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

File details

Details for the file trustcheck-2.1.0-py3-none-any.whl.

File metadata

  • Download URL: trustcheck-2.1.0-py3-none-any.whl
  • Upload date:
  • Size: 196.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for trustcheck-2.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 52a6e7970ef74212e65685393dd9490fcedb7c76f7c2ec1070f9c1fc6ebd2d17
MD5 3dbd1c5278fe71a6d688a549ff8a5a43
BLAKE2b-256 8b4cae4f7ffc89c696b5c0f6287695aaa5917c6aa8eb468d0c4d59ecbbbe2b30

See more details on using hashes here.

Provenance

The following attestation bundles were made for trustcheck-2.1.0-py3-none-any.whl:

Publisher: publish.yml on Halfblood-Prince/trustcheck

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