Skip to content

fix(env): uv venv in env_cache key to prevent cross directory leak#10217

Merged
jdx merged 3 commits into
jdx:mainfrom
Nagato-Yuzuru:fix/env-cache-venv-leak
Jun 4, 2026
Merged

fix(env): uv venv in env_cache key to prevent cross directory leak#10217
jdx merged 3 commits into
jdx:mainfrom
Nagato-Yuzuru:fix/env-cache-venv-leak

Conversation

@Nagato-Yuzuru

@Nagato-Yuzuru Nagato-Yuzuru commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

fix #4316

Problem

With env_cache enabled and python.uv_venv_auto active, a uv venv stays active after you leave the project directory: VIRTUAL_ENV (and the .venv/bin entry on PATH) persists in unrelated directories. It leaks into a long-lived shell it propagates to every child process.

Repro

Enable env caching with uv venv auto source (shell has mise activate):

# ~/.config/mise/config.toml
[settings]
env_cache = true
python.uv_venv_auto = "source"

A plain uv project: uv.lock + .venv, no local mise.toml:

$ cd ~/work/proj                 # has uv.lock + .venv
$ echo "$VIRTUAL_ENV"
/home/me/work/proj/.venv         # activated — correct
$ which python3
/home/me/work/proj/.venv/bin/python3         # activated — correct

$ cd ~/work/other                # no uv.lock, no venv
$ echo "$VIRTUAL_ENV"
                                 # expected: empty
/home/me/work/proj/.venv         # actual: still proj's venv
$ which python3
/your/system/python3                                 # expected: system python3
/home/me/work/proj/.venv/bin/python3         # activated — leak

VIRTUAL_ENV (and proj/.venv/bin on PATH) stays active after leaving the project. Since it's exported, it then propagates to every process spawned from that shell, until the cache TTL expires.

Disabling env_cache makes the venv deactivate correctly.

Cause

compute_env_cache_key() derives the key from the resolved config files (plus sibling mise.lock), tool versions, settings and the base PATH, but not from the uv.lock / .venv that python.uv_venv_auto discovers by walking up
from the current directory (uv_root()find_up("uv.lock")).

So two directories that resolve the same config files produce the same cache key even when only one of them contains a venv. On a cache hit mise returns the stored env and skips the uv_venv step entirely, so whichever directory
computed first wins for both:

  • enter proj/ (caches an env with the venv) → cd to a sibling → cache hit
    VIRTUAL_ENV leaks in;
  • enter a non-venv sibling first (caches an env without the venv) → cd proj/
    → cache hit → venv never activates.

cd/chpwd is not a cache-invalidation trigger, so the stale entry survives.

Fix

Mirroring theexisting mise.lock handling, so venv and non-venv directories no longer collide on one key. Add the uv venv (uv.lock + .venv) to the env_cache key.

Test

Add e2e test.

Summary by CodeRabbit

  • Bug Fixes

    • Fixed env caching to properly isolate uv-based virtual environments across directories, preventing incorrect environment sharing when multiple projects share the same configuration files.
  • Tests

    • Added end-to-end regression tests for Windows and Unix environments to verify virtual environment caching behavior.

@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f6095393-d066-4ea9-9f2e-abdd37d30622

📥 Commits

Reviewing files that changed from the base of the PR and between 7011751 and 46319ea.

📒 Files selected for processing (4)
  • e2e-win/env_cache_venv.Tests.ps1
  • e2e/env/test_env_cache_venv
  • src/toolset/toolset_env.rs
  • src/uv.rs

📝 Walkthrough

Walkthrough

This PR fixes an env-cache bug where directories sharing identical configuration files would incorrectly inherit cached virtual environment state. The fix extends cache key computation to include uv.lock and .venv modification times, ensuring cache invalidation when venv state changes. Cross-platform e2e tests validate the fix on Windows and Unix.

Changes

Env cache venv isolation

Layer / File(s) Summary
Cache key computation with uv venv inputs
src/uv.rs, src/toolset/toolset_env.rs
uv_root is promoted to crate-private scope. The cache key computation now includes uv.lock and .venv mtimes alongside config files and tool versions when uv_venv_auto sourcing is enabled, preventing cache collisions across directories sharing identical parent config.
Cross-platform e2e regression test coverage
e2e-win/env_cache_venv.Tests.ps1, e2e/env/test_env_cache_venv
Windows PowerShell and Unix Bash tests verify two scenarios: (1) a sibling directory without .venv does not inherit cached venv state from a directory that has one, and (2) clearing cache state does not let a cached non-venv entry suppress a sibling's own venv activation.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 A venv cache that's crisp and clean,
No venv leaks between machine!
Lock files and mtimes now in the key,
Each project's env stays private, you see.
Windows and Unix both sing the same tune! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% 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 clearly and specifically describes the main change: fixing an env_cache issue where uv venv state leaked across directories by including uv venv information in the cache key.
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.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@greptile-apps

