From 0ad3e3335e94c541bfdff34d5ceb5e4fb791c537 Mon Sep 17 00:00:00 2001 From: en Date: Wed, 16 Sep 2026 07:59:34 +0200 Subject: [PATCH] Refactor chmod_runtime_dir to chmod_dir(path); test uses tempdir Split the chmod helper so tests can exercise it on a private tempdir instead of mutating the user's XDG_RUNTIME_DIR. The thin chmod_runtime_dir() wrapper still picks runtime_dir() for the production path (called from session.rs). --- src/profile.rs | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/src/profile.rs b/src/profile.rs index f73f2a0..c518471 100644 --- a/src/profile.rs +++ b/src/profile.rs @@ -468,12 +468,18 @@ pub fn runtime_dir() -> PathBuf { /// protocol (including `Command::Type`, which is wide-open text injection /// into game windows). Permissions are the cheapest defense. pub fn chmod_runtime_dir() { + chmod_dir(&runtime_dir()); +} + +/// `chmod 0o700` an arbitrary directory. Split out from +/// [`chmod_runtime_dir`] so tests can exercise it on a tempdir they own +/// without mutating the user's live `XDG_RUNTIME_DIR`. +pub fn chmod_dir(path: &std::path::Path) { #[cfg(unix)] { use std::os::unix::fs::PermissionsExt; - let dir = runtime_dir(); let _ = std::fs::set_permissions( - &dir, + path, std::fs::Permissions::from_mode(0o700), ); } @@ -541,20 +547,24 @@ fn chmod_socket_sets_0o600() { #[cfg(unix)] #[test] -fn chmod_runtime_dir_sets_0o700() { +fn chmod_dir_sets_0o700_on_a_tempdir() { use std::os::unix::fs::PermissionsExt; - // Save and restore the real dir perms around the test so we don't break - // the live session if it happens to share XDG_RUNTIME_DIR. - let dir = runtime_dir(); - let _ = std::fs::create_dir_all(&dir); - let saved = std::fs::metadata(&dir).ok().map(|m| m.permissions().mode() & 0o777); - // Force 0o755 so the helper actually has to change it. - let _ = std::fs::set_permissions(&dir, std::fs::Permissions::from_mode(0o755)); - chmod_runtime_dir(); + // Use a private tempdir so the test never mutates the user's + // XDG_RUNTIME_DIR (which is what runtime_dir() resolves to). + let unique = format!( + "enboxer-chmod-{}-{}", + std::process::id(), + std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .map(|d| d.as_nanos()) + .unwrap_or(0) + ); + let dir = std::env::temp_dir().join(unique); + std::fs::create_dir_all(&dir).unwrap(); + std::fs::set_permissions(&dir, std::fs::Permissions::from_mode(0o755)).unwrap(); + chmod_dir(&dir); let m = std::fs::metadata(&dir).unwrap().permissions().mode() & 0o777; assert_eq!(m, 0o700, "expected 0o700, got {m:o}"); - if let Some(s) = saved { - let _ = std::fs::set_permissions(&dir, std::fs::Permissions::from_mode(s)); - } + let _ = std::fs::remove_dir(&dir); }