//! A secret file is read from the file that was checked, never from whatever the path names a //! moment later (M4a review, finding 2). `read_checked` runs `between` after checking the path and //! before opening it; each test swaps something there. Do not edit. #[path = "support/tmp.rs"] mod tmp; use std::os::unix::fs::PermissionsExt; use std::path::{Path, PathBuf}; use gatewayd::secrets::read_checked; use tmp::TempDir; const TOKEN: &str = "the-real-token"; const OTHER: &str = "a-file-the-owner-never-chose"; fn owner_file(dir: &TempDir, name: &str, text: &str) -> PathBuf { let path = dir.write(name, text); std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o600)).unwrap(); path } fn refused(path: &Path, between: &dyn Fn(), word: &str) { let why = read_checked(path, between).expect_err(word); assert!(why.contains(word), "{word}: {why}"); assert!(why.contains(&path.display().to_string()), "{why}"); assert!( !why.contains(TOKEN) && !why.contains(OTHER), "never a value: {why}" ); } #[test] fn an_untouched_file_is_read() { let dir = TempDir::new("race-ok"); let path = owner_file(&dir, "token", &format!("{TOKEN}\n")); let bytes = read_checked(&path, &|| {}).unwrap(); assert_eq!(bytes.as_slice(), format!("{TOKEN}\n").as_bytes()); } #[test] fn a_file_swapped_for_a_link_is_refused() { let dir = TempDir::new("race-link"); let path = owner_file(&dir, "token", TOKEN); let other = owner_file(&dir, "other", OTHER); let swap = || { std::fs::remove_file(&path).unwrap(); std::os::unix::fs::symlink(&other, &path).unwrap(); }; refused(&path, &swap, "changed while it was read"); } #[test] fn a_file_swapped_for_another_file_is_refused() { let dir = TempDir::new("race-rename"); let path = owner_file(&dir, "token", TOKEN); let other = owner_file(&dir, "other", OTHER); let swap = || std::fs::rename(&other, &path).unwrap(); refused(&path, &swap, "changed while it was read"); } #[test] fn the_checks_hold_for_the_file_that_is_read() { let dir = TempDir::new("race-mode"); let path = owner_file(&dir, "token", TOKEN); let widen = || { std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o644)).unwrap(); }; refused(&path, &widen, "has mode 644"); } #[test] fn the_path_checks_still_come_first() { let dir = TempDir::new("race-first"); let other = owner_file(&dir, "other", OTHER); let link = dir.path().join("link"); std::os::unix::fs::symlink(&other, &link).unwrap(); refused( &link, &|| panic!("never reached for a link"), "is a symbolic link", ); refused( dir.path(), &|| panic!("never reached for a directory"), "is not a regular file", ); let relative = Path::new("relative/token"); let why = read_checked(relative, &|| panic!("never reached")).unwrap_err(); assert!(why.contains("is not an absolute path"), "{why}"); }