Skip to content

fix(vfox): apply tools=true env to os.execute install hooks (#10282)#10432

Merged
jdx merged 1 commit into
jdx:mainfrom
JamBalaya56562:fix-vfox-os-execute-tools-env
Jun 14, 2026
Merged

fix(vfox): apply tools=true env to os.execute install hooks (#10282)#10432
jdx merged 1 commit into
jdx:mainfrom
JamBalaya56562:fix-vfox-os-execute-tools-env

Conversation

@JamBalaya56562

@JamBalaya56562 JamBalaya56562 commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #10282. When mise install installs several tools at once, a tools = true [env] var that depends on another tool — e.g. a gcloud + python setup:

[tools]
python = "3.13"
gcloud = { version = "latest", depends = ["python"] }

[env]
CLOUDSDK_PYTHON = { value = "{{ tools.python.path }}/bin/python3", tools = true }

— did not reach the dependent tool's install. Installing separately (mise install python then mise install gcloud) worked, but a combined mise install failed.

Root cause

Two interacting gaps:

  1. os.execute bypasses the sanitized env. vfox plugins that shell out via Lua os.execute (e.g. vfox-gcloud's install.sh) inherit mise's raw process env, ignoring the mise_env registry that cmd.exec applies. During a combined install that raw env still carried the stale CLOUDSDK_PYTHON rendered before python was installed ({{ tools.python.path }} was empty → /bin/python3), so install.sh used a nonexistent python and failed.
  2. tools = true values were never computed for the install. dependency_env resolves with full_env_without_tools, so tools = true [env] values weren't applied to the install environment at all.

The separate-install case only worked because the (activated) shell re-exported the now-correct CLOUDSDK_PYTHON between the two commands — something a single combined mise install process never does.

Fix

  • crates/vfox: route Lua os.execute through mise_env (env_clear + mise_env), matching cmd.exec. Factored the env application into a shared apply_mise_env helper. When mise_env is unset (i.e. not a mise-managed install) os.execute behaves exactly as stock, so the blast radius is limited to installs.
  • env resolution: a new ToolsFilter::ToolsOnlyVals selects tools = true value directives only. Toolset::tool_val_env resolves those against the full (installed) toolset and dependency_env merges them in best-effort (PATH untouched; errors fall back to the tool-less env). Env modules (PythonVenv/Module/Source/File/Path) are deliberately skipped so modules are never run on a partial toolset.

The full toolset (not the dependency toolset) is used for the value resolution because depends ordering installs the dependency first, but dependency_toolset only tracks backend/registry-declared deps, not user depends.

Tests

  • crates/vfox unit test: os.execute honors mise_env.
  • env_directive unit test: ToolsOnlyVals includes tools = true Vals and excludes tools = false vars and modules.
  • e2e e2e/backend/test_vfox_install_tools_env: a local vfox plugin whose PostInstall reads a tools = true var via os.execute (network-free, deterministic).

Notes / scope

  • Only os.execute is rerouted; io.popen (file-handle semantics) is left as a follow-up. vfox-gcloud uses os.execute.
  • This delivers the tools = true value (here CLOUDSDK_PYTHON, an absolute path). Putting a user-depends tool's bin on PATH during install is a separate concern (dependency_toolset doesn't track user depends) and not required for this report.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Improved Lua os.execute so shell execution uses the same sanitized mise_env environment as command execution.
    • Tool-related environment is now available in vfox plugin install hooks: only tools = true value directives are resolved, and PATH updates are intentionally avoided.
  • Tests

    • Added a Unix regression test asserting os.execute honors mise_env, including env_clear behavior for shell resolution.
    • Added an end-to-end backend test verifying tools = true env vars are readable inside plugin PostInstall hooks.

@coderabbitai

coderabbitai Bot commented Jun 14, 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
  • ✅ Review completed - (🔄 Check again to review again)

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 984a1dd9-c57b-43e9-be8e-55c2620e90ec

📥 Commits

Reviewing files that changed from the base of the PR and between 956f573 and b089cdb.

📒 Files selected for processing (5)
  • crates/vfox/src/lua_mod/cmd.rs
  • e2e/backend/test_vfox_install_tools_env
  • src/backend/vfox.rs
  • src/config/env_directive/mod.rs
  • src/toolset/toolset_env.rs
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/config/env_directive/mod.rs
  • src/backend/vfox.rs
  • e2e/backend/test_vfox_install_tools_env
  • src/toolset/toolset_env.rs
  • crates/vfox/src/lua_mod/cmd.rs

📝 Walkthrough

Walkthrough

Adds ToolsFilter::ToolsOnlyVals and Toolset::tool_val_env to resolve only tools=true plain env-value directives, wires the result into VfoxBackend::install_version_ (skipping PATH), and overrides Lua os.execute in the vfox module to apply the same mise_env registry environment that cmd.exec already used, validated by unit and e2e tests.

Changes

tools=true env propagation into vfox hooks

Layer / File(s) Summary
ToolsOnlyVals filter and load_post_env signature
src/config/env_directive/mod.rs, src/toolset/toolset_env.rs
Adds ToolsFilter::ToolsOnlyVals variant and filtering logic to select only tools=true plain Val directives. Extends load_post_env with a tools_filter parameter forwarded into EnvResolveOptions, and updates final_env to pass ToolsOnly explicitly.
Toolset::tool_val_env
src/toolset/toolset_env.rs
New public method builds a Tera tools context from installed tools, calls load_post_env with ToolsFilter::ToolsOnlyVals, and returns only resolved plain env-value pairs.
Vfox install env merge
src/backend/vfox.rs
VfoxBackend::install_version_ calls tool_val_env and merges non-PATH key/value pairs into cmd_env; resolution errors log a debug message and fall back to the original env.
Lua os.execute override and apply_mise_env helper
crates/vfox/src/lua_mod/cmd.rs
Ensures Lua global os table exists and replaces os.execute with a Rust implementation. Extracts apply_mise_env to centralize mise_env registry clearing and population (shared with cmd.exec); os_execute shells through the same path as cmd.exec.
Unit and e2e tests
src/config/env_directive/mod.rs, crates/vfox/src/lua_mod/cmd.rs, e2e/backend/test_vfox_install_tools_env
Unit test for ToolsOnlyVals correctness; Unix-only regression test asserting os.execute honors mise_env with env_clear; e2e bash test generating a vfox plugin with a PostInstall hook that writes a tools=true env var to a marker file via os.execute and asserts the resolved value.

Sequence Diagram

sequenceDiagram
  rect rgba(100, 180, 255, 0.5)
    Note over mise install,VfoxBackend: Install-time env resolution
    participant mise install
    participant VfoxBackend
    participant tool_val_env as Toolset::tool_val_env
    participant load_post_env
    mise install->>VfoxBackend: install_version_(ctx)
    VfoxBackend->>tool_val_env: ctx.ts.tool_val_env(config, base_env)
    tool_val_env->>load_post_env: ToolsFilter::ToolsOnlyVals
    load_post_env-->>tool_val_env: KEY→value pairs
    tool_val_env-->>VfoxBackend: EnvMap (no PATH)
    VfoxBackend->>VfoxBackend: merge into cmd_env
  end
  rect rgba(180, 100, 255, 0.5)
    Note over VfoxBackend,Shell: Hook execution via os.execute
    participant os_execute as Lua os.execute (Rust)
    participant apply_mise_env
    participant Shell
    VfoxBackend->>os_execute: PostInstall hook calls os.execute(cmd)
    os_execute->>apply_mise_env: apply_mise_env(lua, &mut cmd)
    apply_mise_env-->>os_execute: sanitized env applied
    os_execute->>Shell: spawn with mise_env
    Shell-->>os_execute: exit code
    os_execute-->>VfoxBackend: hook result
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 A hop through the env map, a patch to Lua's shell,
tools=true now rides the hook, and all works rather well.
ToolsOnlyVals filters neat, no PATH shall sneak along,
os.execute bows to mise — the registry's not wrong.
The bunny stamps the marker file: resolved-via-tools-env. 🌿

🚥 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 summarizes the main fix: applying tools=true environment variables to vfox os.execute install hooks, matching the core changes across all modified files.
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.

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


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

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

🧹 Nitpick comments (1)
src/backend/mod.rs (1)

2332-2343: ⚡ Quick win

Add diagnostics when full toolset resolution is skipped.

If config.get_toolset().await fails, dependency_env silently omits tools=true value injection, which makes this path hard to debug.

Suggested tweak
-        if let Ok(ts) = config.get_toolset().await {
-            match ts.tool_val_env(config, &env).await {
-                Ok(vals) => {
-                    for (k, v) in vals {
-                        if k.as_str() != env::PATH_KEY.as_str() {
-                            env.insert(k, v);
-                        }
-                    }
-                }
-                Err(e) => debug!("dependency_env: skipping tools=true value directives: {e:#}"),
-            }
-        }
+        match config.get_toolset().await {
+            Ok(ts) => match ts.tool_val_env(config, &env).await {
+                Ok(vals) => {
+                    for (k, v) in vals {
+                        if k.as_str() != env::PATH_KEY.as_str() {
+                            env.insert(k, v);
+                        }
+                    }
+                }
+                Err(e) => debug!("dependency_env: skipping tools=true value directives: {e:#}"),
+            },
+            Err(e) => debug!("dependency_env: failed to load full toolset for tools=true values: {e:#}"),
+        }
🤖 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/backend/mod.rs` around lines 2332 - 2343, The code silently skips
tools=true value injection when config.get_toolset().await fails without logging
any diagnostic information, making debugging difficult. Add error handling for
the failed case of config.get_toolset().await by adding an if let Err(e) clause
alongside the existing if let Ok(ts) clause to log a debug message with the
actual error details when toolset resolution fails, similar to how the error
case is already handled inside the match expression for ts.tool_val_env.
🤖 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.

Nitpick comments:
In `@src/backend/mod.rs`:
- Around line 2332-2343: The code silently skips tools=true value injection when
config.get_toolset().await fails without logging any diagnostic information,
making debugging difficult. Add error handling for the failed case of
config.get_toolset().await by adding an if let Err(e) clause alongside the
existing if let Ok(ts) clause to log a debug message with the actual error
details when toolset resolution fails, similar to how the error case is already
handled inside the match expression for ts.tool_val_env.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 44e60f24-efa2-45d9-8c45-00881afdf8ba

📥 Commits

Reviewing files that changed from the base of the PR and between ac6f430 and d356073.

📒 Files selected for processing (5)
  • crates/vfox/src/lua_mod/cmd.rs
  • e2e/backend/test_vfox_install_tools_env
  • src/backend/mod.rs
  • src/config/env_directive/mod.rs
  • src/toolset/toolset_env.rs

@greptile-apps

greptile-apps Bot commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Fixes a combined mise install failure where vfox plugins that shell out via Lua os.execute (not cmd.exec) never received tools=true env directives resolved against already-installed dependencies. The fix has two parts: routing os.execute through the mise_env Lua registry (matching cmd.exec), and computing tools=true value-only env directives at install time via a new ToolsOnlyVals filter.

  • crates/vfox/src/lua_mod/cmd.rs: Replaces Lua's os.execute with os_execute that calls apply_mise_env (factored from cmd.exec). Returns i64 consistent with the crate's lua51 mlua feature.
  • src/backend/vfox.rs: Calls ctx.ts.tool_val_env() after dependency_env and merges the result into cmd_env, excluding PATH to preserve dependency_env's ownership of path resolution.
  • src/config/env_directive/mod.rs + src/toolset/toolset_env.rs: Adds ToolsFilter::ToolsOnlyVals and Toolset::tool_val_env, which evaluate only plain Val directives marked tools=true — skipping modules that could fail on a partial toolset — and expose the resolved values for consumption by install_version_.

Confidence Score: 5/5

Safe to merge. Changes are tightly scoped to vfox install hooks and activate only when mise_env is set in the Lua registry — no effect on non-install code paths.

The two-part fix is internally consistent: the os.execute override correctly uses lua51 integer return semantics (confirmed by the crate's mlua feature flags), the new ToolsOnlyVals filter precisely excludes env modules to avoid partial-toolset errors, and ctx.ts is used instead of config.get_toolset() to avoid OnceCell re-entry. All call sites of the refactored load_post_env pass explicit filter values, unit tests cover the new filter and the mise_env registry application, and an e2e test validates the end-to-end install scenario without network access. Previously flagged issues were addressed in prior commits.

No files require special attention.

Important Files Changed

Filename Overview
crates/vfox/src/lua_mod/cmd.rs Adds apply_mise_env helper and os_execute override that routes Lua's os.execute through the mise_env registry, consistent with cmd.exec. Return type i64 is correct for the lua51 feature enabled by this crate; no semantic regression.
src/backend/vfox.rs Merges tool_val_env results into cmd_env before installation, surfacing tools=true value directives to install hooks. PATH exclusion is correct (case-insensitive on Windows). Uses ctx.ts to avoid OnceCell re-entry deadlock.
src/config/env_directive/mod.rs Adds ToolsOnlyVals filter variant that selects only tools=true Val directives, explicitly excluding modules/Path/Source/File. Filter logic and new unit test are correct.
src/toolset/toolset_env.rs Refactors load_post_env to accept an explicit tools_filter parameter, adds tool_val_env which evaluates only ToolsOnlyVals directives against the current toolset's tera map. All callers correctly pass ToolsFilter::ToolsOnly.
e2e/backend/test_vfox_install_tools_env End-to-end regression test that verifies a tools=true env var is available inside a vfox PostInstall hook via os.execute. The heredoc escaping is correct: $MARKER expands at write time, \$MISE_TEST_TOOLS_VAR is kept literal for runtime expansion.

Reviews (5): Last reviewed commit: "fix(vfox): apply tools=true env to os.ex..." | Re-trigger Greptile

Comment thread src/backend/mod.rs Outdated
Comment thread crates/vfox/src/lua_mod/cmd.rs Outdated
Comment thread e2e/backend/test_vfox_install_tools_env
@JamBalaya56562 JamBalaya56562 force-pushed the fix-vfox-os-execute-tools-env branch 3 times, most recently from 734e27e to 956f573 Compare June 14, 2026 11:03
@JamBalaya56562

Copy link
Copy Markdown
Contributor Author

Pushed a fix for the e2e failures (they were a real deadlock introduced by this PR, not flaky CI).

Root cause: the first revision injected the tools = true value env in Backend::dependency_env, which calls config.get_toolset(). But dependency_env is also invoked from backends' version listing (npm/go _list_remote_versions, vfox _list_remote_versions at vfox.rs:90) — and mise install runs on a fresh toolset without initializing config's toolset OnceCell first. So the first dependency_env call started the OnceCell init (Toolset::resolve), whose version-listing re-entered dependency_envconfig.get_toolset() on the same in-flight OnceCell → deadlock, surfacing as resolve tool version list ... timed out after 20.00s across npm/go/vfox.

Fix: dependency_env is reverted to its original form (no get_toolset). The tools = true value injection now happens in VfoxBackend::install_version_ using ctx.ts (the install toolset, which already has the dependency installed and is not the shared OnceCell), so it runs only at install time and can't re-enter version listing.

Verified locally on Windows with an isolated single vfox plugin: mise install now completes in ~4s (previously hung to the 20s timeout), and the tools = true value is correctly read by the plugin's os.execute hook.

@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

🤖 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/backend/vfox.rs`:
- Line 165: The comparison `k.as_str() != crate::env::PATH_KEY.as_str()` is
case-sensitive, but on Windows environment variables are case-insensitive. This
means if a user defines `path` (lowercase) in their config, it will not be
properly excluded like `PATH` would be. Replace the case-sensitive string
comparison with case-insensitive comparison using `.eq_ignore_ascii_case()`
method to ensure all variants of the PATH environment variable name are
correctly excluded regardless of case, particularly on Windows systems.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 21bfc10b-f822-453b-9597-6775774ce590

📥 Commits

Reviewing files that changed from the base of the PR and between 734e27e and 956f573.

📒 Files selected for processing (5)
  • crates/vfox/src/lua_mod/cmd.rs
  • e2e/backend/test_vfox_install_tools_env
  • src/backend/vfox.rs
  • src/config/env_directive/mod.rs
  • src/toolset/toolset_env.rs
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/config/env_directive/mod.rs
  • src/toolset/toolset_env.rs
  • e2e/backend/test_vfox_install_tools_env
  • crates/vfox/src/lua_mod/cmd.rs

Comment thread src/backend/vfox.rs Outdated
When `mise install` installs several tools at once, a `tools = true` `[env]`
var that depends on another tool — e.g.
`CLOUDSDK_PYTHON = "{{ tools.python.path }}/bin/python3"` for a gcloud + python
setup — did not reach the dependent tool's install. Two gaps caused it:

1. vfox plugins that shell out via Lua `os.execute` (e.g. vfox-gcloud's
   install.sh) inherited mise's raw process env, ignoring the sanitized
   `mise_env` that cmd.exec applies. In a combined install that raw env still
   carried the *stale* value rendered before the dependency was installed.
2. `dependency_env` resolved with `full_env_without_tools`, so `tools = true`
   `[env]` values were never computed for the install at all.

Fix:
- crates/vfox: route Lua `os.execute` through `mise_env` (env_clear + mise_env),
  matching cmd.exec; falls back to stock behavior when `mise_env` is unset, so
  only mise-managed installs are affected.
- Resolve `tools = true` *value* directives against the full (installed) toolset
  and merge them into `dependency_env` (best-effort). Env *modules* are skipped
  via the new `ToolsFilter::ToolsOnlyVals` so modules are never run on a partial
  toolset, and any resolution error falls back to the tool-less env.

Separate installs worked only because a re-activated shell re-exported the
resolved value between commands; this makes the combined install behave the same.

Tests: a vfox os.execute unit test, a ToolsOnlyVals filter unit test, and an
e2e (e2e/backend/test_vfox_install_tools_env) where a vfox plugin's PostInstall
reads a tools=true var via os.execute.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@JamBalaya56562 JamBalaya56562 force-pushed the fix-vfox-os-execute-tools-env branch from 956f573 to b089cdb Compare June 14, 2026 11:22
@jdx jdx merged commit 0e90dbc into jdx:main Jun 14, 2026
34 checks passed
@JamBalaya56562 JamBalaya56562 deleted the fix-vfox-os-execute-tools-env branch June 14, 2026 22:35
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