MCPcopy Create free account
hub / github.com/dallay/agentsync / revalidate_unlink_path

Method revalidate_unlink_path

src/linker.rs:217–291  ·  view source on GitHub ↗

Re-validate a path before unlinking (remove_file/remove_dir). Unlike revalidate_path, this does NOT canonicalize the final component, allowing safe removal of symlinks that point outside project_root. The symlink entry itself must be within project_root, but its target can be anywhere.

(&self, path: &Path)

Source from the content-addressed store, hash-verified

215 /// allowing safe removal of symlinks that point outside project_root.
216 /// The symlink entry itself must be within project_root, but its target can be anywhere.
217 fn revalidate_unlink_path(&self, path: &Path) -> Result<()> {
218 let display_path = path.display().to_string();
219
220 // SECURITY: Reject absolute paths
221 if path.is_absolute() {
222 // If path is already absolute and under project_root, validate parent only
223 if !path.starts_with(&self.project_root) {
224 anyhow::bail!("Path is outside project root: {}", display_path);
225 }
226 // For absolute paths under project_root, validate the parent directory
227 if let Some(parent) = path.parent() {
228 let canonical_parent = self.canonicalize_uncached(parent).with_context(|| {
229 format!("Failed to canonicalize parent: {}", parent.display())
230 })?;
231
232 let canonical_root = self.get_canonical_project_root()?;
233
234 if !canonical_parent.starts_with(&canonical_root) {
235 anyhow::bail!(
236 "Path parent resolves outside project root: {}",
237 display_path
238 );
239 }
240 }
241 return Ok(());
242 }
243
244 // SECURITY: Reject paths with ParentDir components before resolution
245 for component in path.components() {
246 if matches!(component, Component::ParentDir) {
247 anyhow::bail!(
248 "Path contains parent directory (..) component: {}",
249 display_path
250 );
251 }
252 }
253
254 // Validate that the parent directory (if any) is within project_root
255 // We canonicalize the parent but NOT the final component (which might be a symlink)
256 if let Some(parent) = path.parent() {
257 if parent.as_os_str().is_empty() {
258 // Path has no parent (e.g., just a filename), it's relative to project_root
259 return Ok(());
260 }
261
262 let parent_absolute = if parent.is_absolute() {
263 parent.to_path_buf()
264 } else {
265 self.project_root.join(parent)
266 };
267
268 // Only canonicalize if the parent exists; for cleanup operations the parent might not exist yet
269 if parent_absolute.exists() {
270 let canonical_parent =
271 self.canonicalize_uncached(&parent_absolute)
272 .with_context(|| {
273 format!(
274 "Failed to canonicalize parent: {}",

Callers 2

create_symlinkMethod · 0.80
cleanMethod · 0.80

Calls 2

canonicalize_uncachedMethod · 0.80

Tested by

no test coverage detected