From bffd6bdd3c696a9808eea57034c96811eab591a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Chatlamet?= Date: Fri, 19 Jun 2026 05:40:42 +0000 Subject: [PATCH 1/3] state: create run directory on startup with clear error context - Add to calls in State::new() and write_state_file() so directory creation failures produce actionable error messages instead of raw I/O errors - Remove pre-creation of /var/run/ and /var/lib/intermesh/ from the e2e test Dockerfile since the daemon now creates these at runtime --- docker/Dockerfile | 4 +--- src/state/mod.rs | 8 ++++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 2601b08..e3ffd2f 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -32,9 +32,7 @@ RUN --mount=type=cache,target=/nix,from=nixos/nix:latest,source=/nix \ ln -s "$bin" /out/test-nix/bin/$(basename "$bin"); \ done && \ mkdir -p /out/test-rootfs/tmp \ - /out/test-rootfs/usr/local/bin \ - /out/test-rootfs/var/run \ - /out/test-rootfs/var/lib/intermesh && \ + /out/test-rootfs/usr/local/bin && \ chmod 1777 /out/test-rootfs/tmp FROM e2e-builder AS builder diff --git a/src/state/mod.rs b/src/state/mod.rs index d50656b..f1c3a7e 100644 --- a/src/state/mod.rs +++ b/src/state/mod.rs @@ -137,7 +137,9 @@ impl State { /// If a field isn't provided via args/env, we fall back to the state file. pub(crate) async fn new(args: Args) -> Result { if let Some(parent) = args.state_file.parent() { - fs::create_dir_all(parent).await?; + fs::create_dir_all(parent) + .await + .with_context(|| format!("failed to create state directory {}", parent.display()))?; } let mut private_key_pem = None; @@ -368,7 +370,9 @@ impl State { .context("state file has no parent directory")? .to_path_buf(); - fs::create_dir_all(&parent_dir).await?; + fs::create_dir_all(&parent_dir) + .await + .with_context(|| format!("failed to create state directory {}", parent_dir.display()))?; // The tempfile + fsync + rename sequence uses blocking std::fs APIs. // Run it on Tokio's blocking pool so we don't stall async tasks. From 4cd1248d1a35f64855dee8fbe37d1d6e2287e8a6 Mon Sep 17 00:00:00 2001 From: Tim Anglade Date: Fri, 19 Jun 2026 01:09:20 -0700 Subject: [PATCH 2/3] fix: apply cargo fmt formatting --- src/state/mod.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/state/mod.rs b/src/state/mod.rs index f1c3a7e..c0073f9 100644 --- a/src/state/mod.rs +++ b/src/state/mod.rs @@ -137,9 +137,9 @@ impl State { /// If a field isn't provided via args/env, we fall back to the state file. pub(crate) async fn new(args: Args) -> Result { if let Some(parent) = args.state_file.parent() { - fs::create_dir_all(parent) - .await - .with_context(|| format!("failed to create state directory {}", parent.display()))?; + fs::create_dir_all(parent).await.with_context(|| { + format!("failed to create state directory {}", parent.display()) + })?; } let mut private_key_pem = None; @@ -370,9 +370,9 @@ impl State { .context("state file has no parent directory")? .to_path_buf(); - fs::create_dir_all(&parent_dir) - .await - .with_context(|| format!("failed to create state directory {}", parent_dir.display()))?; + fs::create_dir_all(&parent_dir).await.with_context(|| { + format!("failed to create state directory {}", parent_dir.display()) + })?; // The tempfile + fsync + rename sequence uses blocking std::fs APIs. // Run it on Tokio's blocking pool so we don't stall async tasks. From 6e77291d47e7bea249e97f82548ce4d898b77d0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Chatlamet?= Date: Tue, 23 Jun 2026 07:17:17 +0000 Subject: [PATCH 3/3] state: set 0o700 permissions on state directory --- src/state/mod.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/state/mod.rs b/src/state/mod.rs index c0073f9..22dc335 100644 --- a/src/state/mod.rs +++ b/src/state/mod.rs @@ -140,6 +140,17 @@ impl State { fs::create_dir_all(parent).await.with_context(|| { format!("failed to create state directory {}", parent.display()) })?; + #[cfg(unix)] + { + fs::set_permissions(parent, Permissions::from_mode(0o700)) + .await + .with_context(|| { + format!( + "failed to set permissions on state directory {}", + parent.display() + ) + })?; + } } let mut private_key_pem = None;