From 5e38e5fb5fc2cc5d30844df71432a60742bcb572 Mon Sep 17 00:00:00 2001 From: akbash Date: Mon, 14 Sep 2026 23:13:52 +0300 Subject: fix: protect integration configs from failed writes (#3973) * fix: atomically write integration configs refs #3970 * fix: atomically write integration configs refs #3970 * fix: atomically write integration configs refs #3970 * fix: atomically write integration configs refs #3970 * fix: atomically write integration configs refs #3970 * fix: atomically write integration configs refs #3970 * fix: atomically write integration configs refs #3970 * fix: atomically write integration configs refs #3970 * fix: atomically write integration configs refs #3970 * fix: atomically write integration configs refs #3970 * fix: atomically write integration configs refs #3970 * fix: atomically write integration configs refs #3970 * fix: atomically write integration configs refs #3970 * fix: atomically write integration configs refs #3970 * fix: atomically write integration configs refs #3970 --------- Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com> Co-authored-by: JJ Liebig --- src/platform/macos/config_file_tests.rs | 44 +++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 src/platform/macos/config_file_tests.rs (limited to 'src/platform/macos/config_file_tests.rs') diff --git a/src/platform/macos/config_file_tests.rs b/src/platform/macos/config_file_tests.rs new file mode 100644 index 00000000..f08d6c2a --- /dev/null +++ b/src/platform/macos/config_file_tests.rs @@ -0,0 +1,44 @@ +use super::*; + +#[test] +fn config_replacement_preserves_macos_acl() { + let dir = std::env::temp_dir().join(format!("herdr-config-acl-{}", std::process::id())); + std::fs::create_dir(&dir).unwrap(); + let source = dir.join("source"); + let temporary = dir.join("temporary"); + std::fs::write(&source, b"original").unwrap(); + assert!(Command::new("chmod") + .args(["+a", "everyone deny execute"]) + .arg(&source) + .status() + .unwrap() + .success()); + let acl = |path: &Path| { + let output = Command::new("ls").arg("-le").arg(path).output().unwrap(); + assert!(output.status.success()); + String::from_utf8(output.stdout) + .unwrap() + .lines() + .skip(1) + .collect::>() + .join("\n") + }; + let original = acl(&source); + assert!(original.contains("everyone deny execute")); + assert!(Command::new("chmod") + .args(["+a", "everyone allow read,file_inherit"]) + .arg(&dir) + .status() + .unwrap() + .success()); + drop(create_config_temporary(&temporary, true).unwrap()); + assert!( + acl(&temporary).is_empty(), + "staging must not inherit allow ACEs" + ); + write_config_temporary(Some(&source), &temporary, b"new").unwrap(); + assert_eq!(acl(&temporary), original); + assert_eq!(std::fs::read(&source).unwrap(), b"original"); + assert_eq!(std::fs::read(&temporary).unwrap(), b"new"); + std::fs::remove_dir_all(dir).unwrap(); +} -- cgit v1.2.3