Skip to content

fix(github): skip attestations on non-default api_url#9486

Merged
jdx merged 3 commits intomainfrom
claude/sharp-rubin-6bef66
Apr 30, 2026
Merged

fix(github): skip attestations on non-default api_url#9486
jdx merged 3 commits intomainfrom
claude/sharp-rubin-6bef66

Conversation

@jdx
Copy link
Copy Markdown
Owner

@jdx jdx commented Apr 30, 2026

Summary

  • GitHub artifact attestations are only served by https://api.github.com. GHE Server doesn't implement the endpoint, so verification always fails against a custom api_url.
  • Today users with GHE-hosted github backend tools have to set MISE_GITHUB_ATTESTATIONS=false globally, which also weakens the default for github.com tools (Non-global disable `MISE_GITHUB_ATTESTATIONS` for certain GHE hosts #9379).
  • This PR adds a small 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

  • Unit tests for the helper covering the default API and custom GHE/GitLab/Forgejo URLs.
  • mise run lint-fix clean.
  • Manual verification on a real GHE Server (not available in this environment).

🤖 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 public https://api.github.com endpoint and automatically skipped for custom api_url values (e.g. GHE).

Lock/install provenance flow is updated to pass the resolved api_url through verification functions, emit a clearer error when a lockfile requires GitHub attestations but the configured api_url can’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.

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-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 30, 2026

Greptile Summary

This PR adds an attestations_supported(api_url) helper that gates GitHub Artifact Attestation checks (lock-time detection, lock-time cryptographic verification, and install-time verification) behind a check that the api_url resolves to https://api.github.com. SLSA provenance verification (asset-based) continues to run for GHE/custom-URL tools. The implementation is clean: trim_end_matches('/') is used in the comparison so trailing-slash variants of the default URL still work, a clear early error is surfaced when a lockfile already records github-attestations provenance but the current api_url doesn't support them, and api_url is threaded through as a parameter to try_verify_github_attestations and try_verify_slsa (removing redundant re-computation). The targeted unit tests cover the default URL, trailing-slash normalization, and several custom-URL cases.

Confidence Score: 5/5

Safe 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 attestations_supported helper correctly normalises trailing slashes (addressing the prior review comment). The new early-error path for locked_provenance = github-attestations + unsupported api_url (addressing the prior outside-diff comment) is logically correct and well-placed before the generic downgrade guard. The api_url parameter refactor removes redundant get_api_url calls without changing semantics. Unit tests cover the key cases.

No files require special attention.

Important Files Changed

Filename Overview
src/backend/github.rs Adds attestations_supported helper with trailing-slash normalization, gates all three attestation paths on it, surfaces a clear error when locked provenance requires attestations but the api_url doesn't support them, and refactors api_url as a parameter to try_verify_github_attestations / try_verify_slsa to avoid redundant lookups.
settings.toml Documentation update for github_attestations setting to explain that attestations are automatically skipped for tools with a custom api_url; no logic changes.

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]
Loading

Reviews (3): Last reviewed commit: "refactor(github): thread api_url through..." | Re-trigger Greptile

Comment thread src/backend/github.rs
…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.
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 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.

Comment thread src/backend/github.rs
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
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The api_url is calculated here and then again inside try_verify_github_attestations and try_verify_slsa. While not a bug, it would be cleaner to calculate it once in verify_attestations_or_slsa and pass it down to the helper methods to avoid redundant option lookups and string allocations.

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.
@jdx
Copy link
Copy Markdown
Owner Author

jdx commented Apr 30, 2026

@gemini-code-assist this is already addressed in 7869c21api_url is resolved once in verify_attestations_or_slsa and passed as a &str parameter to both try_verify_github_attestations and try_verify_slsa; neither helper calls self.get_api_url(...) anymore. Looks like the review ran against the diff before that commit landed.

This comment was generated by an AI coding assistant.

@gemini-code-assist
Copy link
Copy Markdown
Contributor

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 api_url once and passing it as a parameter is indeed cleaner and more robust. The logic looks solid.

@jdx jdx enabled auto-merge (squash) April 30, 2026 13:14
@github-actions
Copy link
Copy Markdown

Hyperfine Performance

mise x -- echo

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%

@jdx jdx merged commit 0533ad2 into main Apr 30, 2026
51 of 53 checks passed
@jdx jdx deleted the claude/sharp-rubin-6bef66 branch April 30, 2026 13:49
mise-en-dev added a commit that referenced this pull request May 3, 2026
### 🚀 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)
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.

1 participant