Skip to content

feat(python): add GitHub provenance verification for prebuilt binaries#8820

Merged
jdx merged 10 commits intojdx:mainfrom
malept:feat/python-provenance-verification
Mar 30, 2026
Merged

feat(python): add GitHub provenance verification for prebuilt binaries#8820
jdx merged 10 commits intojdx:mainfrom
malept:feat/python-provenance-verification

Conversation

@malept
Copy link
Copy Markdown
Contributor

@malept malept commented Mar 30, 2026

Problem

Precompiled Python binaries from astral-sh/python-build-standalone lack provenance verification. Unlike Ruby (which already supports GitHub Artifact Attestations), Python installs have no mechanism to verify that downloaded binaries were actually produced by the expected CI workflow in the expected repository.

Additionally, there is no downgrade protection: if a lockfile records that provenance was previously verified, nothing prevents an attacker from stripping that metadata and serving unverified binaries.

Solution

Add GitHub Artifact Attestations support for precompiled Python binaries, following the same pattern already established for Ruby:

  1. New setting: python.github_attestations (env: MISE_PYTHON_GITHUB_ATTESTATIONS) overrides the global github_attestations setting specifically for Python. Defaults to the global value (which is true).

  2. Lockfile provenance recording: mise lock now records provenance = "github-attestations" in Python platform entries when the setting is enabled.

  3. Install-time verification: mise install verifies downloaded tarballs against GitHub Artifact Attestations using the sigstore verification crate, with owner/repo hardcoded to astral-sh/python-build-standalone.

  4. Downgrade protection: If the lockfile records provenance but verification is disabled at install time, the install fails with a "downgrade attack" error, preventing provenance stripping attacks.

Test plan

  • mise run test:e2e test_lockfile_python — all tests pass
  • Tests verify: provenance recorded when enabled, not recorded when disabled, downgrade attack detected when lockfile has provenance but verification is off
  • mise run build and mise run lint pass

🤖 Generated with the assistance of OpenCode (claude-opus-4.6).

malept added 4 commits March 29, 2026 19:42
Add a per-language override for the global github_attestations setting,
allowing users to control GitHub Artifact Attestations verification
specifically for precompiled Python binaries from
astral-sh/python-build-standalone.

Assisted-By: claude-opus-4.6 via OpenCode
Add detect_precompiled_provenance() that checks the
python.github_attestations setting (falling back to the global
github_attestations setting) and returns GithubAttestations provenance
type when enabled. Wire this into resolve_lock_info so that
`mise lock` records provenance metadata for precompiled Python binaries.

Assisted-By: claude-opus-4.6 via OpenCode
…stall time

Add verify_github_artifact_attestations() that checks precompiled Python
binaries against GitHub Artifact Attestations using the sigstore
verification crate, with owner/repo hardcoded to
astral-sh/python-build-standalone.

In install_precompiled, add the full provenance lifecycle between
download and extraction: take the lockfile provenance expectation,
verify attestations, record the result, and enforce that the lockfile
expectation is met (detecting provenance downgrade attacks).

Also adds verify_checksum call and URL recording in lock_platforms
for checksum verification support (same pattern as PR 1, duplicated
here since this branch is based off main).

Assisted-By: claude-opus-4.6 via OpenCode
… protection

Add tests that verify:
- Provenance is recorded in lockfile when github_attestations is enabled
- Provenance is NOT recorded when github_attestations is disabled
- Downgrade attack is detected when lockfile has provenance but
  verification is disabled at install time

Assisted-By: claude-opus-4.6 via OpenCode
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements GitHub artifact attestation verification for precompiled Python binaries. Key changes include adding a github_attestations setting to the Python tool configuration, updating the Python plugin to perform verification during installation, and recording provenance in the lockfile to prevent downgrade attacks. Comprehensive E2E tests were also added to verify these behaviors. Feedback suggests refactoring the logic for checking if attestations are enabled into a helper function to eliminate code duplication between the detection and verification methods.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 30, 2026

Greptile Summary

