fix/audit-findings #5
1 changed files with 61 additions and 2 deletions
fix(fold): follow the filesystem for .. after a symlinked directory
Fold report paths were normalized lexically, so `linkout/../src/main.rs` with `linkout` pointing outside the root attached to the repository's `src/main.rs` although the OS path names a different file. A relative path containing `..` that exists in this checkout is now canonicalized (and must stay under the canonical root); paths absent from the checkout, such as reports from another machine, keep the documented lexical matching. Test: fold::tests::parent_steps_after_a_symlinked_directory_follow_the_filesystem fails before this change (the finding attaches to src/main.rs).
commit
4b2c873445
63
src/fold.rs
63
src/fold.rs
|
|
@ -372,7 +372,24 @@ fn find_file(building: &Building, path: &str) -> Option<String> {
|
||||||
{
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
normalized
|
// When the path exists here, follow the filesystem: `link/../x` names what
|
||||||
|
// the OS resolves through `link`, not the lexical `x`. Paths absent from this
|
||||||
|
// checkout (a report from another machine) keep lexical matching.
|
||||||
|
let on_disk = Path::new(&building.root).join(path.replace('\\', "/"));
|
||||||
|
if path.contains("..")
|
||||||
|
&& let (Ok(canonical), Ok(root)) = (
|
||||||
|
on_disk.canonicalize(),
|
||||||
|
Path::new(&building.root).canonicalize(),
|
||||||
|
)
|
||||||
|
{
|
||||||
|
canonical
|
||||||
|
.strip_prefix(&root)
|
||||||
|
.ok()?
|
||||||
|
.to_str()?
|
||||||
|
.replace('\\', "/")
|
||||||
|
} else {
|
||||||
|
normalized
|
||||||
|
}
|
||||||
};
|
};
|
||||||
building
|
building
|
||||||
.nodes
|
.nodes
|
||||||
|
|
@ -512,7 +529,10 @@ mod tests {
|
||||||
})).collect();
|
})).collect();
|
||||||
fs::write(
|
fs::write(
|
||||||
&report,
|
&report,
|
||||||
serde_json::to_vec(&serde_json::json!({"tool": {"name": "fold"}, "findings": findings})).unwrap(),
|
serde_json::to_vec(
|
||||||
|
&serde_json::json!({"tool": {"name": "fold"}, "findings": findings}),
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let mut model = scan(&root).unwrap();
|
let mut model = scan(&root).unwrap();
|
||||||
|
|
@ -822,4 +842,43 @@ mod tests {
|
||||||
building.diagnostics
|
building.diagnostics
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
#[test]
|
||||||
|
fn parent_steps_after_a_symlinked_directory_follow_the_filesystem() {
|
||||||
|
// `linkout/../src/main.rs` with `linkout` pointing outside the root was
|
||||||
|
// normalized lexically to `src/main.rs`, a file the OS path does not name.
|
||||||
|
use std::os::unix::fs::symlink;
|
||||||
|
let workspace = tempfile::tempdir().unwrap();
|
||||||
|
let root = workspace.path().join("repo");
|
||||||
|
fs::create_dir_all(root.join("src")).unwrap();
|
||||||
|
fs::write(root.join("src/main.rs"), "fn main() {}\n").unwrap();
|
||||||
|
let outside = workspace.path().join("elsewhere/deeper");
|
||||||
|
fs::create_dir_all(&outside).unwrap();
|
||||||
|
fs::create_dir_all(workspace.path().join("elsewhere/src")).unwrap();
|
||||||
|
fs::write(
|
||||||
|
workspace.path().join("elsewhere/src/main.rs"),
|
||||||
|
"fn other() {}\n",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
symlink(&outside, root.join("linkout")).unwrap();
|
||||||
|
let report = workspace.path().join("fold.json");
|
||||||
|
let value = serde_json::json!({
|
||||||
|
"tool": {"name": "fold"},
|
||||||
|
"findings": [{
|
||||||
|
"id": "through-link", "kind": "test",
|
||||||
|
"locations": [{"file": "linkout/../src/main.rs", "line": 1}],
|
||||||
|
"confidence": "heuristic", "evidence": {"backend": "source"}
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
fs::write(&report, serde_json::to_vec(&value).unwrap()).unwrap();
|
||||||
|
let mut model = scan(&root).unwrap();
|
||||||
|
assert_eq!(import_findings(&mut model, &report).unwrap(), 0);
|
||||||
|
assert!(
|
||||||
|
model
|
||||||
|
.diagnostics
|
||||||
|
.iter()
|
||||||
|
.any(|d| d.message.contains("did not match a scanned file"))
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue