Skip to content

feat(install): download pinned versions from mise.jdx.dev with GitHub fallback - #14446

Merged
jdx merged 4 commits into
mainfrom
feat/install-sh-r2-first
Oct 14, 2026
Merged

jdx merged 4 commits into
mainfrom
feat/install-sh-r2-first

Conversation

@jdx

@jdx jdx commented Oct 14, 2026 •

Copy link
Copy Markdown
Owner

https://entire.io/gh/jdx/mise/trails/733

The install script (curl https://mise.run | sh, https://mise.jdx.dev/install.sh) used mise.jdx.dev only when installing the release built into the script. Any pinned MISE_VERSION came from GitHub Releases, which responds more slowly and adds a redirect before the download starts.

Now the release archive for every version comes from mise.jdx.dev first, and the script falls back to GitHub Releases when that download fails. Pinned versions are still always checked against checksums from GitHub Releases:

$ curl -fsSL https://mise.run | MISE_VERSION=v2024.12.0 sh
mise: installing mise...
mise: could not download from mise.jdx.dev, trying GitHub Releases
mise: installed successfully to ~/.local/bin/mise

The fallback is needed because older release folders are being pruned from mise.jdx.dev (#14445).

Behavior

  • Archive: downloaded from https://mise.jdx.dev/v<version>/<asset>. Any failure, including a 404 or a network error, retries the same asset from GitHub Releases.
  • Checksums never come from mise.jdx.dev. The script's built-in version uses the checksums embedded in the script, as before. Any other version is always checked against SHASUMS256.txt from GitHub Releases, wherever the archive came from, as it was before this PR. Because the checksum comes from a separate host, someone who compromised mise.jdx.dev could not serve a tampered archive together with a matching checksum.
  • Unverified archives are refused: the script uses only a well-formed SHA-256 line for exactly the downloaded file. If GitHub's SHASUMS256.txt cannot be fetched or has no such line, the script exits with no checksum found for <file>, refusing to install it unverified before extracting anything. There is no fallback to mise.jdx.dev's checksums. A failed check exits with checksum mismatch.
  • MISE_INSTALL_FROM_GITHUB=1: still downloads only from GitHub.
  • MISE_TARBALL_URL: unchanged. It applies only to the built-in version, uses the embedded checksums, and has no fallback.
  • Built-in version: the only change is the new GitHub fallback for the archive.

installing-mise.md now says where the script downloads archives from and where it gets checksums.

Effect on download stats

Pinned installs will download their archives from mise.jdx.dev, so the per-platform GitHub release-asset counts behind mise-versions.jdx.dev/stats will drop unless jdx/mise-versions starts counting mise.jdx.dev (R2) downloads. Only SHASUMS256.txt will still come from GitHub. That mise-versions change is a separate PR that is still in progress. I recommend merging this after that one lands.

Validation

  • scripts/test-install-release-age.py (run by scripts/test-standalone.sh in CI) gains offline tests. They run install_mise against a stubbed curl that serves real tarballs, and they cover:

    • a pinned version downloaded from mise.jdx.dev and verified against GitHub's SHASUMS256.txt
    • falling back to GitHub when the archive returns 404
    • mise.jdx.dev serving a tampered archive with a matching checksum of its own: the install fails, and mise.jdx.dev's SHASUMS256.txt is never requested
    • GitHub's SHASUMS256.txt unreachable or missing the asset: the install fails without falling back to mise.jdx.dev
    • empty embedded checksums and a hash mismatch
    • failing when both hosts fail
    • MISE_INSTALL_FROM_GITHUB
    • the built-in version
    • MISE_TARBALL_URL

    All tests pass under bash's sh and dash. The download tests also pass under BusyBox ash with BusyBox awk, sha256sum and tar (python:3.12-alpine).

  • I rendered the script with scripts/render-install.sh, passed it through shellcheck, and ran it against the real hosts on macOS arm64:

    • v2026.1.0 came from mise.jdx.dev and was verified against GitHub's checksums.
    • v2025.1.0 (tar.gz, missing from mise.jdx.dev) and v2024.12.0 (no folder on mise.jdx.dev) fell back to GitHub.
    • MISE_INSTALL_FROM_GITHUB=1 used only GitHub.
    • An unpinned install of the latest release came from mise.jdx.dev and used the embedded checksums.

    All of these installs worked.

  • The wget fallback path is not exercised by these tests.

AI-assisted — Tool: Claude Code; model: anthropic/claude-opus-5-5; version: unavailable.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Improvements
    • The installer now verifies downloaded archives before extracting them, using embedded checksums for the current release and GitHub-provided checksums for other versions.
    • Downloads prefer mise.jdx.dev and fall back to GitHub Releases when the mirror is unavailable. Set MISE_INSTALL_FROM_GITHUB=1 to use GitHub Releases only.
    • Installation stops if a checksum is missing or the archive fails verification.
  • Documentation
    • Updated installation guidance to explain download sources and checksum verification.

… fallback

install.sh now fetches every release archive and its SHASUMS256.txt from
mise.jdx.dev first and falls back to GitHub Releases when that fails,
e.g. because an older release is no longer hosted there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Entire-Checkpoint: 01M4XK7E2W90H2NGGTKWMK00KZ
@coderabbitai

coderabbitai Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository YAML (base), Central YAML (inherited), Organization UI (inherited)
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: f67b6988-44c5-42a4-a969-2674dbe36ee4
📥 Commits

Reviewing files that changed from the base of the PR and between 20bec44 and 2c9bf00.

📒 Files selected for processing: 3
  • docs/installing-mise.md
  • packaging/standalone/install.envsubst
  • scripts/test-install-release-age.py

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 2 remain after this review.

📝 Walkthrough

The installer now prefers mise.jdx.dev for release downloads and can fall back to GitHub Releases. It checks archives against embedded or GitHub-hosted checksums before extraction. Documentation and offline tests cover source selection, fallback, and checksum failures.

Changes: Installer download and verification

Layer / File(s) Summary
Download and checksum helpers
packaging/standalone/install.envsubst
The installer builds GitHub and mirror URLs, retrieves checksum manifests, matches exact archive filenames, and returns download failures to the caller.
Source selection and verified installation
packaging/standalone/install.envsubst, docs/installing-mise.md, scripts/test-install-release-age.py
The installer selects a primary download source and fallback, then checks the archive before extraction. The documentation and offline tests cover source selection, checksums, and failure cases.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant Installer
  participant mise.jdx.dev
  participant GitHubReleases as GitHub Releases
  participant shasum
  participant Extractor
  Installer->>mise.jdx.dev: Request archive unless GitHub-only mode applies
  alt Mirror download fails
    Installer->>GitHubReleases: Request fallback archive
  end
  Installer->>GitHubReleases: Request SHASUMS256.txt for non-current versions
  Installer->>shasum: Verify archive against its exact checksum entry
  shasum-->>Installer: Return verification result
  Installer->>Extractor: Extract archive after successful verification
Loading
Merge Risk: ⚪ Minimal · up to 2c9bf

The inspected download and verification paths provide no identified reason to delay merging after normal checks.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 17 functions across 1 files. (2 skipped: 2… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: pinned-version downloads now use mise.jdx.dev with GitHub fallback.
Full details: Docstring Coverage

Explanation

Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 17 functions across 1 files. (2 skipped: 2 unsupported.)

  • Fix all pre-merge checks with AI
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[High impact] The PR appears safe to merge; no new actionable issues remain.

Summary

The installer tries mise.jdx.dev for release archives and falls back to GitHub Releases when the download fails.

  • The install script tries mise.jdx.dev before GitHub for release archives.
  • The installer checks each archive against a valid SHA-256 checksum for that file.

Reviews (4) · Last reviewed commit: "fix(install): always verify pinned versi..." · Reviewed by Greptile

Comment thread scripts/test-install-release-age.py Resolved
…sset

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Entire-Checkpoint: 01M4XKJ5X2QF3YHKXM62GF6GNN

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit d916142. Configure here.

Comment thread packaging/standalone/install.envsubst Resolved
jdx and others added 2 commits October 14, 2026 11:33
…ed archive

The installer now selects the exact SHA-256 line for the downloaded file
and errors out before extracting anything when no host provides one,
instead of relying on how shasum/sha256sum -c treat empty input.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Entire-Checkpoint: 01M4XM5CK21YYXCEQKRR8ZYJ46
Archives still download from mise.jdx.dev first with a GitHub fallback, but
SHASUMS256.txt for versions other than the built-in one now always comes from
GitHub Releases, with no fallback to mise.jdx.dev. A compromise of the
mise.jdx.dev bucket alone can no longer serve a matching archive and checksum.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Entire-Checkpoint: 01M4XNYA3SCVV6S333B6GB3N4T
@jdx
jdx merged commit 8b0429b into main Oct 14, 2026
56 of 59 checks passed
@jdx
jdx deleted the feat/install-sh-r2-first branch October 14, 2026 17:54
@github-actions

Copy link
Copy Markdown
Contributor

Instruction counts

Nothing was compared, and so nothing was gated. No series appears on both sides: either the base has no measurements recorded, or the two were measured on different runner classes, which are deliberately not comparable — counts shift between machine types by more than a real regression does.

New, nothing to compare against: env on jdx-perf-v1-ubuntu24.04-x64-mise-rust1.97.1-img5263c143, hook-env on jdx-perf-v1-ubuntu24.04-x64-mise-rust1.97.1-img5263c143, ls on jdx-perf-v1-ubuntu24.04-x64-mise-rust1.97.1-img5263c143, registry on jdx-perf-v1-ubuntu24.04-x64-mise-rust1.97.1-img5263c143, startup on jdx-perf-v1-ubuntu24.04-x64-mise-rust1.97.1-img5263c143

Only instruction counts gate. Wall clock is shown for context — on identical hardware it moves 4-20% run to run.

Measured by tak — instruction-counted CLI benchmarks, stored in this repository's git notes.

2c9bf00e3db2 vs 20bec44a2491 · measured on the runner, not pushed to the history.

mise-en-dev added a commit that referenced this pull request Oct 15, 2026
<!-- entire-trail-link-start -->
https://entire.io/gh/jdx/mise/trails/726
<!-- entire-trail-link-end -->

### 🚀 Features

- **(bootstrap)** add --upgrade to upgrade packages and tools by @jdx in
[#14433](#14433)
- **(env)** add --paths to list the PATH entries mise manages by @jdx in
[#14429](#14429)
- **(install)** download pinned versions from mise.jdx.dev with GitHub
fallback by @jdx in [#14446](#14446)

### 🐛 Bug Fixes

- **(aqua)** read GitHub-hosted aqua registries from
raw.githubusercontent.com by @jdx in
[#14470](#14470)
- **(backend)** build packslip after versions_host_applies was removed
by @jdx in
[8bdf9ae](8bdf9ae)
- **(backend)** resolve packslip prefixes like `latest` by @jdx in
[#14467](#14467)
- **(bootstrap)** render incoming direction for ufw interface rules by
@jdx in [#14480](#14480)
- **(dotfiles)** show planned file actions before the apply prompt by
@jdx in [#14430](#14430)
- **(dotfiles)** speed up flaky objects_at test by @jdx in
[#14439](#14439)
- **(dotfiles)** capture changed files of copy-mode groups with dot add
--changed by @jdx in [#14436](#14436)
- **(exec)** ask mise-versions for GitHub releases when auto-installing
from exec and shims by @jdx in
[#14458](#14458)
- **(github)** stop falling back to api.github.com when mise-versions
misses by @jdx in [#14460](#14460)
- **(github)** read the checksum-mismatch hint's digest from
mise-versions by @jdx in
[#14481](#14481)
- **(github)** list git tags from mise-versions instead of
api.github.com by @jdx in
[#14461](#14461)
- **(github)** verify attestations from mise-versions without
api.github.com fallbacks by @jdx in
[#14469](#14469)
- **(lock)** ignore the host's implicit compile default for other lock
platforms by @jdx in [#14432](#14432)
- **(lock)** download artifacts for provenance checks from github.com,
not the API by @jdx in [#14465](#14465)
- **(oci)** require root for apt bootstrap packages and show dpkg output
on failure by @jdx in [#14447](#14447)
- **(pipx)** preserve uv graph locking during global upgrades by
@wislertt in [#14426](#14426)
- **(ruby)** look up the latest ruby-build release through mise-versions
by @jdx in [#14471](#14471)
- **(self-update)** read mise releases from mise-versions and download
from github.com by @jdx in
[#14464](#14464)
- **(shim)** allow a few repeated fallback handoffs in one process by
@jdx in [#14475](#14475)
- **(upgrade)** leave lazy tools that are not installed to their first
run by @ryanrhughes in [#14422](#14422)
- **(upgrade)** skip version lookups for lazy tools a bare upgrade
leaves alone by @jdx in [#14444](#14444)
- avoid false "stack limit reached" on musl builds by @jdx in
[#14450](#14450)

### 📚 Documentation

- recommend committing mise.lock so CI and Docker skip version lookups
by @jdx in [#14453](#14453)

### ⚡ Performance

- **(backend)** take release tags from the versions host instead of
listing or guessing them by @jdx in
[#14442](#14442)
- **(backend)** read the registry tool's version list for an explicit
backend arg by @jdx in [#14459](#14459)
- **(backend)** stop re-downloading what packslip resolution already
verified by @jdx in [#14466](#14466)
- **(github)** reuse mirrored attestations and skip mise-versions for
asset-less latest releases by @jdx in
[#14443](#14443)
- **(github)** list releases and tags from mise-versions' whole lists by
@jdx in [#14477](#14477)
- **(install)** skip refetching version lists a cached copy already
answers by @jdx in [#14457](#14457)
- **(install)** reuse cached version lists for the tool's release-age
window by @jdx in [#14484](#14484)
- **(install)** keep the versions index and pipx's latest release for
the release-age window by @jdx in
[#14485](#14485)
- **(outdated)** resolve `latest` without refetching the version list by
@jdx in [#14456](#14456)
- **(outdated)** resolve many registry tools with one request to the
mise-versions index by @jdx in
[#14473](#14473)
- **(python)** list python versions from mise-versions instead of
cloning pyenv by @jdx in
[#14455](#14455)
- **(versions-host)** send install tracking and python lists to static
assets by @jdx in [#14441](#14441)

### 📦️ Dependency Updates

- bump jactionlint to 2.2.0 and mbx to 1.24.0 by @jdx in
[#14448](#14448)

### 📦 Registry

- install native-sdk from npm so the native command works by @jdx in
[#14431](#14431)
- add gdal (conda:libgdal-core) by @ivan-ivkovic in
[#14440](#14440)

### Ci

- prune unused release folders from the mise.jdx.dev CDN bucket by @jdx
in [#14445](#14445)
- check R2 credentials on every prune run by @jdx in
[#14451](#14451)
- stop aube-lock from re-committing on Cargo-only Renovate PRs by @jdx
in [#14482](#14482)

### Security

- **(deps)** update rustls to 0.23.46 by @jdx in
[#14434](#14434)
- **(task)** require trust before rendering a remote task file by
@JamBalaya56562 in [#14416](#14416)

### New Contributors

- @ivan-ivkovic made their first contribution in
[#14440](#14440)

## 📦 Aqua Registry Updates

### New Packages (2)

- [`btwld/fvm`](https://github.com/btwld/fvm)
- [`tailscale/tailcat`](https://github.com/tailscale/tailcat)

### Updated Packages (1)

- [`k1LoW/tbls`](https://github.com/k1LoW/tbls)
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