security(lock): block github tool upgrade when provenance is lost#8706
security(lock): block github tool upgrade when provenance is lost#8706
Conversation
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request enhances supply chain security by introducing a critical warning system within the Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
Greptile SummaryThis PR adds supply-chain protection to mise's lockfile infrastructure: when a Key changes:
Remaining concern: Confidence Score: 4/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[mise install / mise use] --> B[rebuild_shims_and_runtime_symlinks]
B --> C[update_lockfiles]
C --> D{check_provenance_regression\nfor each tool on current platform}
D -- regression detected --> E[skip merge for regressing tools\ncollect error]
D -- no regression --> F[merge_tool_entries\nwrites new version, drops old]
E --> G[save lockfile\nold entry preserved]
F --> G
G --> H{any provenance errors?}
H -- yes --> I[return Err\nauto_lock_new_versions skipped]
H -- no --> J[auto_lock_new_versions]
J --> K[resolve platform checksums/URLs]
K --> L[apply_lock_result\ncheck_single_tool_provenance]
L -- regression detected --> M[collect error\ndo NOT write platform info]
L -- no regression --> N[set_platform_info in lockfile]
M --> O[save lockfile]
N --> O
O --> P{any provenance errors?}
P -- yes --> Q[return Err to caller]
P -- no --> R[OK]
S[mise lock] --> T[process_tools\nper tool×platform in JoinSet]
T --> U[resolve_tool_lock_info]
U --> V[apply_lock_result\ncheck_single_tool_provenance]
V -- regression --> W[collect provenance_error\nresult = false]
V -- ok --> X[set_platform_info]
W --> Y[lockfile.write]
X --> Y
Y --> Z{any provenance errors?}
Z -- yes --> AA[return Err after all lockfiles written]
Z -- no --> AB[OK]
|
There was a problem hiding this comment.
Code Review
This pull request adds an important security feature: it warns the user when a tool upgrade results in a loss of provenance, which could indicate a supply chain attack. The implementation is correct and includes a new end-to-end test to verify the functionality. I have one suggestion to improve the code's readability and make it more idiomatic.
src/lockfile.rs
Outdated
| // publishes a release without attestations. | ||
| if info.provenance.is_none() && backend.starts_with("github:") { | ||
| if let Some(tools) = lockfile.tools.get(&short) { | ||
| let prior_provenance = tools.iter().find_map(|t| { | ||
| if t.version != version { | ||
| t.platforms | ||
| .get(&platform_key) | ||
| .and_then(|pi| pi.provenance.as_ref()) | ||
| } else { |
There was a problem hiding this comment.
This logic for finding a prior version with provenance can be made more concise and idiomatic by chaining iterator methods. Using filter() before find_map() separates the concerns of filtering out the current version and finding the desired provenance, which improves readability.
let prior_provenance = tools
.iter()
.filter(|t| t.version != version)
.find_map(|t| t.platforms.get(&platform_key)?.provenance.as_ref());3bb24a5 to
43b365d
Compare
231d4d3 to
2095e12
Compare
…upgrade When locking a new version of a github backend tool, check if any prior version in the lockfile had provenance verification. If the new version has no provenance, warn about a potential supply chain attack (attacker publishes a release without attestations). This check is scoped to github backend only — aqua and vfox tools have different trust models where provenance changes across versions are expected. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… on upgrade Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The ? on apply_lock_result caused early return from the result loop, silently dropping already-applied lock entries for unaffected tools because lockfile.save() was never reached. Now collect the provenance error, save the lockfile for all unaffected tools, then return the error. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Move provenance check into update_lockfiles where old version entries are still available (fixes dead code in auto_lock_new_versions path where merge_tool_entries already removed old entries) - Defer provenance errors across the outer lockfile loop so monorepo projects don't skip remaining lockfiles - Compare against highest prior version only, not any arbitrary version - Include prior version number in error message - Quote $PLATFORM in test, add version dependency comment Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Auto-lock path now hard-fails on provenance regression instead of warn (config/mod.rs propagates error instead of swallowing it) - check_provenance_regression only checks current platform to avoid false positives (new entries only have lock_platforms for current platform, not all 5 common platforms) - Collect all provenance errors instead of only reporting the last one (both mise lock and auto-lock paths) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Skip regressing tools during merge/save so the old provenance-verified entry is preserved in the lockfile (prevents single-warning bypass) - Filter new entries by github: backend to avoid false positives when a tool migrates from github to another backend (e.g., aqua) - Refactor check_provenance_regression to return regressing tool names Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Only flag upgrades that lose provenance — intentional downgrades to versions that predate attestation support are allowed. Applied to both check_provenance_regression and apply_lock_result paths. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ackend - Auto-lock provenance errors are now collected across all lockfiles before returning, so monorepo projects don't skip remaining lockfiles - apply_lock_result now filters prior entries by github: backend, matching check_provenance_regression's behavior (avoids false positives when a tool previously appeared under aqua/vfox with provenance) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2201981 to
c7116fc
Compare
…ce check None backend on new LockfileTool entries bypassed the github-only guard because `if let Some` didn't match. Use `is_some_and` to skip entries that aren't explicitly github backend. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
cad9cb5 to
ae6fdcd
Compare
- mise lock now saves the lockfile before returning provenance errors, matching update_lockfiles and auto_lock_new_versions behavior - Provenance errors are deferred across all lockfile targets in monorepo - Extracted shared check_single_tool_provenance helper to deduplicate the provenance regression logic between apply_lock_result and check_provenance_regression Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Provenance-blocked entries are now included in the results as skipped so the summary counts add up to total_tasks. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Hyperfine Performance
|
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.3.10 x -- echo |
24.2 ± 0.9 | 23.4 | 34.8 | 1.00 |
mise x -- echo |
24.4 ± 0.8 | 23.5 | 32.9 | 1.01 ± 0.05 |
mise env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.3.10 env |
24.5 ± 0.9 | 23.1 | 30.7 | 1.00 |
mise env |
25.5 ± 1.0 | 23.7 | 34.1 | 1.04 ± 0.06 |
mise hook-env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.3.10 hook-env |
26.0 ± 1.3 | 23.8 | 33.2 | 1.00 |
mise hook-env |
26.9 ± 0.9 | 24.3 | 31.1 | 1.03 ± 0.06 |
mise ls
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.3.10 ls |
25.4 ± 0.9 | 23.1 | 30.2 | 1.00 |
mise ls |
26.3 ± 1.2 | 24.1 | 35.3 | 1.04 ± 0.06 |
xtasks/test/perf
| Command | mise-2026.3.10 | mise | Variance |
|---|---|---|---|
| install (cached) | 159ms | 158ms | +0% |
| ls (cached) | 89ms | 89ms | +0% |
| bin-paths (cached) | 92ms | 92ms | +0% |
| task-ls (cached) | 891ms | 860ms | +3% |

Summary
mise lockand the auto-lock path (duringmise install/mise use), and hard-fails in both cases.Key design decisions
LockfileToolentries only havelock_platformsfor the platform where installation ran; checking other platforms would cause false positives.github:to another backend (e.g.,aqua:).github:jdx/usage@1.6.0 has no provenance verification on linux-x64, but github:jdx/usage@1.5.0 had github-attestationsTest plan
mise run test:e2e test_lockfile_provenance_upgrade— verifiesmise lockerrors when provenance is lost (2s)🤖 Generated with Claude Code
Note
Medium Risk
Changes lockfile update and auto-lock flows to hard-fail on certain GitHub tool upgrades, which can block installs/locks and may surface in monorepos; logic is new and touches core lockfile write paths.
Overview
Adds provenance-regression detection for
github:backend tools: if upgrading to a newer version would remove previously-recorded provenance for the current platform, the operation is blocked with an error that cites the prior verified version.Applies this check in both
mise lock(per-resolution apply) and the install-time auto-lock/update paths, while deferring errors until after lockfiles are written so unaffected entries/lockfiles are still saved. Includes a new E2E test (test_lockfile_provenance_upgrade) assertingmise lockfails with a supply-chain warning when provenance is lost.Written by Cursor Bugbot for commit 7801020. This will update automatically on new commits. Configure here.