Skip to content

Commit 5dc3c0e

Browse files
committed
fix: enhance workdir_file_contents to follow symlinks only resolving within the repository workdir and add tests for symlink behavior
1 parent f8d9079 commit 5dc3c0e

1 file changed

Lines changed: 32 additions & 11 deletions

File tree

apps/native/src-tauri/src/git/repo_files.rs

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,25 +42,16 @@ pub fn head_file_contents(repo: &Repository, path: &Path) -> String {
4242

4343
/// Reads the contents of a file at the given path from the working directory of the repository.
4444
/// Returns an empty string if the file does not exist on disk.
45+
/// Symlinks are followed, but only if the resolved target remains inside the repository workdir.
4546
pub fn workdir_file_contents(repo: &Repository, path: &Path) -> String {
4647
let Some(workdir) = repo.workdir() else {
4748
return String::new();
4849
};
4950

50-
let full_path = workdir.join(path);
51-
let Ok(metadata) = std::fs::symlink_metadata(&full_path) else {
52-
return String::new();
53-
};
54-
55-
if metadata.file_type().is_symlink() {
56-
return std::fs::read_link(&full_path)
57-
.map(|target| target.to_string_lossy().into_owned())
58-
.unwrap_or_default();
59-
}
60-
6151
let Ok(workdir_canonical) = workdir.canonicalize() else {
6252
return String::new();
6353
};
54+
let full_path = workdir.join(path);
6455
let Ok(full_path_canonical) = full_path.canonicalize() else {
6556
return String::new();
6657
};
@@ -189,4 +180,34 @@ mod tests {
189180
""
190181
);
191182
}
183+
184+
#[cfg(unix)]
185+
#[test]
186+
fn workdir_file_contents_follows_symlink_inside_workdir() {
187+
let temp = TempDir::new().expect("create temp dir");
188+
let repo = Repository::init(temp.path()).expect("init repo");
189+
190+
fs::write(temp.path().join("target.txt"), "inside\n").expect("write target file");
191+
std::os::unix::fs::symlink("target.txt", temp.path().join("link.txt"))
192+
.expect("create symlink");
193+
194+
assert_eq!(
195+
workdir_file_contents(&repo, Path::new("link.txt")),
196+
"inside\n"
197+
);
198+
}
199+
200+
#[cfg(unix)]
201+
#[test]
202+
fn workdir_file_contents_rejects_symlink_outside_workdir() {
203+
let temp = TempDir::new().expect("create temp dir");
204+
let repo = Repository::init(temp.path()).expect("init repo");
205+
let outside = temp.path().join("../outside.txt");
206+
fs::write(&outside, "outside").expect("write outside file");
207+
208+
std::os::unix::fs::symlink(&outside, temp.path().join("link.txt"))
209+
.expect("create symlink");
210+
211+
assert_eq!(workdir_file_contents(&repo, Path::new("link.txt")), "");
212+
}
192213
}

0 commit comments

Comments
 (0)