Skip to content

chore: harden uv parser, cache panics, test isolation, and temp dir cleanup#410

Merged
karthiknadig merged 2 commits intomainfrom
chore/fix-397-402-403-401-hardening
Apr 6, 2026
Merged

chore: harden uv parser, cache panics, test isolation, and temp dir cleanup#410
karthiknadig merged 2 commits intomainfrom
chore/fix-397-402-403-401-hardening

Conversation

@karthiknadig
Copy link
Copy Markdown
Member

Summary

Batch of four hardening and code quality improvements identified during coverage gap analysis.

Changes

Fixes #397, Fixes #402, Fixes #403, Fixes #401

@karthiknadig karthiknadig requested a review from Copilot April 6, 2026 19:04
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 6, 2026

Performance Report (Linux) ➖

Metric PR (P50) PR (P95) Baseline (P50) Delta Change
Server Startup 1ms 1ms 1ms 0ms 0%
Full Refresh 77ms 775ms 70ms 7ms 10.0%

Results based on 10 iterations. P50 = median, P95 = 95th percentile.


Legend
  • 🚀 Significant speedup (>100ms faster)
  • ✅ Faster than baseline
  • ➖ No significant change
  • 🔺 Slower than baseline (>100ms)
  • ⚠️ Significant slowdown (>500ms)

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 6, 2026

Test Coverage Report (Linux)

Metric Value
Current Coverage 73.3%
Base Branch Coverage 73.2%
Delta .1% ✅

Coverage increased! Great work!

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 6, 2026

Performance Report (macOS)

Metric PR (P50) PR (P95) Baseline (P50) Delta
Server Startup 56ms 535ms 60ms -4ms
Full Refresh 125ms 28756ms 122ms 3ms

Results based on 10 iterations. P50 = median, P95 = 95th percentile.


Legend
  • 🚀 Significant speedup (>100ms faster)
  • ✅ Faster than baseline
  • ➖ No significant change
  • 🔺 Slower than baseline (>100ms)
  • ⚠️ Significant slowdown (>500ms)

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 6, 2026

Performance Report (Windows) ➖

Metric PR (P50) PR (P95) Baseline (P50) Delta Change
Server Startup 11ms 14ms 9ms 2ms 22.2%
Full Refresh 177ms 855ms 147ms 30ms 20.4%

Results based on 10 iterations. P50 = median, P95 = 95th percentile.


Legend
  • 🚀 Significant speedup (>100ms faster)
  • ✅ Faster than baseline
  • ➖ No significant change
  • 🔺 Slower than baseline (>100ms)
  • ⚠️ Significant slowdown (>500ms)

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 6, 2026

Test Coverage Report (Windows)

Metric Value
Current Coverage 69.49%
Base Branch Coverage 69.4%
Delta 0.09% ✅

Coverage increased! Great work!

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR batches several hardening and test-quality improvements across PET, mainly to reduce host-environment leakage in tests, improve panic diagnostics, and tighten uv directory parsing.

Changes:

  • Harden pet-uv’s uv-managed Python directory version parsing and add regression tests.
  • Replace RwLock .unwrap()s in pet-core’s LocatorCache with descriptive .expect(...) messages.
  • Improve test isolation/cleanup by using env_clear() for the JSONRPC test server process and tempfile::TempDir RAII for temp directories in locator tests.
Show a summary per file
File Description
crates/pet/tests/jsonrpc_client.rs Clear inherited environment for the spawned PET server to avoid host tool configuration leakage.
crates/pet-windows-registry/src/lib.rs Switch tests from manual temp dir creation/cleanup to TempDir RAII.
crates/pet-windows-registry/Cargo.toml Add tempfile as a dev-dependency for tests.
crates/pet-uv/src/lib.rs Tighten uv version parsing and add acceptance/rejection tests.
crates/pet-pixi/src/lib.rs Switch tests from manual temp dir creation/cleanup to TempDir RAII.
crates/pet-pixi/Cargo.toml Add tempfile as a dev-dependency for tests.
crates/pet-core/src/cache.rs Improve lock-poison panic diagnostics by using .expect("locator cache lock poisoned").
Cargo.lock Record new tempfile dev-dependency usage in workspace lockfile.

Copilot's findings

  • Files reviewed: 7/8 changed files
  • Comments generated: 2

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR applies several hardening and test-quality improvements across PET, including stricter uv directory version parsing, improved panic diagnostics for locator caches, more reliable temp dir cleanup in tests, and better JSONRPC test-server environment isolation.

Changes:

  • Harden pet-uv’s uv install directory version parsing and add targeted tests (including prerelease acceptance).
  • Improve LocatorCache lock-poisoning panic diagnostics by replacing unwrap() with expect(...).
  • Update tests to use tempfile::TempDir RAII cleanup and clear inherited environment variables for JSONRPC integration tests.
