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 resolved = if candidate.is_absolute() {
9 candidate.to_path_buf()
10 } else {
11 root.join(candidate)
12 };
13
14 let canon = resolved
15 .canonicalize()
16 .with_context(|| format!("failed to canonicalize {}", resolved.display()))?;
17
18 if !canon.starts_with(root) {
19 anyhow::bail!(
20 "path escapes root ({}): {}",
21 root.display(),
22 canon.display()
23 );
24 }
25
26 Ok(canon)
27}