This PR adds GitHub Artifact Attestations support for precompiled Python binaries from astral-sh/python-build-standalone, following the existing Ruby implementation pattern. It introduces a new python.github_attestations setting (env: MISE_PYTHON_GITHUB_ATTESTATIONS) that overrides the global github_attestations setting, records provenance = \"github-attestations\" in the lockfile, verifies attestations at install time using sigstore, and enforces downgrade protection when the lockfile carries provenance.

Key changes:

  • New python.github_attestations optional Bool setting in settings.toml and schema/mise.json, defaulting to the global github_attestations value (true)
  • detect_precompiled_provenance() helper determines whether to record/check provenance based on compile mode and the setting
  • verify_github_artifact_attestations() mirrors the Ruby implementation: returns Ok(true) on success, Ok(false) when disabled, Err on any failure including NoAttestations for old releases
  • Downgrade protection: if tv.lock_platforms carries a provenance entry but verification was skipped, installation is aborted
  • security_info() override now advertises SecurityFeature::GithubAttestations when applicable, closing the parity gap with Ruby
  • All existing Python e2e tests add MISE_PYTHON_GITHUB_ATTESTATIONS=0 for older versions that predate attestation support

Minor gaps: downgrade protection is not enforced when compile = true is set after lockfile generation; security_info may advertise attestations for versions that fall back to compiled-from-source.

Confidence Score: 4/5

Safe to merge with minor open questions around the compile=true bypass and security_info accuracy

All findings are P2 edge-case concerns. The core verification flow, lockfile recording, and downgrade protection for the primary use case are correct. Prior P1 concern about missing security_info was already fixed.

src/plugins/core/python.rs — install_version_ branching and detect_precompiled_provenance logic

Important Files Changed

Filename Overview
src/plugins/core/python.rs Core implementation: adds GitHub Artifact Attestations support for precompiled Python binaries. Correctly follows Ruby pattern. Minor gap: compile=true bypasses downgrade check; detect_precompiled_provenance condition slightly inconsistent with install_precompiled fallback logic.
e2e/lockfile/test_lockfile_python New test sections cover provenance recording, disabled case, and downgrade detection. awk injection is correct but redundant when global attestations default is true.
e2e/core/test_python_github_attestations New e2e test for live attestation verification using python@3.13.5. Depends on GitHub APIs (noted in comments). Correctly asserts progress messages and installed version.
settings.toml Adds python.github_attestations optional Bool setting with MISE_PYTHON_GITHUB_ATTESTATIONS env var. Correct placement and documentation.
schema/mise.json Adds github_attestations boolean field to python settings schema. Consistent with settings.toml addition.
e2e-win/python.Tests.ps1 Disables GitHub attestations for Windows e2e tests using older Python versions. Correct safety measure.
e2e/backend/test_pipx_deep_dependencies_slow Adds MISE_PYTHON_GITHUB_ATTESTATIONS=0 for e2e test using Python 3.12.3, which predates attestation support. Correct fix.
docs/dev-tools/mise-lock.md Adds core:python to the provenance support list in lockfile documentation. Accurate and complete.

Sequence Diagram

sequenceDiagram
    participant User
    participant mise as mise install
    participant Lock as Lockfile
    participant PBS as python-build-standalone
    participant Sigstore

    User->>mise: mise install python@3.13.5
    mise->>Lock: read lock_platforms[platform].provenance
    Note over mise,Lock: locked_provenance = Some("github-attestations") or None
    mise->>PBS: download tarball
    PBS-->>mise: cpython-3.13.5-*.tar.gz
    mise->>mise: verify_checksum (SHA256SUMS)
    alt github_attestations enabled
        mise->>Sigstore: verify_github_attestation(tarball, "astral-sh", "python-build-standalone")
        Sigstore-->>mise: Ok(true)
        mise->>Lock: set pi.provenance = GithubAttestations
    else attestations disabled
        mise->>mise: verified = false
    end
    alt locked_provenance is Some AND verified == false
        mise-->>User: Error: downgrade attack detected
    else provenance matches or no provenance in lockfile
        mise->>mise: untar + sysconfig patch
        mise-->>User: python@3.13.5 installed
    end
Loading

Reviews (4): Last reviewed commit: "fix(python): guard detect_precompiled_pr..." | Re-trigger Greptile

