{"record":{"id":"e26ed09e9c68bc01","repo":"Hmbown/CodeWhale","slug":"codewhale-credentials-directory-must-be-owned-by-t","errorCode":null,"errorMessage":"Codewhale credentials directory must be owned by the current user","messagePattern":"Codewhale credentials directory must be owned by the current user","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/config/src/xai_credentials.rs","lineNumber":672,"sourceCode":"                    crate::quote_os_path(directory)\n                )\n            });\n        }\n        // SAFETY: `fd` is a newly owned descriptor on the success path above.\n        current = unsafe { File::from_raw_fd(fd) };\n    }\n    let metadata = current.metadata().with_context(|| {\n        format!(\n            \"inspecting Codewhale credentials directory {}\",\n            crate::quote_os_path(directory)\n        )\n    })?;\n    anyhow::ensure!(\n        metadata.is_dir(),\n        \"Codewhale credentials path must be a directory\"\n    );\n    // SAFETY: geteuid(2) dereferences no pointers.\n    anyhow::ensure!(\n        metadata.uid() == unsafe { libc::geteuid() },\n        \"Codewhale credentials directory must be owned by the current user\"\n    );\n    current\n        .set_permissions(fs::Permissions::from_mode(0o700))\n        .with_context(|| {\n            format!(\n                \"securing Codewhale credentials directory {}\",\n                crate::quote_os_path(directory)\n            )\n        })?;\n    Ok(XaiOAuthCredentialStore {\n        directory: directory.to_path_buf(),\n        directory_handle: current,\n    })\n}\n\n#[cfg(unix)]","sourceCodeStart":654,"sourceCodeEnd":690,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/config/src/xai_credentials.rs#L654-L690","documentation":"The credentials directory must be owned by the effective UID of the running process. This is a hardening check against credential theft via another account's directory; the store also force-sets 0o700 permissions after the check. Opening the store fails if the directory owner differs from geteuid().","triggerScenarios":"Calling open when the credentials directory is owned by root or another user — e.g. a previous run used sudo, or the directory was created by a system package/installer.","commonSituations":"Running the CLI once with sudo created a root-owned ~/.codewhale; a Docker container copied the directory as root; an admin pre-created the directory.","solutions":["Chown the directory back to the current user: `sudo chown -R $(id -u):$(id -g) ~/.codewhale`.","Avoid running the tool with sudo; re-authenticate as the normal user.","In containers, create the directory as the runtime USER before the first run.","If a pre-provisioned directory is required, create it with the same UID that runs the app."],"exampleFix":"// shell fix\n# sudo chown -R $(id -u):$(id -g) ~/.codewhale\n// guard before calling open\nlet md = std::fs::metadata(dir)?;\nanyhow::ensure!(md.uid() == unsafe { libc::geteuid() }, \"dir not owned by current user\");","handlingStrategy":"validation","validationCode":"#[cfg(unix)]\nfn owned_by_current_user(dir: &Path) -> bool {\n    std::os::unix::fs::MetadataExt::uid(&std::fs::metadata(dir).unwrap())\n        == unsafe { libc::geteuid() }\n}","typeGuard":null,"tryCatchPattern":"match XaiOAuthCredentialStore::open(dir) {\n    Ok(s) => s,\n    Err(e) if e.to_string().contains(\"owned by the current user\") => {\n        // instruct user to chown or re-run without sudo\n        bail!(\"fix ownership: sudo chown -R $(id -u):$(id -g) {}\", dir.display());\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Never run the CLI under sudo","Create credential directories as the runtime user in Dockerfiles","Chown after restoring from backups/rsync"],"tags":["permissions","ownership","security","unix"],"backgroundTag":"permission-denied","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}