greptile-apps Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a cache-key collision in compute_env_cache_key() that caused a uv virtual environment to leak across sibling directories when env_cache and python.uv_venv_auto = "source" were both enabled. The fix adds the uv.lock and .venv path+mtime to the cache key, mirroring the existing mise.lock handling, and exposes uv_root() as pub(crate) to avoid duplicating the find-up logic.

  • src/toolset/toolset_env.rs: When uv_venv_auto.should_source() is true, the resolved uv.lock and .venv paths (with their mtimes) are appended to the cache-key inputs. Directories without a uv.lock produce an empty slice, giving them a distinct key from a sibling that does have one.
  • src/uv.rs: uv_root() visibility widened from private to pub(crate).
  • Tests: Bash and PowerShell e2e regression tests cover both failure modes — venv leaking into a sibling, and a cached non-venv sibling suppressing the project venv.

Confidence Score: 5/5

Safe to merge — the change is surgical (one new block in the key computation, one visibility change) and both failure scenarios are covered by tests.

The cache-key change is minimal and correctly mirrors the existing mise.lock pattern. The condition guarding the new inputs (should_source()) is exactly the same condition used inside uv_venv() itself, so the key is always consistent with what the function would do. get_file_mtime handles directories correctly via std::fs::metadata, and the empty-vec path for non-venv directories ensures they get a distinct key without any extra bookkeeping. Both leak scenarios are exercised by the new e2e tests on Linux and Windows.

No files require special attention.

Important Files Changed

Filename Overview
src/toolset/toolset_env.rs Adds uv.lock + .venv path/mtime to the env cache key, mirroring the existing mise.lock handling, so venv and non-venv sibling directories no longer collide on one cache entry.
src/uv.rs Widens uv_root() visibility from private to pub(crate) so toolset_env.rs can call it for cache key computation without duplicating the find-up logic.
e2e/env/test_env_cache_venv Adds a bash e2e regression test covering both leak scenarios: venv persisting into a sibling, and a cached non-venv sibling suppressing a project's venv.
e2e-win/env_cache_venv.Tests.ps1 Windows Pester equivalent of the bash regression test, correctly using .venv\Scripts instead of .venv/bin.

Reviews (2): Last reviewed commit: "Update src/toolset/toolset_env.rs" | Re-trigger Greptile

Comment thread src/toolset/toolset_env.rs Outdated
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
@Nagato-Yuzuru

Copy link
Copy Markdown
Contributor Author

I don't have a Windows device, but it looks like it's been fixed. I'd appreciate it if someone could help me with some user testing.

@Nagato-Yuzuru Nagato-Yuzuru marked this pull request as ready for review June 4, 2026 06:57
Copilot AI review requested due to automatic review settings June 4, 2026 06:57

Copilot AI 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.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR fixes env-cache key collisions when python.uv_venv_auto auto-sources a uv virtualenv, preventing VIRTUAL_ENV from leaking (or being suppressed) across sibling directories that share the same resolved config inputs.

Changes:

  • Expose uv_root() within the crate so other modules can key off the discovered uv.lock root.
  • Include uv.lock / .venv (and their mtimes) in the env cache key computation when uv auto-source is enabled.
  • Add Unix and Windows E2E regression tests covering both “venv leaks to sibling” and “sibling suppresses venv” scenarios.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
src/uv.rs Makes uv_root() accessible to integrate uv discovery into other logic.
src/toolset/toolset_env.rs Adds uv venv inputs into cache-key computation to prevent cross-directory cache collisions.
e2e/env/test_env_cache_venv Adds Unix regression test asserting no uv venv leakage/suppression via env cache.
e2e-win/env_cache_venv.Tests.ps1 Adds Windows regression test for the same env-cache/uv-venv interaction.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/uv.rs
Comment on lines +77 to 79
pub(crate) fn uv_root() -> Option<PathBuf> {
file::find_up(dirs::CWD.as_ref()?, &["uv.lock"]).map(|p| p.parent().unwrap().to_path_buf())
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

find_up always returns a path ending in uv.lock, so parent() is never None

Comment on lines +22 to +25
@"
[settings]
python.uv_venv_auto = "source"
"@ | Out-File (Join-Path $script:TestRoot ".mise.toml")
@jdx jdx enabled auto-merge (squash) June 4, 2026 16:52
@jdx jdx merged commit c386bcc into jdx:main Jun 4, 2026
33 checks passed
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.

3 participants