From a18f5c760490bf1d389492eb5aae1afab5fec0f5 Mon Sep 17 00:00:00 2001 From: Marco Allegretti Date: Wed, 11 Mar 2026 18:52:54 +0100 Subject: [PATCH] fix(file-portal): create parent directories on write std::fs::write fails when the destination parent does not exist. Add create_dir_all before the write so apps can store files in nested paths (e.g. config/sub/settings.json) without pre-creating directories. Add regression test for the nested-path case. --- crates/weft-file-portal/src/main.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/crates/weft-file-portal/src/main.rs b/crates/weft-file-portal/src/main.rs index 23a87c8..5fb7ed8 100644 --- a/crates/weft-file-portal/src/main.rs +++ b/crates/weft-file-portal/src/main.rs @@ -142,6 +142,9 @@ fn handle_request(req: Request, allowed: &[PathBuf]) -> Response { Ok(d) => d, Err(e) => return Response::err(format!("bad base64: {e}")), }; + if let Some(Err(e)) = p.parent().map(std::fs::create_dir_all) { + return Response::err(e); + } match std::fs::write(&p, &data) { Ok(()) => Response::Ok, Err(e) => Response::err(e), @@ -273,4 +276,27 @@ mod tests { let _ = fs::remove_dir_all(&dir); } + + #[test] + fn handle_request_write_creates_parent_dirs() { + use std::fs; + let dir = std::env::temp_dir().join(format!("wfp_write_{}", std::process::id())); + let _ = fs::remove_dir_all(&dir); + let nested = dir.join("sub").join("deep").join("file.txt"); + let data = base64::Engine::encode( + &base64::engine::general_purpose::STANDARD, + b"nested content", + ); + let allowed = vec![dir.clone()]; + let resp = handle_request( + Request::Write { + path: nested.to_string_lossy().into(), + data_b64: data, + }, + &allowed, + ); + assert!(matches!(resp, Response::Ok), "expected Ok response"); + assert_eq!(fs::read(&nested).unwrap(), b"nested content"); + let _ = fs::remove_dir_all(&dir); + } }