Skip to content

Commit a977a14

Browse files
committed
fix: address review feedback - require platform segment and tighten version validation (PR #410)
1 parent 371044a commit a977a14

File tree

1 file changed

+34
-10
lines changed

1 file changed

+34
-10
lines changed

crates/pet-uv/src/lib.rs

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -344,19 +344,32 @@ fn parse_version_from_uv_dir_name(dir_name: &str) -> Option<String> {
344344
let mut parts = dir_name.splitn(3, '-');
345345
let _impl = parts.next()?;
346346
let version = parts.next()?;
347-
// Verify at minimum X.Y format (e.g., "3.12" or "3.12.3")
348-
// and that each component starts with a digit. Trailing alpha chars are
349-
// allowed on the last component to support pre-release versions like "3.14.0a4".
347+
// Require the platform segment to exist (rejects bare "<impl>-<version>").
348+
let platform = parts.next()?;
349+
if platform.is_empty() {
350+
return None;
351+
}
352+
// Verify at minimum X.Y format (e.g., "3.12" or "3.12.3").
353+
// Components before the last must be purely numeric.
354+
// The last component may have a pre-release suffix (e.g., "0a4", "0rc1").
350355
let components: Vec<&str> = version.split('.').collect();
351-
if components.len() >= 2
352-
&& components
353-
.iter()
354-
.all(|c| !c.is_empty() && c.starts_with(|ch: char| ch.is_ascii_digit()))
356+
if components.len() < 2 {
357+
return None;
358+
}
359+
// All components except the last must be purely numeric.
360+
let all_but_last = &components[..components.len() - 1];
361+
if !all_but_last
362+
.iter()
363+
.all(|c| !c.is_empty() && c.chars().all(|ch| ch.is_ascii_digit()))
355364
{
356-
Some(version.to_string())
357-
} else {
358-
None
365+
return None;
359366
}
367+
// The last component must start with a digit (allows pre-release suffix like "0a4").
368+
let last = components.last()?;
369+
if last.is_empty() || !last.starts_with(|ch: char| ch.is_ascii_digit()) {
370+
return None;
371+
}
372+
Some(version.to_string())
360373
}
361374

362375
/// Walks up from `project_path` looking for a workspace that this project belongs to.
@@ -1123,6 +1136,17 @@ exclude = ["packages/legacy"]"#;
11231136
);
11241137
// Empty component after dot.
11251138
assert_eq!(parse_version_from_uv_dir_name("cpython-3.12.-linux"), None);
1139+
// Non-numeric middle component must be rejected even if it starts with a digit.
1140+
assert_eq!(
1141+
parse_version_from_uv_dir_name("cpython-3.12abc.1-linux"),
1142+
None
1143+
);
1144+
}
1145+
1146+
#[test]
1147+
fn test_parse_version_from_uv_dir_name_rejects_missing_platform() {
1148+
// Bare "<impl>-<version>" without platform segment should be rejected.
1149+
assert_eq!(parse_version_from_uv_dir_name("cpython-3.12"), None);
11261150
}
11271151

11281152
#[test]

0 commit comments

Comments
 (0)