(pattern: &str, label: &str)
| 927 | } |
| 928 | |
| 929 | pub(crate) fn validate_relative_pattern(pattern: &str, label: &str) -> Result<()> { |
| 930 | let pattern = pattern.trim(); |
| 931 | if pattern.is_empty() { |
| 932 | bail!("{label} cannot be empty"); |
| 933 | } |
| 934 | if has_windows_path_prefix(pattern) || Path::new(pattern).is_absolute() { |
| 935 | bail!("{label} must be relative to the workspace"); |
| 936 | } |
| 937 | |
| 938 | let normalized = pattern.replace('\\', "/"); |
| 939 | if normalized.split('/').any(|component| component == "..") { |
| 940 | bail!("{label} must not contain parent directory traversal"); |
| 941 | } |
| 942 | |
| 943 | Ok(()) |
| 944 | } |
| 945 | |
| 946 | fn normalize_relative_path(path: &Path) -> Result<PathBuf> { |
| 947 | let mut out = PathBuf::new(); |
no test coverage detected