Skip to content

fix(task): avoid remote resolution during task startup - #10571

Merged
jdx merged 4 commits into
mainfrom
codex/fix-activation-task-offline
Jun 23, 2026
Merged

jdx merged 4 commits into
mainfrom
codex/fix-activation-task-offline

Conversation

@jdx

@jdx jdx commented Jun 22, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • keep prefer-offline version resolution local for latest, rolling channels, npm semver ranges, and prefixes instead of falling through to remote metadata
  • make mise run build its initial task toolset in offline resolution mode; auto-install still re-resolves missing tools online when installation is actually needed
  • add regression coverage that hook-env, mise run --skip-tools, and task startup with auto-install disabled do not invoke github.credential_command for a github: latest tool with minimum_release_age

Tests

  • cargo fmt --check
  • cargo check --bin mise
  • mise run test:e2e e2e/cli/test_hook_env_prefer_offline_no_remote_versions e2e/tasks/test_task_skip_tools

Note

Medium Risk
Changes core version resolution and shell/task startup paths; wrong offline behavior could pin wrong versions or skip needed installs, but auto-install still re-resolves online when installation is required.

Overview
Shell activation and task runs no longer hit the network to resolve tool versions during startup. hook-env builds its toolset with ResolveOptions { offline: true }, and mise run does the same for the initial toolset after tasks resolve; missing tools can still be installed online when auto-install actually runs.

Prefer-offline resolution is tightened in tool_version.rs: CLI ToolSource::Argument requests are excluded from prefer-offline shortcuts, and when prefer-offline applies (without full offline), resolution stops at installed versions for latest, rolling channels, npm semver ranges in package.json, and prefix specs—avoiding fall-through to remote metadata (e.g. GitHub releases that would run github.credential_command).

E2E tests assert hook-env and mise run (with --skip-tools or auto_install = false) do not invoke a fake credential command for github:cli/cli@latest with minimum_release_age set.

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

Summary by CodeRabbit

  • Bug Fixes
    • Fixed mise run to resolve tool versions with offline-first behavior to avoid remote version metadata lookups and prevent credential command invocations during task startup.
    • Updated mise hook-env to build its toolset using offline resolve, reducing network dependence during hook activation.
  • Improvements
    • Refined “prefer offline” resolution to apply only for non-argument tool requests, improving latest, rolling channels, and semver-range handling.
  • Tests
    • Added end-to-end coverage ensuring credential commands are not invoked when offline is preferred and when tools are skipped during task runs.

@coderabbitai

coderabbitai Bot commented Jun 22, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds prefer-offline early-return fast paths to ToolVersion::resolve_version and resolve_prefix for latest, rolling-channel, npm semver-range, and prefix specs. Both hook-env and run commands now build their toolsets with ResolveOptions { offline: true } to skip remote version fetches. Two e2e tests verify that a fake GitHub credential command is never invoked under these offline or skip-tools code paths.

Changes

Offline Tool Resolution

Layer / File(s) Summary
Offline fast paths in ToolVersion resolution
src/toolset/tool_version.rs
Adds prefer_offline && !opts.latest_versions early returns in resolve_version for the latest, rolling-channel, and npm semver-range branches, and in resolve_prefix, each preferring installed versions or returning the raw spec to skip remote resolution.
Offline resolve wiring in hook-env and run
src/cli/hook_env.rs, src/cli/run.rs
Both commands now import ResolveOptions and ToolsetBuilder, then build toolsets with ResolveOptions { offline: true } instead of default resolution. Hook-env adjusts reference passing to support the new builder pattern.
E2E tests: no credential invocation under offline/skip-tools
e2e/cli/test_hook_env_prefer_offline_no_remote_versions, e2e/tasks/test_task_skip_tools
Sets up a fake GitHub credential command with a marker file in both tests; asserts the marker is absent after mise hook-env --force with latest version pin and after mise run [--skip-tools] nop-test with a github:cli/cli tool entry.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • jdx/mise#10423: Both PRs modify src/toolset/tool_version.rs rolling-channel resolution; this PR adds the prefer_offline fast path for rolling channels introduced in that PR.

Poem

🐇 Hop hop, no network calls today,
The credential command stays away!
prefer_offline guards the gate,
Installed versions seal our fate.
No remote fetch, no token chase —
The rabbit runs at offline pace! 🌿

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ 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%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: preventing remote resolution during task startup, which aligns with all modified files (hook_env.rs, run.rs, tool_version.rs) that implement offline-first resolution behavior.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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 c4deba3. Configure here.

Comment thread src/toolset/tool_version.rs Resolved
@greptile-apps

greptile-apps Bot commented Jun 22, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR prevents hook-env and mise run from hitting the network during startup by building their toolsets with offline: true, while auto-install still re-resolves missing tools online when needed. The prefer-offline resolution logic in tool_version.rs is extended with early-return fast paths for latest, rolling channels, npm semver ranges, and prefix specs, and ToolSource::Argument requests are explicitly excluded so explicit CLI tool args retain online resolution.

  • hook_env.rs switches from config.get_toolset() to an explicit ToolsetBuilder with offline: true, stopping credential-command invocations during shell activation.
  • run.rs applies the same offline resolve option to the initial toolset build for mise run, with install_missing_versions handling the online fallback for truly absent tools.
  • New E2E tests assert that neither hook-env nor mise run invoke github.credential_command when minimum_release_age is configured.

Confidence Score: 5/5

Safe to merge; the offline fast paths are logically correct and auto-install retains its online fallback for missing tools.

The core mechanism — forcing offline:true for the initial toolset build in hook-env and mise run, then letting install_missing_versions re-resolve online — is sound. The ToolSource::Argument carve-out correctly preserves online resolution for explicit CLI tool specs. No wrong-data or broken-contract issues were found.

No files require special attention; the tool_version.rs redundancies are cosmetic and carry no correctness risk.

Important Files Changed

Filename Overview
src/toolset/tool_version.rs Adds prefer-offline early-return paths for latest, rolling channels, npm semver ranges, and prefix specs; the latest branch has a redundant check and the npm range path calls list_installed_versions twice under prefer_offline.
src/cli/hook_env.rs Switches hook-env from config.get_toolset() to ToolsetBuilder with offline:true so shell activation never hits the network; ownership change from by-value to by-reference propagated consistently.
src/cli/run.rs Adds offline:true ResolveOptions to the mise run toolset build; auto-install still re-resolves missing tools online via install_missing_versions.
e2e/cli/test_hook_env_prefer_offline_no_remote_versions Adds regression coverage verifying that hook-env with minimum_release_age and a github:latest tool never invokes the github credential_command.
e2e/tasks/test_task_skip_tools Adds E2E coverage for mise run --skip-tools and mise run (with auto_install=false) verifying no credential_command is invoked during task startup when github:cli/cli@latest + minimum_release_age is configured.

Reviews (4): Last reviewed commit: "fix(toolset): satisfy prefer-offline cli..." | Re-trigger Greptile

@github-actions

github-actions Bot commented Jun 22, 2026 •

Copy link
Copy Markdown
Contributor

Hyperfine Performance

mise x -- echo

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.6.12 x -- echo 20.6 ± 1.1 18.1 26.0 1.00
mise x -- echo 21.1 ± 1.6 18.5 38.8 1.03 ± 0.09

mise env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.6.12 env 20.3 ± 1.0 17.9 24.2 1.00
mise env 20.9 ± 1.4 18.2 26.5 1.03 ± 0.09

mise hook-env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.6.12 hook-env 21.0 ± 1.3 18.3 25.8 1.00
mise hook-env 21.8 ± 1.4 19.1 26.8 1.04 ± 0.09

mise ls

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.6.12 ls 17.7 ± 1.1 15.2 22.1 1.00
mise ls 18.7 ± 0.8 16.6 21.8 1.06 ± 0.08

xtasks/test/perf