Show a summary per file
File Description
crates/pet/tests/jsonrpc_client.rs Clears inherited env vars for spawned test server and restores minimal needed variables.
crates/pet-uv/src/lib.rs Tightens uv directory version parsing and adds new unit tests.
crates/pet-core/src/cache.rs Replaces RwLock .unwrap() calls with .expect(...) for clearer poison diagnostics.
crates/pet-pixi/src/lib.rs Switches tests from manual temp dir management to TempDir RAII cleanup.
crates/pet-pixi/Cargo.toml Adds tempfile as a dev-dependency for tests.
crates/pet-windows-registry/src/lib.rs Switches tests from manual temp dir management to TempDir RAII cleanup.
crates/pet-windows-registry/Cargo.toml Adds tempfile as a dev-dependency for tests.
Cargo.lock Records the new tempfile dev-dependency usage in affected crates.

Copilot's findings

  • Files reviewed: 7/8 changed files
  • Comments generated: 2

Comment on lines +353 to +367
// Components before the last must be purely numeric.
// The last component may have a pre-release suffix (e.g., "0a4", "0rc1").
let components: Vec<&str> = version.split('.').collect();
if components.len() < 2 {
return None;
}
// All components except the last must be purely numeric.
let all_but_last = &components[..components.len() - 1];
if !all_but_last
.iter()
.all(|c| !c.is_empty() && c.chars().all(|ch| ch.is_ascii_digit()))
{
return None;
}
// The last component must start with a digit (allows pre-release suffix like "0a4").
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

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

components validation currently allows non-numeric suffixes on a 2-part version like 3.12abc (because only the major component is in all_but_last, and the last component only has to start with a digit). That seems to undercut the hardening goal and could misidentify directories like cpython-3.12abc-... as valid. Consider requiring the first two components (major+minor) to be digits-only, and only allowing a pre-release suffix on the patch component when a third component exists (and add a test case for the 3.12abc scenario).

Suggested change
// Components before the last must be purely numeric.
// The last component may have a pre-release suffix (e.g., "0a4", "0rc1").
let components: Vec<&str> = version.split('.').collect();
if components.len() < 2 {
return None;
}
// All components except the last must be purely numeric.
let all_but_last = &components[..components.len() - 1];
if !all_but_last
.iter()
.all(|c| !c.is_empty() && c.chars().all(|ch| ch.is_ascii_digit()))
{
return None;
}
// The last component must start with a digit (allows pre-release suffix like "0a4").
// Major and minor must always be purely numeric.
// Only the patch component may have a pre-release suffix (e.g., "0a4", "0rc1").
let components: Vec<&str> = version.split('.').collect();
if components.len() < 2 {
return None;
}
let is_numeric_component =
|c: &str| !c.is_empty() && c.chars().all(|ch| ch.is_ascii_digit());
if !is_numeric_component(components[0]) || !is_numeric_component(components[1]) {
return None;
}
if components.len() == 2 {
return Some(version.to_string());
}
let all_but_last = &components[2..components.len() - 1];
if !all_but_last.iter().all(|c| is_numeric_component(c)) {
return None;
}
// The patch component may start with a digit and include a pre-release suffix.

Copilot uses AI. Check for mistakes.
Comment on lines +106 to +110
.env_clear()
.env("PATH", "")
.env(
"SYSTEMROOT",
std::env::var("SYSTEMROOT").unwrap_or_default(),
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

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

With .env_clear(), SYSTEMROOT becomes the only restored OS-specific variable here, but unwrap_or_default() will silently set it to an empty string if the parent process doesn't have it. On Windows that can produce confusing downstream failures; it’s better to either (a) only set this on Windows and expect/return an error if missing, or (b) only set it when std::env::var("SYSTEMROOT") succeeds (and omit it otherwise on non-Windows).

Copilot uses AI. Check for mistakes.
@karthiknadig karthiknadig merged commit 3a7b3fa into main Apr 6, 2026
34 checks passed
@karthiknadig karthiknadig deleted the chore/fix-397-402-403-401-hardening branch April 6, 2026 23:33
karthiknadig added a commit that referenced this pull request Apr 6, 2026
karthiknadig added a commit that referenced this pull request Apr 6, 2026
…lient (#411)

## Summary

Addresses two unresolved Copilot review comments from merged PR #410.

## Changes

- **uv version parser:** Major and minor components are now explicitly
validated as purely numeric. Pre-release suffix (e.g., `0a4`, `0rc1`) is
only allowed on the patch component (3rd+). Previously `3.12abc` passed
validation because the minor was the "last" component and only needed to
start with a digit. Added test case for this scenario.

- **SYSTEMROOT in test client:** Platform-gated with `#[cfg(windows)]`
and only set when `std::env::var("SYSTEMROOT")` succeeds. Previously
used `unwrap_or_default()` which silently set it to empty string on
non-Windows or when missing.

Follow-up to #410
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants