{"record":{"id":"e733b5241af3b8f9","repo":"xai-org/grok-build","slug":"local-workspace-home-denied","errorCode":null,"errorMessage":"{LOCAL_WORKSPACE_HOME_DENIED}","messagePattern":"\\{LOCAL_WORKSPACE_HOME_DENIED\\}","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-pager/src/app/session_startup.rs","lineNumber":522,"sourceCode":"            abs.display()\n        )\n    })?;\n    if !canon.is_dir() {\n        anyhow::bail!(\n            \"local workspace cwd must be an existing directory: {}\",\n            canon.display()\n        );\n    }\n    if env_truthy(GROK_CHAT_LOCAL_WORKSPACE_ALLOW_HOME_ENV) {\n        return Ok(canon);\n    }\n    if canon == std::path::Path::new(\"/\") {\n        anyhow::bail!(\"{LOCAL_WORKSPACE_HOME_DENIED}\");\n    }\n    if let Some(home_path) = xai_dirs::home_dir() {\n        let home_canon = home_path.canonicalize().unwrap_or(home_path);\n        if canon == home_canon {\n            anyhow::bail!(\"{LOCAL_WORKSPACE_HOME_DENIED}\");\n        }\n    }\n    Ok(canon)\n}\n/// Banner and first-run confirm for the local-workspace own and attach modes.\n///\n/// Skip confirm only with `GROK_CHAT_LOCAL_WORKSPACE_ACK=1` or a prior ack file.\n/// Non-TTY without ACK refuses (fail closed).\n#[cfg(feature = \"local-workspace\")]\npub fn emit_local_workspace_startup_ux(cfg: &LocalWorkspaceConfig) -> anyhow::Result<()> {\n    use std::io::IsTerminal;\n    emit_local_workspace_startup_ux_with(cfg, std::io::stdin().is_terminal())\n}\n/// Testable UX gate: `stdin_is_terminal` is injected.\n#[cfg(feature = \"local-workspace\")]\npub fn emit_local_workspace_startup_ux_with(\n    cfg: &LocalWorkspaceConfig,\n    stdin_is_terminal: bool,","sourceCodeStart":504,"sourceCodeEnd":540,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-pager/src/app/session_startup.rs#L504-L540","documentation":"As a safety rail, `validate_local_workspace_cwd` refuses to use the filesystem root `/` or the user's home directory as the local workspace, bailing with `LOCAL_WORKSPACE_HOME_DENIED` (session_startup.rs:517 and 522). This prevents the agent from operating on the whole home tree by accident. The check is skipped when GROK_CHAT_LOCAL_WORKSPACE_ALLOW_HOME is truthy.","triggerScenarios":"Setting the workspace cwd (CLI or env) to `/`, to `$HOME` exactly, or to any path that canonicalizes to home (e.g. `/home/user`, symlinked home, `~` alone) without the allow-home env override.","commonSituations":"Leaving GROK_CHAT_LOCAL_WORKSPACE_CWD unset-but-enabled so it falls back to $HOME; launching from the home directory with cwd-only semantics; symlink alias resolving to home.","solutions":["Choose a dedicated project subdirectory instead of $HOME or `/`","Set GROK_CHAT_LOCAL_WORKSPACE_ALLOW_HOME=1 only if you truly intend home/root scope","cd into a project directory before launching so the default cwd is not home","Check for symlinks that canonicalize to $HOME"],"exampleFix":"// before\ncd ~\ngrok-pager --chat --local-workspace\n// after\ncd ~/projects/my-app\ngrok-pager --chat --local-workspace","handlingStrategy":"validation","validationCode":"fn is_denied_workspace(p: &std::path::Path) -> bool {\n    let canon = p.canonicalize().unwrap_or_else(|_| p.to_path_buf());\n    canon == std::path::Path::new(\"/\")\n        || std::env::var(\"HOME\").ok().map(|h| std::path::PathBuf::from(h).canonicalize().unwrap_or(std::path::PathBuf::from(h))) == Some(canon.clone())\n        || canon.parent().is_none()\n}","typeGuard":null,"tryCatchPattern":"match validate_local_workspace_cwd(&cwd) {\n    Err(e) if e.to_string().contains(\"HOME_DENIED\") || e.to_string().contains(\"denied\") => {\n        eprintln!(\"pick a project subdirectory (or set GROK_CHAT_LOCAL_WORKSPACE_ALLOW_HOME=1 deliberately): {e}\")\n    }\n    other => other?,\n}","preventionTips":["Always cd into a dedicated project directory before enabling local workspace","Never set GROK_CHAT_LOCAL_WORKSPACE_CWD to ~ or /","Avoid symlink aliases that resolve to $HOME","Treat GROK_CHAT_LOCAL_WORKSPACE_ALLOW_HOME as a last resort"],"tags":["filesystem","safety","local-workspace","path-validation"],"backgroundTag":"workspace-root-denied","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}