{"record":{"id":"568e5c387b6be527","repo":"astrid-runtime/astrid","slug":"private-directory-is-not-owner-only","errorCode":null,"errorMessage":"private directory is not owner-only: {}","messagePattern":"private directory is not owner-only: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-core/src/platform_fs.rs","lineNumber":506,"sourceCode":"}\n\n#[cfg(unix)]\nfn validate_private_directory_unix(path: &Path) -> io::Result<()> {\n    use std::os::unix::fs::{MetadataExt as _, PermissionsExt as _};\n\n    let directory = open_directory_no_follow_unix(path)?;\n    let metadata = directory.metadata()?;\n    if metadata.uid() != nix::unistd::getuid().as_raw() {\n        return Err(io::Error::new(\n            io::ErrorKind::PermissionDenied,\n            format!(\n                \"private directory is not owned by the current user: {}\",\n                path.display()\n            ),\n        ));\n    }\n    if metadata.permissions().mode() & 0o777 != 0o700 {\n        return Err(io::Error::new(\n            io::ErrorKind::PermissionDenied,\n            format!(\"private directory is not owner-only: {}\", path.display()),\n        ));\n    }\n    validate_no_extended_acl(path)?;\n    Ok(())\n}\n\n#[cfg(unix)]\nfn restrict_private_file_unix(path: &Path) -> io::Result<()> {\n    use nix::sys::stat::{Mode, fchmod, fstat};\n\n    let file = open_file_no_follow_unix(path)?;\n    let metadata = fstat(&file).map_err(nix_io_error)?;\n    if metadata.st_mode & 0o170_000 != 0o100_000 {\n        return Err(io::Error::new(\n            io::ErrorKind::InvalidData,\n            format!(\"private path is not a regular file: {}\", path.display()),","sourceCodeStart":488,"sourceCodeEnd":524,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-core/src/platform_fs.rs#L488-L524","documentation":"validate_private_directory_unix requires the directory's permission mode to be exactly 0700 (owner read/write/execute, nothing for group or other). Any looser mode (e.g. 0755 or 0770) widens access beyond the owner and fails with io::ErrorKind::PermissionDenied. Extended ACLs are checked separately afterwards.","triggerScenarios":"Calling validate_private_directory or ensure_private_directory_unix on an existing directory whose mode & 0o777 != 0o700 — typically a 0755 layout-1 leftover or a umask-loosened mkdir.","commonSituations":"Older Astrid layouts (0755 COW slots/unpacked homes) after upgrade; restores that lost the 0700 bit; processes with permissive umask creating the directory first.","solutions":["chmod 700 the directory (and any nested real directories), or call ensure_private_directory / ensure_private_directory_tree which repairs modes automatically.","Remove the permissive directory and let the library recreate it with 0700.","Check for tools (backups, sync clients) that rewrite permissions and re-run validation after they run."],"exampleFix":"// before (shell)\nls -ld ~/.astrid  // drwxr-xr-x\n// after (shell)\nchmod 700 ~/.astrid\n// or in Rust: let the library repair it\nensure_private_directory_tree(&home.join(\".astrid\"))?;","handlingStrategy":"validation","validationCode":"#[cfg(unix)]\nfn is_owner_only(p: &std::path::Path) -> std::io::Result<bool> {\n    use std::os::unix::fs::PermissionsExt;\n    Ok(std::fs::metadata(p)?.permissions().mode() & 0o777 == 0o700)\n}","typeGuard":"#[cfg(unix)]\nfn has_0700(p: &std::path::Path) -> bool {\n    use std::os::unix::fs::PermissionsExt;\n    std::fs::metadata(p)\n        .map(|m| m.permissions().mode() & 0o777 == 0o700)\n        .unwrap_or(false)\n}","tryCatchPattern":"match validate_private_directory(&dir) {\n    Err(e) if e.kind() == io::ErrorKind::PermissionDenied && e.to_string().contains(\"owner-only\") => {\n        #[cfg(unix)]\n        {\n            use std::os::unix::fs::PermissionsExt;\n            std::fs::set_permissions(&dir, std::fs::Permissions::from_mode(0o700))?;\n        }\n    }\n    other => other?,\n}","preventionTips":["Set a restrictive umask (077) for processes that create private state","Call ensure_private_directory/ensure_private_directory_tree to repair modes automatically","Audit for tools (sync/backup clients) that loosen permissions on the private tree"],"tags":["io","filesystem","permissions","security"],"backgroundTag":"insufficient-permissions","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}