{"record":{"id":"5bfae6958120e8b7","repo":"Hmbown/CodeWhale","slug":"invalid-codewhale-owned-xai-oauth-basename","errorCode":null,"errorMessage":"invalid Codewhale-owned xAI OAuth basename","messagePattern":"invalid Codewhale-owned xAI OAuth basename","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/config/src/xai_credentials.rs","lineNumber":431,"sourceCode":"\n    /// Permanently remove retired bytes after the replacement config commits.\n    pub fn commit(self, store: &XaiOAuthCredentialStore) -> Result<usize> {\n        let mut removed = 0;\n        for (_original, _tombstone) in self.retired {\n            #[cfg(windows)]\n            let target = _original;\n            #[cfg(not(windows))]\n            let target = _tombstone;\n            if store.remove_raw(&target)? {\n                removed += 1;\n            }\n        }\n        Ok(removed)\n    }\n}\n\nfn validate_owned_auth_name(name: &str) -> Result<()> {\n    anyhow::ensure!(\n        name == LEGACY_XAI_OAUTH_FILE_NAME || is_valid_xai_oauth_generation(name),\n        \"invalid Codewhale-owned xAI OAuth basename\"\n    );\n    Ok(())\n}\n\nfn validate_private_basename(name: &str) -> Result<()> {\n    let path = Path::new(name);\n    anyhow::ensure!(\n        path.components().count() == 1\n            && matches!(path.components().next(), Some(Component::Normal(_)))\n            && path.file_name().and_then(|value| value.to_str()) == Some(name),\n        \"xAI OAuth private basename must be one UTF-8 path component\"\n    );\n    Ok(())\n}\n\n#[cfg(unix)]","sourceCodeStart":413,"sourceCodeEnd":449,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/crates/config/src/xai_credentials.rs#L413-L449","documentation":"Thrown by every public XaiOAuthCredentialStore accessor (path_for, read_to_string, write, remove) via validate_owned_auth_name when the supplied basename is neither the legacy name `xai-auth.json` nor a valid generation `xai-auth-<32 lowercase hex>.json`. The crate stores only a validated basename so a config-controlled generation pointer can never become an arbitrary path read/delete primitive. It is a fail-closed input-validation error at the credentials-store trust boundary.","triggerScenarios":"Calling store.write(\"xai-auth-abc.json\", ...) with a hex id that is not exactly 32 chars; uppercase hex (\"xai-auth-ABC...\"); missing or wrong prefix/suffix (\"xai-auth-<32hex>\" without \".json\", \"auth-<32hex>.json\"); passing a full path (\"credentials/xai-auth.json\") or any arbitrary string to a store API.","commonSituations":"Tests or scripts hand-building generation names instead of deriving them from the config pointer; truncated or uppercased UUIDs; hand-edited config files pointing at renamed files; version upgrades that changed the naming scheme while stale names linger.","solutions":["Use exactly `xai-auth.json` or `xai-auth-` + 32 lowercase hex characters + `.json`","Pre-validate with the public codewhale_config::is_valid_xai_oauth_generation(name) before calling store APIs","Derive the name from the config generation pointer instead of constructing it by hand","Let the CLI own naming: run `codewhale auth xai-device` instead of writing credential files directly"],"exampleFix":"// before\nstore.write(\"xai-auth-ABCDEF0123456789.json\", &bytes, false)?;\n\n// after\nlet name = \"xai-auth-abcdef0123456789abcdef0123456789.json\";\nassert!(name == codewhale_config::LEGACY_XAI_OAUTH_FILE_NAME\n    || codewhale_config::is_valid_xai_oauth_generation(name));\nstore.write(name, &bytes, false)?;","handlingStrategy":"type-guard","validationCode":"fn valid_store_basename(name: &str) -> bool {\n    name == codewhale_config::LEGACY_XAI_OAUTH_FILE_NAME\n        || codewhale_config::is_valid_xai_oauth_generation(name)\n}\n\n// before any store call\nanyhow::ensure!(valid_store_basename(name), \"bad generation name: {name}\");","typeGuard":"pub fn is_usable_store_name(name: &str) -> bool {\n    name == codewhale_config::LEGACY_XAI_OAUTH_FILE_NAME\n        || codewhale_config::is_valid_xai_oauth_generation(name)\n}","tryCatchPattern":"match store.write(name, &bytes, false) {\n    Ok(()) => {}\n    Err(e) if e.to_string().contains(\"invalid Codewhale-owned xAI OAuth basename\") => {\n        return Err(e.context(\"generation name must be xai-auth-<32 lowercase hex>.json or xai-auth.json\"));\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Always derive generation names from the config generation pointer, never construct them ad hoc","Run is_valid_xai_oauth_generation in unit tests that write fixture names","Lowercase and length-check hex ids before formatting them into basenames"],"tags":["rust","validation","security","filesystem","xai-oauth"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}