safe-path: add more unit test cases

Add more unit test cases to improve code coverage.

Signed-off-by: Liu Jiang <gerry@linux.alibaba.com>
This commit is contained in:
Liu Jiang 2022-04-06 09:41:18 +08:00
parent b63774ec61
commit 0ad89ebd7c
3 changed files with 172 additions and 4 deletions

View File

@ -230,6 +230,7 @@ impl AsRef<Path> for PinnedPathBuf {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use std::ffi::OsString;
use std::fs::DirBuilder; use std::fs::DirBuilder;
use std::io::Write; use std::io::Write;
use std::os::unix::fs::{symlink, MetadataExt}; use std::os::unix::fs::{symlink, MetadataExt};
@ -396,5 +397,48 @@ mod tests {
let path = path.open_child(OsStr::new("child")).unwrap(); let path = path.open_child(OsStr::new("child")).unwrap();
let content = fs::read_to_string(&path).unwrap(); let content = fs::read_to_string(&path).unwrap();
assert_eq!(&content, "test"); assert_eq!(&content, "test");
path.open_child(&OsString::from("__does_not_exist__"))
.unwrap_err();
path.open_child(&OsString::from("test/a")).unwrap_err();
}
#[test]
fn test_prepare_path_component() {
assert!(PinnedPathBuf::prepare_path_component(&OsString::from("")).is_err());
assert!(PinnedPathBuf::prepare_path_component(&OsString::from(".")).is_err());
assert!(PinnedPathBuf::prepare_path_component(&OsString::from("..")).is_err());
assert!(PinnedPathBuf::prepare_path_component(&OsString::from("/")).is_err());
assert!(PinnedPathBuf::prepare_path_component(&OsString::from("//")).is_err());
assert!(PinnedPathBuf::prepare_path_component(&OsString::from("a/b")).is_err());
assert!(PinnedPathBuf::prepare_path_component(&OsString::from("./b")).is_err());
assert!(PinnedPathBuf::prepare_path_component(&OsString::from("a/.")).is_err());
assert!(PinnedPathBuf::prepare_path_component(&OsString::from("a/..")).is_err());
assert!(PinnedPathBuf::prepare_path_component(&OsString::from("a/./")).is_err());
assert!(PinnedPathBuf::prepare_path_component(&OsString::from("a/../")).is_err());
assert!(PinnedPathBuf::prepare_path_component(&OsString::from("a/./a")).is_err());
assert!(PinnedPathBuf::prepare_path_component(&OsString::from("a/../a")).is_err());
assert!(PinnedPathBuf::prepare_path_component(&OsString::from("a")).is_ok());
assert!(PinnedPathBuf::prepare_path_component(&OsString::from("a.b")).is_ok());
assert!(PinnedPathBuf::prepare_path_component(&OsString::from("a..b")).is_ok());
}
#[test]
fn test_target_fs_object_changed() {
let rootfs_dir = tempfile::tempdir().expect("failed to create tmpdir");
let rootfs_path = rootfs_dir.path();
let file = rootfs_path.join("child");
fs::write(&file, "test").unwrap();
let path = PinnedPathBuf::from_path(&file).unwrap();
let path3 = fs::read_link(path.as_path()).unwrap();
assert_eq!(&path3, path.target());
fs::rename(file, rootfs_path.join("child2")).unwrap();
let path4 = fs::read_link(path.as_path()).unwrap();
assert_ne!(&path4, path.target());
fs::remove_file(rootfs_path.join("child2")).unwrap();
let path5 = fs::read_link(path.as_path()).unwrap();
assert_ne!(&path4, &path5);
} }
} }

View File

@ -253,9 +253,42 @@ mod tests {
builder.create("../../.").unwrap(); builder.create("../../.").unwrap();
builder.create("").unwrap(); builder.create("").unwrap();
builder.create_with_unscoped_path("/").unwrap(); builder.create_with_unscoped_path("/").unwrap();
builder.create_with_unscoped_path(".").unwrap(); builder.create_with_unscoped_path("/..").unwrap();
builder.create_with_unscoped_path("..").unwrap(); builder.create_with_unscoped_path("/../.").unwrap();
builder.create_with_unscoped_path("../../.").unwrap(); }
builder.create_with_unscoped_path("").unwrap();
#[test]
fn test_create_with_absolute_path() {
// create temporary directory to emulate container rootfs with symlink
let rootfs_dir = tempdir().expect("failed to create tmpdir");
DirBuilder::new()
.create(rootfs_dir.path().join("b"))
.unwrap();
symlink(rootfs_dir.path().join("b"), rootfs_dir.path().join("a")).unwrap();
let rootfs_path = &rootfs_dir.path().join("a");
let mut builder = ScopedDirBuilder::new(&rootfs_path).unwrap();
builder.create_with_unscoped_path("/").unwrap_err();
builder
.create_with_unscoped_path(rootfs_path.join("../__xxxx___xxx__"))
.unwrap_err();
builder
.create_with_unscoped_path(rootfs_path.join("c/d"))
.unwrap_err();
// Return `AlreadyExist` when recursive is false
builder.create_with_unscoped_path(&rootfs_path).unwrap_err();
builder
.create_with_unscoped_path(rootfs_path.join("."))
.unwrap_err();
builder.recursive(true);
builder.create_with_unscoped_path(&rootfs_path).unwrap();
builder
.create_with_unscoped_path(rootfs_path.join("."))
.unwrap();
builder
.create_with_unscoped_path(rootfs_path.join("c/d"))
.unwrap();
} }
} }

