{"record":{"id":"81474622bd904914","repo":"Hmbown/CodeWhale","slug":"is-a-symbolic-link-not-a-workspace-owned-file","errorCode":null,"errorMessage":"{} is a symbolic link, not a workspace-owned file","messagePattern":"(.+?) is a symbolic link, not a workspace-owned file","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/lib.rs","lineNumber":3054,"sourceCode":"        .map_err(|error| anyhow!(\"could not securely open {}: {error}\", path.display()))?;\n    let metadata = file\n        .metadata()\n        .map_err(|error| anyhow!(\"could not inspect {}: {error}\", path.display()))?;\n    if metadata.file_attributes() & FILE_ATTRIBUTE_REPARSE_POINT != 0 {\n        bail!(\n            \"{} is a reparse point, not a workspace-owned file\",\n            path.display()\n        );\n    }\n    Ok(file)\n}\n\n#[cfg(not(any(unix, windows)))]\nfn open_workspace_dotenv_without_following_links(path: &Path) -> Result<std::fs::File> {\n    let metadata = std::fs::symlink_metadata(path)\n        .map_err(|error| anyhow!(\"could not inspect {}: {error}\", path.display()))?;\n    if metadata.file_type().is_symlink() {\n        bail!(\n            \"{} is a symbolic link, not a workspace-owned file\",\n            path.display()\n        );\n    }\n    std::fs::File::open(path)\n        .map_err(|error| anyhow!(\"could not securely open {}: {error}\", path.display()))\n}\n\n/// Generate shell completions for the given shell\nfn generate_completions(shell: Shell) {\n    let mut cmd = Cli::command();\n    let name = cmd.get_name().to_string();\n    generate(shell, &mut cmd, name, &mut io::stdout());\n}\n\n/// Run the offline evaluation harness (no network/LLM calls).\nfn run_eval(args: EvalArgs) -> Result<()> {\n    let fail_step = match args.fail_step.as_deref() {","sourceCodeStart":3036,"sourceCodeEnd":3072,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/lib.rs#L3036-L3072","documentation":"On platforms other than unix/windows, open_workspace_dotenv_without_following_links inspects symlink_metadata; if the path itself is a symbolic link, it bails because a symlinked .env could point outside the workspace and swap targets after validation. Only a plain, self-owned regular file is accepted as a credential source.","triggerScenarios":"Running Codewhale on a non-unix/non-windows platform where the workspace `.env` is a symbolic link to another file.","commonSituations":"Symlinking .env from a shared secrets directory or dotfiles manager on an unusual platform (e.g. wasm/other targets), or a tool that materializes config as symlinks.","solutions":["Replace the symlink with a real copy of the target file inside the workspace.","Check with `ls -la .env` / `readlink .env` and remove the link, then `cp` the content in.","Configure your dotfiles/secret manager to write real files in the workspace instead of symlinks.","If you believe this platform is unsupported for this path, run on a supported platform (unix/windows) where O_NOFOLLOW-style secure open is used."],"exampleFix":"// before\nln -s /home/user/.secrets/codewhale.env .env\n// after\nrm .env && cp /home/user/.secrets/codewhale.env .env","handlingStrategy":"validation","validationCode":"// shell\n[ ! -L .env ] || { echo '.env must not be a symlink'; exit 1; }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Materialize real files, not symlinks, in workspaces on non-unix/windows targets.","Configure dotfile managers to copy or template config files in place.","Verify with `readlink .env` before launch."],"tags":["symlink","dotenv","filesystem","security"],"backgroundTag":"path-traversal-blocked","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"}