greentic_dev/
path_safety.rs1use std::path::{Path, PathBuf};
2
3use anyhow::{Context, Result};
4
5pub fn normalize_under_root(root: &Path, candidate: &Path) -> Result<PathBuf> {
8 let canonical_root = root
9 .canonicalize()
10 .with_context(|| format!("failed to canonicalize root {}", root.display()))?;
11
12 let resolved = if candidate.is_absolute() {
13 candidate.to_path_buf()
14 } else {
15 canonical_root.join(candidate)
16 };
17
18 let canon = resolved
19 .canonicalize()
20 .with_context(|| format!("failed to canonicalize {}", resolved.display()))?;
21
22 if !canon.starts_with(&canonical_root) {
23 anyhow::bail!(
24 "path escapes root ({}): {}",
25 canonical_root.display(),
26 canon.display()
27 );
28 }
29
30 Ok(canon)
31}