Installation verification across package managers#

Package hashes and Sigstore attestations answer different questions. A hash checks that downloaded bytes match a previously selected digest. A Sigstore attestation checks that an authenticated identity signed a statement about those bytes. Neither check alone establishes that the identity was authorized to publish a package.

Client behavior observed on 2026-08-11#

This comparison reflects the linked public documentation on 2026-08-11. Pinned source links identify the exact Pixi and uv revisions reviewed.

Client

Artifact check during installation

Sigstore attestation check during installation

pip

Checks an index-advertised download hash for corruption. --require-hashes requires locally supplied hashes for all resolved requirements.

None. PyPI documents a separate pypi-attestations verify pypi command for consumer verification.

uv

Records selected index hashes in uv.lock and verifies hashes supplied in requirements files. --require-hashes requires complete hash coverage.

None. uv publish discovers and uploads adjacent PEP 740 attestations, but does not generate them or verify them during installation.

npm

Uses package-lock.json to select exact dependency versions and records Subresource Integrity values for downloaded artifacts.

None. npm audit signatures is a separate command that verifies registry signatures and available provenance attestations after dependencies are installed.

Pixi

Verifies conda and PyPI package checksums recorded in pixi.lock when an artifact is installed or reused from cache.

None. Pixi creates or uploads Sigstore attestations for Prefix.dev publishing and documents external consumer verification with gh or cosign.

conda with conda-sigstore

Conda retains its package digest checks.

An opt-in direct package verifier requires valid CEP 27 evidence from a repodata-hash-pinned immutable sidecar or the separate deterministic Prefix.dev adjacent sidecar. PR 142 selection also needs conda to preserve attestations_sha256. It is an integration preview against conda/conda#16518.

The relevant primary documentation is:

PyPI is the repository in this comparison, not pip. PyPI validates supported attestations at upload, associates publish attestations with Trusted Publisher identities, and exposes provenance through its Integrity API. That gives a consumer enough repository context to perform an authorization check. pip does not consume that evidence during an ordinary install.

uv’s attestation support is also on the producer side. Its publisher passes adjacent PEP 740 JSON objects to a supporting index. Its current upload implementation notes that it does not validate the interior attestation structure beyond JSON before upload. This is transport behavior, not consumer verification.

npm also separates installation from signature and provenance verification. npm audit signatures runs after npm install or npm ci, checks registry signatures and available provenance attestations, and reports an error when a registry that advertises signing keys omits or provides an invalid signature. It verifies provenance when present rather than requiring every package to carry it. It does not expose a consumer-managed identity policy or a reusable verification receipt.

Pixi checks locked artifact digests during installation. Its Sigstore path is separate and producer-oriented. pixi publish --generate-attestation and pixi upload prefix --generate-attestation create and upload evidence for Prefix.dev. The Pixi security guide directs consumers to external Sigstore tools instead of claiming that pixi install verifies those attestations.

The closest existing consumer pattern is PyPI’s separate pypi-attestations verify pypi --repository ... command. The repository is an independent trust input. conda sigstore verify offers the corresponding low-level choice through paired --cert-identity and --cert-oidc-issuer options. They apply to one command and do not create channel policy.

Why enforcement has one switch#

The plugin keeps installation enforcement either disabled or fail-closed. conda sigstore audit is the nonblocking way to measure evidence coverage before enabling enforcement. An ignore mode would duplicate the disabled state, while a warn mode inside installation would duplicate the audit workflow and make invalid evidence easy to overlook.

A client-maintained policy language would not establish who a channel authorized to publish. That information needs to come from a standardized channel delegation, like PyPI’s Trusted Publisher relationship, rather than a new .condarc identity allowlist.

Verification reports are output, not reusable trust decisions. Trust material, transparency evidence, and verifier behavior can change between commands. This matches pip’s treatment of its installation report, which is not accepted as install input. The plugin therefore verifies evidence fresh instead of caching receipts.

Why verification runs before extraction#

An audit can measure evidence coverage after installation, but it cannot prove that invalid evidence was rejected before package files reached a prefix. The package-verifier hook makes an opt-in decision before extraction while conda still has the selected URL, expected digest, and archive.

The verifier uses the same evidence-validation pipeline as the explicit command instead of caching a receipt or reimplementing Sigstore inside conda. Exact transport behavior belongs in Commands, and the setting and recovery controls belong in Configuration and Configure verification.

Upstream status#

conda/conda#16518 provides the pre-extraction verifier hook. This repository’s locked developer environments build a pinned revision from jezdez/conda’s feature/package-verifiers branch as a conda package. No released conda version provides that API yet.

The current conda PackageRecord model and solver conversion paths do not preserve PR 142’s attestations_sha256 field. A separate conda change is required before real solver and install flows can select <artifact>.sigs.<attestations_sha256>. The adjacent Prefix.dev .v0.sigs compatibility path needs only the selected package URL and digest. A rejection prevents that archive from being extracted and linked, although concurrent cache work for other packages may already have completed.

The exact upstream contract is listed in Upstream integration contracts.

For concrete conda-lockfiles and conda-workspaces commands, see Verify locked environments during installation.