Skip to content

fix(swift): record the target distro in lockfile entries - #11299

Merged
jdx merged 2 commits into
mainfrom
claude/mise-discussion-11295-c559e9
Jul 25, 2026
Merged

jdx merged 2 commits into
mainfrom
claude/mise-discussion-11295-c559e9

Conversation

@jdx

@jdx jdx commented Jul 25, 2026 •

Copy link
Copy Markdown
Owner

Reported in #11295.

The problem

Swift publishes a different Linux tarball per distro (ubuntu24.04, fedora39, ubi9, amazonlinux2, …), but nothing about the distro reached the lockfile — entries were keyed by a bare linux-x64 with no options. Two bugs followed:

  1. Cross-distro checksum failures. An entry written on Ubuntu matched exactly on Fedora (same key, both option-free), so the Ubuntu checksum was verified against the Fedora tarball. The error named the downloaded filename and two digests with nothing to suggest a distro mismatch.

  2. mise lock reported success while writing nothing. core:swift implements no resolve_lock_info, so it fell through to resolve_lock_info_fallback, which returns an all-None PlatformInfo. That's Ok, so the run counted it as an update, but set_platform_info drops empty info — ✓ Updated 2 platform entries (0 skipped) over an untouched lockfile. With an entry already present, the empty info merged as "keep everything", silently preserving the previous distro's checksum. Changing swift.platform therefore left a project where mise lock wouldn't re-lock and mise install rejected the artifact the setting selected.

The fix

core:erlang already had this problem — its precompiled builds are per-distro — and solved it with a precompiled_os lockfile option. Swift now does the same:

  • swift_platform option on core:swift lock entries. Entries are matched on options exactly, so a Fedora machine no longer matches the Ubuntu entry, and changing swift.platform produces a new entry instead of reusing a checksum for a different artifact.

  • resolve_lock_info records the URL each entry describes, so mise lock writes something meaningful. swift.org publishes no checksum sidecar (only a detached .sig), so a checksum still can't be resolved without downloading the ~1 GB toolchain — it's filled in at install. Locking a musl target now errors rather than recording a URL that doesn't exist.

  • Target-aware URL construction, so cross-platform locking stops labeling another machine's platform with the host's distro. A non-current target falls back to Ubuntu, the only distro with Linux arm64 builds.

  • Legacy entries (written before the distro was recorded) keep their version pin but have their artifact data ignored, so upgrading neither drops an existing pin nor asserts a checksum for an unknown distro. They're also excluded from option rekeying, which would otherwise stamp the local distro's name onto a foreign artifact's checksum.

  • mise lock accounting: a resolution that wrote no entry counts as skipped, not as an update. This applies to any backend that returns the empty fallback.

  • Checksum mismatch errors name the lock entry the expectation came from — platform key, options, and locked URL:

    Failed to install aqua:mikefarah/yq@4.44.3: lockfile entry for aqua:mikefarah/yq@4.44.3 on linux-x64 locks https://github.com/mikefarah/yq/releases/download/v4.44.3/yq_linux_amd64: Checksum mismatch for file …
    

Before / after

The discussion's second repro (swift.platform = "ubi9", mise lock swift --platform linux-x64,linux-arm64) previously produced a lockfile with no platform entries at all. Now:

[[tools.swift]]
version = "6.3.1"
backend = "core:swift"

[tools.swift.options]
swift_platform = "ubi9"

[tools.swift."platforms.linux-arm64"]
url = "https://download.swift.org/swift-6.3.1-release/ubi9/swift-6.3.1-RELEASE/swift-6.3.1-RELEASE-ubi9-aarch64.tar.gz"

[tools.swift."platforms.linux-x64"]
url = "https://download.swift.org/swift-6.3.1-release/ubi9/swift-6.3.1-RELEASE/swift-6.3.1-RELEASE-ubi9.tar.gz"

Starting from an Ubuntu-written lockfile and pinning ubi9, mise lock now creates a separate ubi9 entry with the right URL and leaves the old entry untouched, instead of silently keeping the ubuntu24.04 checksum.

Testing

  • 6 new unit tests in src/plugins/core/swift.rs (distro options per target, empty options off Linux, URL resolution for a foreign target, musl rejection, Ubuntu fallback).
  • New e2e/lockfile/test_lockfile_swift_distro — covers the distro option, re-locking after changing swift.platform, and a legacy entry keeping its version pin. Locking swift resolves URLs only, so the test never downloads the toolchain.
  • Full unit suite (1922 tests) and all 44 non-slow e2e/lockfile tests pass; mise run lint clean.

Note

Migration is one-directional but recoverable: an existing option-free swift entry keeps pinning its version, and the first install on each machine writes a distro-labeled entry with the correct checksum. The old entry is preserved rather than rewritten, since there's no way to tell which distro it came from.

🤖 Generated with Claude Code


Note

Medium Risk
Changes lockfile matching, install checksum verification, and Swift download URL resolution across platforms; behavior is well-tested but affects reproducible installs for Swift on Linux.

Overview
Fixes Swift lockfile behavior on Linux where every distro shared the same linux-x64 key, so checksums from one distro were verified against another distro’s tarball.

Swift lock entries now carry a swift_platform option (e.g. ubuntu24.04, fedora39, ubi9) and are matched on options exactly, so each distro gets its own entry when swift.platform changes. resolve_lock_info records distro-specific download URLs (HEAD-checked; missing pairs like ubi9 arm64 are skipped; musl fails instead of locking a bogus URL). URL building is target-aware for cross-platform mise lock, with a Ubuntu fallback for foreign Linux targets; swift.platform no longer leaks into macOS/Windows URLs.

Legacy option-free Swift entries still pin the version but drop checksum/URL via without_artifact_data() and skip legacy option rekeying (lockfile_options_are_host_specific). mise lock counts only entries that actually wrote data (apply_lock_result returns bool); checksum errors name the lock entry (options + URL).

Docs and an e2e test cover multi-entry lockfiles and distro changes.

Reviewed by Cursor Bugbot for commit 5e04e13. Bugbot is set up for automated code reviews on this repo. Configure here.

Summary by CodeRabbit

  • New Features

    • Swift lockfiles now distinguish Linux distributions, selecting the correct platform-specific artifact when switching between distributions.
    • Existing lockfiles can be upgraded while preserving pinned Swift versions and refreshing distribution-specific artifact data.
    • Lock entries now provide clearer artifact identity and checksum-related error details.
  • Documentation

    • Added guidance and examples for tools with multiple lockfile entries for the same version but different artifact options.
  • Bug Fixes

    • Improved lock progress reporting to reflect entries actually written rather than attempted operations.

Swift publishes a different Linux tarball per distro (`ubuntu24.04`,
`fedora39`, `ubi9`, `amazonlinux2`, …), but nothing about the distro reached
the lockfile: entries were keyed by a bare `linux-x64` with no options. An
entry written on Ubuntu therefore matched exactly on Fedora, and its checksum
was verified against the Fedora tarball — a mismatch no mise command could
resolve, since `mise lock` wrote nothing for `core:swift` and silently kept the
old distro's checksum when an entry already existed.

- `core:swift` now reports the distro as a lockfile option (`swift_platform`),
  the same way `core:erlang` records `precompiled_os`, so each distro gets its
  own entry and changing `swift.platform` produces a new one instead of reusing
  a checksum for a different artifact.
- `core:swift` resolves lock info, so `mise lock` records the URL each entry
  describes rather than writing nothing. swift.org publishes no checksum
  sidecar, only a detached signature, so the checksum is still filled in at
  install time. Locking a musl target now fails instead of recording a URL that
  doesn't exist.
- Swift's URL construction is target-aware, so cross-platform locking no longer
  labels another machine's platform with the host's distro. A target that isn't
  the current machine falls back to Ubuntu — the only distro with Linux arm64
  builds.
- An entry written before the distro was recorded keeps its version pin but has
  its artifact data ignored, so existing lockfiles neither lose their pin nor
  assert a checksum for an unknown distro.
- `mise lock` reports resolutions that wrote no entry as skipped instead of
  counting them as updates. A backend that can't resolve metadata without
  installing returns empty info, which is `Ok` but produces no entry — that
  read as "✓ 2 platform entries (0 skipped)" over an untouched lockfile.
- Checksum mismatches now name the lock entry the expectation came from,
  including its options and locked URL, so a distro mismatch is visible in the
  message instead of looking like a corrupt download.

Reported in #11295

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 25, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Swift lockfiles now record distro-specific artifact options, distinguish exact host entries, support legacy version-only entries, improve artifact verification metadata, and report only written lock entries. Tests and documentation cover distro switching and fallback behavior.

Changes

Swift lockfile identity

Layer / File(s) Summary
Swift target-aware artifact contract
src/plugins/core/swift.rs
Swift URL generation, distro option recording, target-specific lock metadata, musl rejection, and related tests were updated.
Lockfile application and legacy matching
src/lockfile.rs, src/toolset/tool_request.rs
Lockfile application reports whether data was written, and host-specific backends can synthesize option-specific entries from legacy version-only records without reusing artifact data.
Per-platform artifact verification
src/backend/mod.rs
Checksum and size metadata are read and stored per platform, with lock-entry identity added to verification errors.
Lock command validation and documentation
src/cli/lock.rs, e2e/lockfile/test_lockfile_swift_distro, docs/dev-tools/mise-lock.md
Lock progress counts written entries, while regression tests and documentation cover distro-specific Swift entries and legacy fallback.
Estimated code review effort: 4 (Complex) ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant ToolRequest
  participant Lockfile
  participant SwiftPlugin
  User->>ToolRequest: lock Swift for target
  ToolRequest->>SwiftPlugin: resolve lockfile options
  SwiftPlugin-->>ToolRequest: swift_platform and target URL
  ToolRequest->>Lockfile: find exact or legacy entry
  Lockfile-->>ToolRequest: selected version and platform data
  ToolRequest->>SwiftPlugin: verify artifact
  SwiftPlugin-->>Lockfile: checksum and size metadata
Loading

Possibly related PRs

  • jdx/mise#11255: Both update lockfile version resolution and prefix-pinning plumbing.
  • jdx/mise#11272: Both modify lockfile platform artifact identity and provenance handling.

Poem

A bunny hops through Swift’s lock,
With distro tags around the clock.
Old pins shed their artifact coat,
New host entries keep versions afloat.
Checksums bloom where platforms meet—
A tidy lockfile, soft and sweet.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 is concise, specific, and accurately captures the main Swift lockfile change.

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.

@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 c189dbb. Configure here.

Comment thread src/plugins/core/swift.rs Resolved
@greptile-apps

greptile-apps Bot commented Jul 25, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR makes Swift lockfile entries distro-aware and improves lock resolution behavior.

  • Records the selected Linux distribution as a Swift lockfile option.
  • Builds and validates artifact URLs for the requested target platform.
  • Preserves legacy version pins while discarding artifact metadata of unknown origin.
  • Counts only lock resolutions that actually wrote data as updates.
  • Adds clearer checksum mismatch context, documentation, and regression coverage.

Confidence Score: 5/5

The PR appears safe to merge.

The previous target URL issue is resolved because Linux distro pins are no longer applied to macOS or Windows targets, and constructed artifact URLs must pass an HTTP status check before they can be recorded; no blocking failure remains.

Important Files Changed

Filename Overview
src/plugins/core/swift.rs Makes Swift artifact selection target-aware, isolates distro-specific lock entries, and validates URLs before recording them; the previously reported target URL corruption is fixed.
src/lockfile.rs Adds safe legacy-entry fallback and reports whether lock resolution contributed data.
src/backend/mod.rs Adds host-specific lock-option handling and richer checksum mismatch context.
src/toolset/tool_request.rs Enables legacy option-free fallback only for backends declaring host-specific artifact options.
src/cli/lock.rs Counts and reports only platform entries that were actually written.
e2e/lockfile/test_lockfile_swift_distro Covers distro-specific Swift locking, relocking after a platform change, unsupported artifacts, and legacy version pins.

Reviews (2): Last reviewed commit: "fix(swift): apply the distro pin only to..." | Re-trigger Greptile

Comment thread src/plugins/core/swift.rs Resolved

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
e2e/lockfile/test_lockfile_swift_distro (1)

39-58: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert the legacy checksum is actually dropped.

The legacy-entry case verifies the version pin survives and that a new distro entry appears, but nothing asserts the core regression — that the unattributable checksum isn't carried into the ubi9 entry. A assert_not_contains on that blake3 hash in the new entry (or on the whole file after relock) would pin the behavior this PR exists to fix.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@e2e/lockfile/test_lockfile_swift_distro` around lines 39 - 58, The lockfile
regression test around the legacy Swift entry must verify that the
unattributable legacy checksum is removed, not merely that the version and ubi9
entry remain. After relocking with `mise lock swift --platform linux-x64`, add
an assertion using the existing checksum hash and `assert_not_contains` against
the rewritten lockfile (or new entry), while preserving the current version and
distro-entry assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/plugins/core/swift.rs`:
- Around line 336-345: Update platform() so the Settings::get().swift.platform
override is applied only when target.os_name() is Linux; inspect the target
before returning the configured platform. Preserve the existing macOS and
Windows mappings and linux_platform fallback for non-overridden targets,
ensuring non-Linux targets never inherit the Linux distro setting.

---

Nitpick comments:
In `@e2e/lockfile/test_lockfile_swift_distro`:
- Around line 39-58: The lockfile regression test around the legacy Swift entry
must verify that the unattributable legacy checksum is removed, not merely that
the version and ubi9 entry remain. After relocking with `mise lock swift
--platform linux-x64`, add an assertion using the existing checksum hash and
`assert_not_contains` against the rewritten lockfile (or new entry), while
preserving the current version and distro-entry assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 6a7c57ef-0955-4d65-826a-5ded52960738

📥 Commits

Reviewing files that changed from the base of the PR and between 1a7abf7 and c189dbb.

📒 Files selected for processing (7)
  • docs/dev-tools/mise-lock.md
  • e2e/lockfile/test_lockfile_swift_distro
  • src/backend/mod.rs
  • src/cli/lock.rs
  • src/lockfile.rs
  • src/plugins/core/swift.rs
  • src/toolset/tool_request.rs

Comment thread src/plugins/core/swift.rs Resolved
`swift.platform` names a Linux distro build, but `platform()` returned it for
every target before inspecting the OS. With the setting configured repo-wide,
cross-platform locking built URLs like
`.../ubi9/swift-6.3.1-RELEASE-ubi9.pkg` for macOS — and since the distro option
is only recorded for Linux, that URL landed in an option-free entry every macOS
host would match.

Not every distro/arch pair is published either (`ubi9` has no aarch64 build),
and coverage shifts per release, so lock resolution now HEADs the artifact
rather than encoding a matrix that would go stale. A platform that isn't
published is reported as skipped instead of recording a URL that 404s.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@jdx

jdx commented Jul 25, 2026

Copy link
Copy Markdown
Owner Author

Addressed the review feedback in 5e04e13 — all three bots flagged the same real bug, thanks.

swift.platform leaking into non-Linux targets. Correct, and it was worse than cosmetic: because the distro option is only recorded for Linux, a bogus .../ubi9/swift-6.3.1-RELEASE-ubi9.pkg would land in an option-free macOS entry that every macOS host matches. platform() now inspects the target OS first and only consults the setting for Linux targets — the same shape as CodeRabbit's suggested diff. Covered by a new pinned_distro_does_not_apply_off_linux unit test.

Distro/arch pairs that aren't published (Greptile's second half — ubi9 has no aarch64 build). Which pairs swift.org publishes shifts per release, so rather than encode a matrix that would go stale, lock resolution now HEADs the artifact and reports the platform as skipped if it isn't there. Verified against the real service: a followed HEAD returns 404 for swift-6.3.1-RELEASE-ubi9-aarch64.tar.gz and 200 for the x64 build.

The discussion's repro with lockfile_platforms = ["linux-x64", "linux-arm64"] and swift.platform = "ubi9" now reports ✓ Updated 1 platform entries (1 skipped) and records only the x64 URL, instead of writing an arm64 URL that doesn't resolve. Also asserted in the e2e test.

I looked at recording size from the HEAD while I was there, but PlatformInfo::size is #[serde(skip_serializing)] by design ("preserved from existing lockfiles but not written"), so the HEAD is used purely as an existence check.

Unit suite 1923 passing, e2e/lockfile green, mise run lint clean.

This comment was generated by an AI coding assistant.

@jdx
jdx enabled auto-merge (squash) July 25, 2026 20:21
@github-actions

Copy link
Copy Markdown
Contributor

Hyperfine Performance

mise x -- echo

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.7.13 x -- echo 18.4 ± 2.6 16.4 34.8 1.00
mise x -- echo 19.2 ± 1.8 17.3 50.9 1.04 ± 0.18

mise env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.7.13 env 17.1 ± 0.7 15.8 20.0 1.00
mise env 17.8 ± 0.8 16.4 21.1 1.04 ± 0.06

mise hook-env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.7.13 hook-env 17.8 ± 0.8 16.4 21.6 1.00
mise hook-env 18.7 ± 0.9 17.3 23.1 1.05 ± 0.07

mise ls

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.7.13 ls 15.1 ± 0.7 13.9 18.8 1.00
mise ls 15.8 ± 0.8 14.4 20.3 1.05 ± 0.07

xtasks/test/perf

Command mise-2026.7.13 mise Variance
install (cached) 153ms 165ms -7%
ls (cached) 57ms 58ms -1%
bin-paths (cached) 59ms 62ms -4%
task-ls (cached) 126ms 129ms -2%

@jdx
jdx merged commit df9ec24 into main Jul 25, 2026
35 checks passed
@jdx
jdx deleted the claude/mise-discussion-11295-c559e9 branch July 25, 2026 20:38
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