fix(github): skip attestations on non-default api_url#9486
Conversation
GitHub artifact attestations are only served by https://api.github.com. GHE Server doesn't implement the endpoint, so attempts always fail and users had to set MISE_GITHUB_ATTESTATIONS=false globally to install GHE tools — also weakening the default for github.com tools. Auto-skip attestation verification when a tool resolves to a custom api_url. SLSA verification (asset-based, not API-based) still runs.
Greptile SummaryThis PR adds an Confidence Score: 5/5Safe to merge — behavior for the default api.github.com is completely unchanged, and the GHE/custom-URL path now fails fast with a clear error instead of a misleading downgrade message. No P0 or P1 issues found. The No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[verify_attestations_or_slsa] --> B{GitLab or Forgejo?}
B -->|yes, locked| D[Error: not available for GitLab/Forgejo]
B -->|yes, unlocked| E[return Ok - None]
B -->|no| F[get api_url]
F --> G{api_url unsupported AND locked = github-attestations?}
G -->|yes| H[Error: clear message - re-run mise lock]
G -->|no| I{attestations_supported AND settings enabled AND not skip?}
I -->|yes| J[try_verify_github_attestations]
J -->|verified| K[return GithubAttestations]
J -->|failed| L[Error: verification failed]
J -->|not found| M{SLSA enabled AND not skip?}
I -->|no| M
M -->|yes| N[try_verify_slsa]
N -->|verified| O[return Slsa]
N -->|failed| P[Error: SLSA failed]
N -->|not found| Q{locked_provenance set?}
M -->|no| Q
Q -->|yes| R[Error: downgrade attack]
Q -->|no| S[return Ok - None]
Reviews (3): Last reviewed commit: "refactor(github): thread api_url through..." | Re-trigger Greptile |
…url mismatch Address review feedback on #9486: - attestations_supported now trims a trailing slash, so a hand-written api_url = "https://api.github.com/" still resolves correctly. - When a lockfile records github-attestations but the configured api_url doesn't serve them, surface a clear error pointing at the configuration change instead of falling through to the generic "downgrade attack" path.
There was a problem hiding this comment.
Code Review
This pull request updates the GitHub backend to skip artifact attestation verification when a custom API URL is used, as GitHub Enterprise Server does not support the attestations endpoint. The changes include a new helper function attestations_supported, integration of this check into the verification logic, and updated documentation. Feedback suggests refactoring the api_url calculation to avoid redundant lookups and string allocations by passing the URL directly to helper methods.
| let skip_slsa = locked_provenance.as_ref().is_some_and(|l| !l.is_slsa()); | ||
|
|
||
| // If the lockfile expects github-attestations but the configured api_url | ||
| // doesn't support them (e.g. GHE Server), surface a clear, actionable |
There was a problem hiding this comment.
Per review: pass api_url into try_verify_github_attestations and try_verify_slsa so it's resolved once in the caller rather than re-derived from tv.request.options() inside each helper.
|
@gemini-code-assist this is already addressed in 7869c21 — This comment was generated by an AI coding assistant. |
|
Thank you for the clarification, jdx. You are absolutely right—my review was based on an earlier version of the code. I have re-examined the current implementation in commit 7869c21, and the approach of resolving |
Hyperfine Performance
|
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.4.28 x -- echo |
20.4 ± 1.0 | 18.7 | 26.9 | 1.00 |
mise x -- echo |
20.9 ± 1.4 | 19.0 | 28.7 | 1.03 ± 0.09 |
mise env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.4.28 env |
20.2 ± 1.2 | 18.6 | 26.6 | 1.00 ± 0.08 |
mise env |
20.1 ± 1.1 | 18.6 | 26.6 | 1.00 |
mise hook-env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.4.28 hook-env |
20.3 ± 1.1 | 18.7 | 27.6 | 1.00 |
mise hook-env |
21.1 ± 1.6 | 19.2 | 28.6 | 1.04 ± 0.10 |
mise ls
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.4.28 ls |
21.7 ± 1.4 | 20.0 | 30.5 | 1.00 |
mise ls |
22.5 ± 1.7 | 20.5 | 33.8 | 1.03 ± 0.10 |
xtasks/test/perf
| Command | mise-2026.4.28 | mise | Variance |
|---|---|---|---|
| install (cached) | 124ms | 127ms | -2% |
| ls (cached) | 74ms | 74ms | +0% |
| bin-paths (cached) | 78ms | 81ms | -3% |
| task-ls (cached) | 740ms | 735ms | +0% |
### 🚀 Features - **(conda)** graduate conda backend out of experimental by @jdx in [#9544](#9544) - **(deps)** Add dart and flutter providers by @tjarvstrand in [#9505](#9505) - **(registry)** add neo4j by @mnm364 in [#9525](#9525) - **(registry)** add rustfs by @mnm364 in [#9530](#9530) - **(task)** support exclusion patterns in task sources by @jlarmstrongiv in [#9496](#9496) - **(vfox)** add stat function to lua file module by @esteve in [#9497](#9497) ### 🐛 Bug Fixes - **(backend)** flag regex prerelease versions by @jdx in [#9500](#9500) - **(backend)** mark -nightly/-canary/-experimental as prereleases by @jdx in [#9523](#9523) - **(backend)** suppress no-versions warning for unresolved-latest backends by @jdx in [#9548](#9548) - **(backend)** include dotnet prereleases from package flags by @jdx in [#9551](#9551) - **(backend)** scope PEP 440 prerelease detection to Python backends by @jdx in [#9558](#9558) - **(cargo)** Apply install_env during cargo install by @c22 in [#9502](#9502) - **(copr)** drop epel-9 chroots since rust >= 1.91 is unavailable by @jdx in [#9484](#9484) - **(github)** skip attestations on non-default api_url by @jdx in [#9486](#9486) - **(github)** retry ip allow list errors without auth by @risu729 in [#9506](#9506) - **(http)** update versions host tracking endpoint by @jdx in [#9527](#9527) - **(install)** don't warn for configured tools when version is passed via CLI by @jdx in [#9522](#9522) - **(install)** refresh latest before installing missing tools by @jdx in [#9545](#9545) - **(install)** don't cache nonexistent install paths by @jdx in [#9553](#9553) - **(lockfile)** don't propagate ad-hoc CLI overrides into the project lockfile by @jdx in [#9562](#9562) - **(plugin)** detect plugin types after cloning by @risu729 in [#9540](#9540) - **(release)** pass --no-git-checks to aube publish by @jdx in [#9483](#9483) - **(task)** convert PATH to MSYS Unix form when spawning POSIX shells on Windows by @JamBalaya56562 in [#9547](#9547) ### 📚 Documentation - **(contributing)** require popularity check for registry PRs by @jdx in [7bbeebe](7bbeebe) - **(watch)** update pitchfork domain to en.dev by @risu729 in [#9536](#9536) - document ghtkn GitHub token setup by @jdx in [#9546](#9546) - clarify registry backend acceptance policy by @jdx in [#9543](#9543) - Change exec command to use bash for variable echo by @kuboon in [#9567](#9567) ### 🧪 Testing - **(e2e)** run test-tool targets in parallel by @jdx in [#9564](#9564) - **(e2e)** run tests in parallel by @jdx in [#9563](#9563) - **(e2e)** bind-mount /tmp on disk and surface failed tests in CI summary by @jdx in [#9570](#9570) - **(tasks)** migrate test_task_help atask to usage field by @jdx in [#9549](#9549) ### 📦️ Dependency Updates - update fedora:45 docker digest to 8b838b3 by @renovate[bot] in [#9507](#9507) - update ghcr.io/jdx/mise:deb docker digest to f02194c by @renovate[bot] in [#9509](#9509) - update taiki-e/install-action digest to 7769b73 by @renovate[bot] in [#9512](#9512) - update ghcr.io/jdx/mise:alpine docker digest to 581f8a8 by @renovate[bot] in [#9508](#9508) - update rust crate ctor to v0.10.1 by @renovate[bot] in [#9515](#9515) - update ghcr.io/jdx/mise:rpm docker digest to a5c9655 by @renovate[bot] in [#9510](#9510) - update rust docker digest to a9cfb75 by @renovate[bot] in [#9511](#9511) - update rust crate age to v0.11.3 by @renovate[bot] in [#9514](#9514) - update rust crate jiff to v0.2.24 by @renovate[bot] in [#9516](#9516) - update dependency vitepress-plugin-tabs to ^0.9.0 by @renovate[bot] in [#9518](#9518) - update autofix-ci/action action to v1.3.4 by @renovate[bot] in [#9513](#9513) - update rust crate usage-lib to v3.2.1 by @renovate[bot] in [#9517](#9517) - update apple-actions/import-codesign-certs action to v7 by @renovate[bot] in [#9519](#9519) - update taiki-e/install-action digest to 51cd0b8 by @renovate[bot] in [#9531](#9531) - exclude taiki-e/install-action from renovate by @jdx in [#9532](#9532) - update rust crate blake3 to v1.8.5 by @renovate[bot] in [#9533](#9533) ### 📦 Registry - enable shellcheck on windows by @zeitlinger in [#9487](#9487) - add google-java-format by @zeitlinger in [#9488](#9488) - add expert ([aqua:expert-lsp/expert](https://github.com/expert-lsp/expert)) by @AlternateRT in [#9498](#9498) - update entry for checkmake by @eread in [#9504](#9504) - add systemctl-tui ([aqua:rgwood/systemctl-tui](https://github.com/rgwood/systemctl-tui)) by @2xdevv in [#9521](#9521) - add codon by @3w36zj6 in [#9538](#9538) - add tool yr (backend:github:VirusTotal/yara-x) by @adam-moss in [#9542](#9542) - add tool betterleaks (backend:aqua/betterleaks/betterleaks) by @adam-moss in [#9541](#9541) - add `git-filter-repo` by @garysassano in [#9550](#9550) - add umoci ([aqua:opencontainers/umoci](https://github.com/opencontainers/umoci)) by @2xdevv in [#9555](#9555) - add aqua backend for elixir-ls by @AlternateRT in [#9557](#9557) - deny inline backend options by @risu729 in [#9565](#9565) ### Chore - **(ci)** fail registry tests without summary by @jdx in [#9559](#9559) - **(ci)** use !cancelled() instead of always() for test-ci aggregator by @jdx in [#9569](#9569) - **(ci)** use namespace runners for ci jobs by @jdx in [#9561](#9561) - **(config)** deprecate shorthands_file setting by @risu729 in [#9534](#9534) - **(docs)** remove shrill.en.dev analytics script by @jdx in [#9539](#9539) - **(release)** replace bc with awk in release-plz star formatting by @jdx in [d7f177f](d7f177f) - bump hk to 1.44.3 by @jdx in [#9493](#9493) - invert CLAUDE.md/AGENTS.md so AGENTS.md is canonical by @jdx in [#9560](#9560) - set dev profile debug to 1 by @jdx in [#9572](#9572) ### New Contributors - @kuboon made their first contribution in [#9567](#9567) - @AlternateRT made their first contribution in [#9557](#9557) - @2xdevv made their first contribution in [#9555](#9555) - @adam-moss made their first contribution in [#9541](#9541) - @jlarmstrongiv made their first contribution in [#9496](#9496) - @tjarvstrand made their first contribution in [#9505](#9505)
Summary
https://api.github.com. GHE Server doesn't implement the endpoint, so verification always fails against a customapi_url.MISE_GITHUB_ATTESTATIONS=falseglobally, which also weakens the default for github.com tools (Non-global disable `MISE_GITHUB_ATTESTATIONS` for certain GHE hosts #9379).attestations_supported(api_url)helper and gates the three attestation paths on it (lock-time detection, lock-time crypto verification, install-time verification). SLSA verification (asset-based, not API-based) still runs on GHE.Behavior is unchanged for tools that resolve to
https://api.github.com(the default).Closes the question raised in #9379 (reply in thread).
Test plan
mise run lint-fixclean.🤖 Generated with Claude Code
Note
Medium Risk
Touches supply-chain verification and lockfile provenance enforcement paths; while the change is narrowly scoped, mistakes could incorrectly skip verification or change install behavior for GitHub-backed tools with custom
api_url.Overview
GitHub backend now gates artifact attestation detection and verification behind a new
attestations_supported(api_url)helper, so attestations are only attempted against the publichttps://api.github.comendpoint and automatically skipped for customapi_urlvalues (e.g. GHE).Lock/install provenance flow is updated to pass the resolved
api_urlthrough verification functions, emit a clearer error when a lockfile requires GitHub attestations but the configuredapi_urlcan’t serve them, and adds unit tests plus settings docs explaining the behavior.Reviewed by Cursor Bugbot for commit 7869c21. Bugbot is set up for automated code reviews on this repo. Configure here.