malept added 6 commits March 29, 2026 21:21
…e duplication

The logic to check whether GitHub attestations are enabled was
duplicated in detect_precompiled_provenance() and
verify_github_artifact_attestations(). Extract it into a static
helper method for reuse.

Assisted-By: claude-opus-4.6 via OpenCode
…rting

PythonPlugin was missing a security_info() override, so
`mise tool python` would not report GitHub Attestations as a
security feature even when enabled. Add the override, mirroring
the existing RubyPlugin implementation.

Assisted-By: claude-opus-4.6 via OpenCode
Assisted-By: claude-opus-4.6 via OpenCode
…Python versions

Older Python versions in astral-sh/python-build-standalone (e.g.,
3.12.3, 3.12.0, 3.11.3) do not have GitHub artifact attestations. Since
github_attestations defaults to true, all e2e tests installing these
versions fail with "No GitHub artifact attestations found".

Add MISE_PYTHON_GITHUB_ATTESTATIONS=0 to 14 e2e tests across Linux
(bash) and Windows (PowerShell Pester) that install older precompiled
Python versions not covered by attestations.

Assisted-By: claude-opus-4.6 via opencode
Add a dedicated e2e test that validates Python precompiled binary
attestation verification works end-to-end, analogous to the existing
test_aqua_github_attestations test. Uses Python 3.13.5 which has
known-good attestations in python-build-standalone.

Assisted-By: claude-opus-4.6 via opencode
When python.compile=true, detect_precompiled_provenance() was still
returning GithubAttestations provenance, causing mise lock to record
provenance metadata that would never be verified at install time
(since the compiled path skips attestation verification entirely).

Add the same cfg!(windows) || compile != Some(true) guard used by
install_version_ and security_info. Also simplify security_info to
delegate to detect_precompiled_provenance instead of duplicating
the precompiled + attestations-enabled logic.

Assisted-By: claude-opus-4.6 via opencode
@jdx jdx merged commit bdd9eb6 into jdx:main Mar 30, 2026
33 of 35 checks passed
mise-en-dev added a commit that referenced this pull request Mar 31, 2026
### 🚀 Features

- **(python)** add GitHub provenance verification for prebuilt binaries
by @malept in [#8820](#8820)

### 🐛 Bug Fixes

- **(ci)** use rustls-native-roots for Windows CI build by @jdx in
[#8822](#8822)
- **(go)** improve version fetching logic to support deeply nested
sub-modules by @roele in [#8823](#8823)
- **(shim)** prevent infinite recursion when system shims dir is on PATH
by @andrewthauer in [#8816](#8816)
- go backend missing supports_lockfile_url() override by
@palootcenas-outreach in [#8790](#8790)
- strip shims from PATH in credential and template subprocesses by
@antonioacg in [#8802](#8802)

### 📚 Documentation

- fix typo in shims documentation for fish by @roele in
[#8798](#8798)

### 📦️ Dependency Updates

- update ghcr.io/jdx/mise:alpine docker digest to 3e6d001 by
@renovate[bot] in [#8794](#8794)
- pin dependencies by @renovate[bot] in
[#8793](#8793)

### 📦 Registry

- fix flutter version sorting by @roele in
[#8818](#8818)
- add svgo (npm:svgo) by @3w36zj6 in
[#8817](#8817)

### New Contributors

- @antonioacg made their first contribution in
[#8802](#8802)
- @palootcenas-outreach made their first contribution in
[#8790](#8790)

## 📦 Aqua Registry Updates

#### New Packages (3)

- [`RasKrebs/sonar`](https://github.com/RasKrebs/sonar)
- [`emacs-eask/cli`](https://github.com/emacs-eask/cli)
-
[`superradcompany/microsandbox`](https://github.com/superradcompany/microsandbox)

#### Updated Packages (4)

- [`dimo414/bkt`](https://github.com/dimo414/bkt)
- [`lxc/incus`](https://github.com/lxc/incus)
-
[`shinagawa-web/gomarklint`](https://github.com/shinagawa-web/gomarklint)
- [`updatecli/updatecli`](https://github.com/updatecli/updatecli)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants