Skip to content

fix(aqua): keep the lock-time artifact download out of TEMP - #12064

Merged
jdx merged 4 commits into
jdx:mainfrom
JamBalaya56562:fix/aqua-lock-download-outside-temp
Aug 16, 2026
Merged

jdx merged 4 commits into
jdx:mainfrom
JamBalaya56562:fix/aqua-lock-download-outside-temp

Conversation

@JamBalaya56562

@JamBalaya56562 JamBalaya56562 commented Aug 16, 2026 •

Copy link
Copy Markdown
Contributor

mise lock verifies provenance for the current platform by downloading the release artifact
and checking it cryptographically. That download goes to tempfile::tempdir() — under
TEMP — which makes the generated lockfile depend on where the machine points TEMP.

Found while sweeping Windows behaviour under a long TEMP on 2026.8.6 windows-x64.

What happens

<TEMP>\.tmpXXXXXX\<artifact filename> is the download target. Once that path reaches
MAX_PATH the download fails:

> mise lock
mise WARN  lock-time provenance verification failed for jqlang/jq,
           will be verified at install time: 指定されたパスが見つかりません。 (os error 3)

mise lock still exits 0, and the lockfile is still written — but the provenance line for
the current platform is gone from it. Same project, same command, only the length of TEMP
differs
:

 [tools.jq."platforms.windows-x64"]
 checksum = "sha256:a6fc67fe…"
 url = "https://github.com/jqlang/jq/releases/download/jq-1.8.2/jq-windows-amd64.exe"
 url_api = "https://api.github.com/repos/jqlang/jq/releases/assets/453012788"
-provenance = "github-attestations"

The cross-platform entries are unaffected: lock-time verification only runs for the current
platform, so the others keep the provenance they got from registry metadata.

Measurement

jq-windows-amd64.exe is 20 characters and the scratch directory adds \.tmpXXXXXX\, so the artifact path is TEMP + 32. The threshold
was predicted from that and then measured — Windows 11 26200, LongPathsEnabled=0:

TEMP length artifact path provenance in mise.lock
31 (default) 63 recorded
210 242 recorded
230 262 dropped
250 282 dropped

The threshold moves with the artifact's filename, so it is different for every tool.

Nothing else in mise is affected. With TEMP at 250, install, reshim,
doctor --json, cache clear, ls and upgrade --dry-run all exit 0. This is the only
path that puts a release artifact in TEMP.

Why this is the fix

mise already owns a configurable place for exactly this file: install downloads the artifact
to MISE_DOWNLOADS_DIR via tv.download_path(), under a per-tool path its own cleanup owns. The lock-time download is the same artifact
from the same URL, and it was the only one going somewhere else. Pointing it at
MISE_CACHE_DIR/lock-provenance takes the lockfile's
contents out of the environment's hands.

It is still a TempDir removed on drop — this changes where the scratch lives, not how
long. Reusing the downloaded artifact at install time would be a real improvement (today it
is fetched twice) but is a behaviour change, so it is deliberately left out.

How bad was it

Mild, and this PR does not change that part — measured, not assumed:

  • with no provenance in the lockfile, has_lockfile_integrity is false, so install takes
    the verify_provenance branch rather than trusting the lockfile. Verified end to end:
    installing from the degraded lockfile logs verify GitHub artifact attestations →
    GitHub attestations verified.
  • the missing line is restored by that first install.

So there is no verification gap. What was actually wrong is that a committed artifact's
contents varied by machine
— a lockfile written on a box with a deep TEMP differs by one
line from the same lockfile written anywhere else, and the difference bounces back on the
next install.

Tests

  • Unit (src/backend/aqua.rs) — lock_time_download_dir() returns a directory under
    MISE_CACHE_DIR/lock-provenance. Cheap, no network, and it is the property the fix is about.
  • e2e-win/lock_temp_independence.Tests.ps1 — runs mise lock twice, once with an
    ordinary TEMP and once with a 230-character one, and requires the two lockfiles to be
    identical. The control run is also asserted to contain provenance, so the comparison
    cannot pass vacuously if lock ever stopped recording it at all.

Notes

  • No local build was run: cargo fmt --all only. cargo test and windows-e2e are left to
    CI.
  • Existing e2e/lockfile/* tests drive mise lock --platform "$PLATFORM"; this change moves
    where the scratch directory is created and nothing about what is written.

Summary by CodeRabbit

Bug Fixes

  • Improved mise lock reliability when temporary-directory paths are unusually long on Windows.
  • Lockfile generation now remains consistent across different temporary-directory configurations.
  • Lock-time verification uses a stable cache location for temporary downloads.
  • Temporary verification files are cleaned up more reliably and validated against Windows path limits.

Tests

  • Added Windows end-to-end coverage for long temporary paths and consistent lockfile generation.

Follow-up after review

The scratch first went under MISE_DOWNLOADS_DIR, reasoning only about where install puts the same
artifact. jdx pointed out the part that reasoning missed: the two directories are swept by different
things. Install's copy lands under a per-tool path its own cleanup owns; this one is a .tmpXXXXXX
at the root, owned by nothing — TempDir covers the ordinary path and neither mise cache clear
nor the per-tool download cleanup covers the rest, so a crash or a failed delete would strand it
indefinitely.

It is now MISE_CACHE_DIR/lock-provenance, in its own commit so the earlier review still applies to
what it reviewed. The unit test moved with it.

@coderabbitai

coderabbitai Bot commented Aug 16, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

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: Pro Plus

Run ID: fe6ea312-b8b2-4652-994c-782fdffd99d6

📥 Commits

Reviewing files that changed from the base of the PR and between 8a60147 and 83faea0.

📒 Files selected for processing (1)
  • src/backend/aqua.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/backend/aqua.rs

Included review availability: Your plan includes up to 10 reviews per rolling hour; 5 remain after this review.


📝 Walkthrough

Walkthrough

The Aqua backend stores lock-time provenance downloads under the configured cache directory and validates Windows path limits. A Windows end-to-end test compares lockfiles generated with normal and excessively long TEMP and TMP paths.

Changes

Lock temporary-directory independence

Layer / File(s) Summary
Cache-based scratch directory
src/backend/aqua.rs
Lock-time provenance verification uses cache-based scratch directories. Windows validation includes the downloader sidecar and reports MISE_CACHE_DIR when the path is too long. Tests cover cache placement and path diagnostics.
Windows lock validation
e2e-win/lock_temp_independence.Tests.ps1
The test preserves environment variables, runs mise lock with normal and long TEMP and TMP paths, verifies provenance, and compares lockfiles.

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

Merge Risk: ⚪ Minimal · up to 83fae

The change keeps lock-time artifact verification in mise’s cache instead of TEMP, preventing lockfile contents from varying with the machine’s TEMP path. No actionable merge-blocking risk remains beyond normal checks and review.

Possibly related PRs

  • jdx/mise#11948: Both modify Windows Pester tests that preserve and restore process environment variables.

Sequence Diagram(s)

sequenceDiagram
  participant LockWorkflow
  participant AquaBackend
  participant CacheDirectory
  participant Downloader
  LockWorkflow->>AquaBackend: Verify lock-time provenance
  AquaBackend->>CacheDirectory: Create lock-provenance scratch directory
  AquaBackend->>Downloader: Download verification artifacts
  Downloader-->>AquaBackend: Return artifacts
Loading

Poem

A rabbit checks each lock with care,
While provenance rests in cache lair.
Long temp paths no longer sway,
Matching lockfiles lead the way.
Hop, hop, verified.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: moving Aqua lock-time artifact downloads out of TEMP.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.

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 Aug 16, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR moves Aqua lock-time provenance downloads from the process temporary directory into a sweepable cache directory and adds Windows path-length diagnostics.

  • Adds Windows end-to-end coverage proving lockfile output is independent of TEMP.
  • Adds cache-location and path-length-hint unit tests.
  • Keeps failed lock-time verification as a warning followed by install-time verification.

Confidence Score: 4/5

The PR should not merge until deep MISE_CACHE_DIR values no longer cause lock-time verification to remove provenance from generated lockfiles.

The move fixes TEMP dependence, but the independently configurable cache root remains part of every scratch path; when Windows rejects a generated path, the error branch still clears provenance and writes a machine-dependent lockfile. The author’s reply says the issue was fixed by adding a diagnostic, but the current code provides the concrete residual counterexample: it still treats the path failure as a warning and assigns provenance to None.

Files Needing Attention: src/backend/aqua.rs

Important Files Changed

Filename Overview
src/backend/aqua.rs Moves provenance scratch downloads under MISE_CACHE_DIR and adds diagnostics, but deep cache paths can still cause verification failure and remove provenance.
e2e-win/lock_temp_independence.Tests.ps1 Adds focused Windows coverage showing that long TEMP paths no longer change generated lockfiles.

Reviews (6): Last reviewed commit: "fix(aqua): report the scratch length aft..." | Re-trigger Greptile

Comment thread src/backend/aqua.rs Resolved
@JamBalaya56562
JamBalaya56562 marked this pull request as ready for review August 16, 2026 20:05
@JamBalaya56562
JamBalaya56562 marked this pull request as draft August 16, 2026 20:18
@JamBalaya56562
JamBalaya56562 force-pushed the fix/aqua-lock-download-outside-temp branch from ddee104 to 6ddbd3f Compare August 16, 2026 20:18
@JamBalaya56562
JamBalaya56562 marked this pull request as ready for review August 16, 2026 20:47

jdx commented Aug 16, 2026

Copy link
Copy Markdown
Owner

Could you put this scratch directory under a dedicated cache path such as MISE_CACHE_DIR/lock-provenance instead of directly under MISE_DOWNLOADS_DIR?

These artifacts are disposable and are not reused by installation. TempDir cleans them up during ordinary execution, but cleanup is best-effort: a crash, abort, or deletion failure can leave the randomly named directory behind. A root-level .tmpXXXXXX under the persistent downloads directory is not covered by mise cache clear or the normal per-tool download cleanup, so it could remain indefinitely. Putting it under the cache keeps the download independent of TEMP while allowing any orphaned directories to be removed by normal cache clearing/pruning.

AI-assisted — Tool: Codex; model: OpenAI/GPT-5; version: unavailable.

@JamBalaya56562
JamBalaya56562 marked this pull request as draft August 16, 2026 21:00
@JamBalaya56562
JamBalaya56562 force-pushed the fix/aqua-lock-download-outside-temp branch from 6ddbd3f to 4685094 Compare August 16, 2026 21:16
@JamBalaya56562

Copy link
Copy Markdown
Contributor Author

Done in 4685094, as its own commit so the review already on this branch still applies to what it reviewed. The branch is also rebased onto current main.

You are right about the orphan, and the part I had not thought through is that the two directories are swept by different things. I moved this to MISE_DOWNLOADS_DIR reasoning only about where install puts the same artifact, which made the two halves of the job agree — but install's copy lands under a per-tool path that its own cleanup owns, while this one is a .tmpXXXXXX at the root, owned by nothing. TempDir covers the ordinary path and nothing covers the rest.

It is now MISE_CACHE_DIR/lock-provenance. That keeps what the PR is actually for — the lockfile no longer depends on how deep the machine points TEMP — while leaving any orphan somewhere mise cache clear reaches.

The unit test moved with it: it pinned the scratch under MISE_DOWNLOADS_DIR, and now pins it under the cache path. I dropped a second assertion I had drafted for it (!starts_with(DOWNLOADS)), because it would misfire on any configuration that nests the cache under the downloads directory rather than catching a real regression.

@JamBalaya56562
JamBalaya56562 marked this pull request as ready for review August 16, 2026 21:17
Comment thread src/backend/aqua.rs Resolved
@JamBalaya56562
JamBalaya56562 force-pushed the fix/aqua-lock-download-outside-temp branch from 4685094 to 35b5aca Compare August 16, 2026 21:34
Comment thread src/backend/aqua.rs Resolved
`mise lock` verifies provenance for the current platform by downloading the
release artifact and checking it cryptographically. That download went to
`tempfile::tempdir()`, i.e. under TEMP, which makes the generated lockfile depend
on where the machine points TEMP.

On Windows it does so visibly. The download lands at
`<TEMP>\.tmpXXXXXX\<artifact filename>`, and once that reaches MAX_PATH it fails:

    mise WARN  lock-time provenance verification failed for jqlang/jq,
               will be verified at install time: (os error 3)

`mise lock` still exits 0, but the `provenance` line for the current platform is
gone from mise.lock. Measured with jq 1.8.2 (`jq-windows-amd64.exe`, so the
artifact path is TEMP + 35), varying only the length of TEMP:

    TEMP=210  ->  path 245, provenance recorded
    TEMP=230  ->  path 265, provenance dropped
    TEMP=250  ->  path 285, provenance dropped

The threshold moves with the artifact's filename, so it differs per tool.

Nothing else in mise is affected: install, reshim, doctor, cache clear, ls and
upgrade --dry-run all succeed with TEMP at 250. This is the only path that puts a
release artifact in TEMP — install already downloads to `MISE_DOWNLOADS_DIR`.

Point the lock-time download at `MISE_DOWNLOADS_DIR` too. It is still a `TempDir`
removed on drop, so this changes where the scratch lives, not how long.

The consequences were mild and are unchanged by this: with no `provenance` in the
lockfile, `has_lockfile_integrity` is false, so install runs the real verification
rather than trusting the lockfile, and the line is restored. What was actually
wrong is that a committed artifact's contents varied by machine.
Follow-up to review. The scratch directory went under MISE_DOWNLOADS_DIR because
that is where install puts the same artifact — but this copy is verified and
thrown away, never reused, and `TempDir` cleanup is best-effort. A crash, an
abort or a failed delete strands a randomly named `.tmpXXXXXX` at the root of a
persistent directory that nothing sweeps: not `mise cache clear`, not the
per-tool download cleanup.

`MISE_CACHE_DIR/lock-provenance` keeps the download independent of TEMP, which is
what this PR is for, while leaving any orphan somewhere ordinary cache clearing
collects it.

Added as its own commit rather than folded into the first, so the review already
on this branch still applies to what it reviewed.
…ot fit

Follow-up to Greptile's review, which is right and whose earlier version I had
pushed back on for a reason that does not transfer here.

Moving the scratch out of TEMP removed one environment variable from the answer,
not the arithmetic. MISE_CACHE_DIR is configurable too, and the longest path in
this operation is not the artifact but the download's own sidecar,
`.{filename}.mise-part.json`, written beside it by http::PartialDownload. Past
MAX_PATH that comes back as `os error 3`, the caller warns and clears provenance,
and the lockfile loses the entry for this platform.

The defence used against the same argument about MISE_DOWNLOADS_DIR was that
install writes a longer path under the same root and therefore fails first,
loudly. That does not hold for the cache: the two roots are independent.
Measured on 2026.8.6 with MISE_CACHE_DIR at 200 characters — `mise install` and
`mise lock` both exit 0 and provenance is recorded, so nothing else in mise
fails at that depth to hint at why.

So check the length before downloading and say what to change. This does not
turn `mise lock` into a failure: the caller already catches this and degrades to
install-time verification, so what changes is that the reason is legible and
names MISE_CACHE_DIR instead of being a bare OS error code.

Its own commit again, so the review already on this branch still applies to what
it reviewed.
@JamBalaya56562
JamBalaya56562 force-pushed the fix/aqua-lock-download-outside-temp branch from 35b5aca to 8a60147 Compare August 16, 2026 21:46
…ing before

The previous commit checked one path — the artifact's `.mise-part.json` sidecar —
before downloading. That is not enough, and Greptile was right to say so: the
same scratch directory later receives a checksum file, a provenance or signature
file, and each takes its name from a URL. A check on the first file passes while
a later, longer one does not, so the guard could be satisfied and verification
still fail with the lockfile quietly losing provenance.

Enumerating those files is the wrong shape. Annotate the failure instead: when
lock-time verification fails, append the scratch directory's length and name the
variable to shorten. That covers every file written there, including any added
later, because it reacts to what happened rather than predicting what will.

This still does not make `mise lock` fail — the caller already catches the error,
warns, and degrades to install-time verification. What changes is that the
warning carries a reason.

Also drops the local MAX_PATH: jdx#12058 merged, so `file::MAX_PATH` is the shared
one, as its body said it would be.
@JamBalaya56562
JamBalaya56562 force-pushed the fix/aqua-lock-download-outside-temp branch from 8a60147 to 83faea0 Compare August 16, 2026 22:09
@jdx
jdx merged commit fbcf199 into jdx:main Aug 16, 2026
30 checks passed
@JamBalaya56562
JamBalaya56562 deleted the fix/aqua-lock-download-outside-temp branch August 16, 2026 22:59
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.

2 participants