Command mise-2026.6.12 mise Variance
install (cached) 145ms 147ms -1%
ls (cached) 66ms 67ms -1%
bin-paths (cached) 74ms 76ms -2%
task-ls (cached) 131ms 133ms -1%

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/toolset/tool_version.rs (1)

378-420: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Close the no-installed-version fallthrough before remote resolution.

These fast paths only return when a local match exists. If nothing is installed, prefer_offline && !opts.latest_versions still falls through to remote metadata calls for latest, rolling channels, npm semver ranges, and prefixes; resolve_prefix also ignores global offline because it checks opts.offline instead of is_offline. Return the raw spec for these local-only modes after the installed-version check.

Suggested shape
-        let prefer_offline_without_offline = prefer_offline && !is_offline;
         let should_filter_installed_versions =
             opts.filters_installed_versions() && !is_offline && !prefer_offline;
 
         if v == "latest" {
-            if prefer_offline_without_offline
-                && !opts.latest_versions
-                && let Some(v) = backend.latest_installed_version(None)?
-            {
-                return build(v);
+            if prefer_offline && !opts.latest_versions {
+                if let Some(v) = backend.latest_installed_version(None)? {
+                    return build(v);
+                }
+                return build(v);
             }
             if prefer_offline
                 && !opts.latest_versions
                 && let Some(installed) = backend.latest_installed_channel_version(&v)
             {
                 return build(installed);
             }
+            if prefer_offline && !opts.latest_versions {
+                return build(v);
+            }
             if prefer_offline && !opts.latest_versions {
                 let installed_versions = backend.list_installed_versions();
                 if let Some(matches) =
                     crate::semver::npm_semver_range_filter(&installed_versions, &v)
                     && let Some(v) = matches.last()
                 {
                     return build(v.clone());
                 }
+                return build(v);
             }
         if prefer_offline
             && !opts.latest_versions
             && let Some(v) = backend.list_installed_versions_matching(prefix).last()
         {
             return Ok(Self::new(request, v.to_string()));
         }
+        if prefer_offline && !opts.latest_versions {
+            return Ok(Self::new(request, prefix.to_string()));
+        }
...
-        if opts.offline {
+        if is_offline {
             return Ok(Self::new(request, prefix.to_string()));
         }

Also applies to: 432-457, 473-516, 612-625

🤖 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 `@src/toolset/tool_version.rs` around lines 378 - 420, The "latest" version
resolution block is falling through to remote metadata calls even when in
local-only mode (prefer_offline_without_offline && !opts.latest_versions). After
the installed-version checks using backend.latest_installed_version(None)?, add
an early return of the raw spec value (v, which is "latest") if
prefer_offline_without_offline && !opts.latest_versions conditions are met but
no installed version was found. This prevents unnecessary remote resolution
attempts for local-only modes and should be applied similarly in the other
affected sections mentioned in the comment.
🤖 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.

Outside diff comments:
In `@src/toolset/tool_version.rs`:
- Around line 378-420: The "latest" version resolution block is falling through
to remote metadata calls even when in local-only mode
(prefer_offline_without_offline && !opts.latest_versions). After the
installed-version checks using backend.latest_installed_version(None)?, add an
early return of the raw spec value (v, which is "latest") if
prefer_offline_without_offline && !opts.latest_versions conditions are met but
no installed version was found. This prevents unnecessary remote resolution
attempts for local-only modes and should be applied similarly in the other
affected sections mentioned in the comment.

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Pro Plus

Run ID: 98fef5a3-428f-4b8e-88cc-dced771b6e96

📥 Commits

Reviewing files that changed from the base of the PR and between be92199 and 9c81ce2.

📒 Files selected for processing (2)
  • src/cli/hook_env.rs
  • src/toolset/tool_version.rs

@jdx
jdx merged commit 6f2243a into main Jun 23, 2026
34 checks passed
@jdx
jdx deleted the codex/fix-activation-task-offline branch June 23, 2026 18:28
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