View File

@ -319,6 +319,97 @@ mod tests {
// Detect symlink loop. // Detect symlink loop.
fs::symlink("/endpoint_b", rootfs_path.join("endpoint_a")).unwrap(); fs::symlink("/endpoint_b", rootfs_path.join("endpoint_a")).unwrap();
fs::symlink("/endpoint_a", rootfs_path.join("endpoint_b")).unwrap(); fs::symlink("/endpoint_a", rootfs_path.join("endpoint_b")).unwrap();
scoped_resolve(rootfs_path, "endpoint_a").unwrap_err();
}
#[test]
fn test_scoped_join() {
// create temporary directory to emulate container rootfs with symlink
let rootfs_dir = tempdir().expect("failed to create tmpdir");
let rootfs_path = &rootfs_dir.path();
assert_eq!(
scoped_join(&rootfs_path, "a").unwrap(),
rootfs_path.join("a")
);
assert_eq!(
scoped_join(&rootfs_path, "./a").unwrap(),
rootfs_path.join("a")
);
assert_eq!(
scoped_join(&rootfs_path, "././a").unwrap(),
rootfs_path.join("a")
);
assert_eq!(
scoped_join(&rootfs_path, "c/d/../../a").unwrap(),
rootfs_path.join("a")
);
assert_eq!(
scoped_join(&rootfs_path, "c/d/../../../.././a").unwrap(),
rootfs_path.join("a")
);
assert_eq!(
scoped_join(&rootfs_path, "../../a").unwrap(),
rootfs_path.join("a")
);
assert_eq!(
scoped_join(&rootfs_path, "./../a").unwrap(),
rootfs_path.join("a")
);
}
#[test]
fn test_scoped_join_symlink() {
// create temporary directory to emulate container rootfs with symlink
let rootfs_dir = tempdir().expect("failed to create tmpdir");
let rootfs_path = &rootfs_dir.path();
DirBuilder::new()
.recursive(true)
.create(rootfs_dir.path().join("b/c"))
.unwrap();
fs::symlink("b/c", rootfs_dir.path().join("a")).unwrap();
let target = rootfs_path.join("b/c");
assert_eq!(scoped_join(&rootfs_path, "a").unwrap(), target);
assert_eq!(scoped_join(&rootfs_path, "./a").unwrap(), target);
assert_eq!(scoped_join(&rootfs_path, "././a").unwrap(), target);
assert_eq!(scoped_join(&rootfs_path, "b/c/../../a").unwrap(), target);
assert_eq!(
scoped_join(&rootfs_path, "b/c/../../../.././a").unwrap(),
target
);
assert_eq!(scoped_join(&rootfs_path, "../../a").unwrap(), target);
assert_eq!(scoped_join(&rootfs_path, "./../a").unwrap(), target);
assert_eq!(scoped_join(&rootfs_path, "a/../../../a").unwrap(), target);
assert_eq!(scoped_join(&rootfs_path, "a/../../../b/c").unwrap(), target);
}
#[test]
fn test_scoped_join_symlink_loop() {
// create temporary directory to emulate container rootfs with symlink
let rootfs_dir = tempdir().expect("failed to create tmpdir");
let rootfs_path = &rootfs_dir.path();
fs::symlink("/endpoint_b", rootfs_path.join("endpoint_a")).unwrap();
fs::symlink("/endpoint_a", rootfs_path.join("endpoint_b")).unwrap();
scoped_join(rootfs_path, "endpoint_a").unwrap_err(); scoped_join(rootfs_path, "endpoint_a").unwrap_err();
} }
#[test]
fn test_scoped_join_unicode_character() {
// create temporary directory to emulate container rootfs with symlink
let rootfs_dir = tempdir().expect("failed to create tmpdir");
let rootfs_path = &rootfs_dir.path().canonicalize().unwrap();
let path = scoped_join(rootfs_path, "您好").unwrap();
assert_eq!(path, rootfs_path.join("您好"));
let path = scoped_join(rootfs_path, "../../../您好").unwrap();
assert_eq!(path, rootfs_path.join("您好"));
let path = scoped_join(rootfs_path, "。。/您好").unwrap();
assert_eq!(path, rootfs_path.join("。。/您好"));
let path = scoped_join(rootfs_path, "您好/../../test").unwrap();
assert_eq!(path, rootfs_path.join("test"));
}
} }