{"record":{"id":"9b5092d2cddc3c37","repo":"Hmbown/CodeWhale","slug":"deepseek-harness-import-requires-a-dsh-cli-grant","errorCode":null,"errorMessage":"DeepSeek Harness import requires a dsh_cli grant, not {}","messagePattern":"DeepSeek Harness import requires a dsh_cli grant, not (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/dsh_credentials.rs","lineNumber":18,"sourceCode":"//! Read-only DeepSeek Harness credential import.\n//!\n//! Official `dsh` stores API keys as a YAML mapping in\n//! `$DSH_HOME/.credentials.yaml`. Codewhale may read `DEEPSEEK_API_KEY` from\n//! that exact file only after `codewhale auth external-consent`. The file is\n//! never written, refreshed, or loaded into the process environment.\n\nuse anyhow::{Result, bail};\nuse codewhale_config::ExternalCredentialReadGrant;\n\nconst DEEPSEEK_API_KEY_REF: &str = \"DEEPSEEK_API_KEY\";\n\n/// Extract the DeepSeek API key from a granted dsh credentials document.\npub(crate) fn deepseek_api_key_from_grant(\n    grant: &ExternalCredentialReadGrant,\n) -> Result<Option<String>> {\n    if grant.source() != codewhale_config::ExternalCredentialSource::DshCli {\n        bail!(\n            \"DeepSeek Harness import requires a dsh_cli grant, not {}\",\n            grant.source().as_str()\n        );\n    }\n    let Some(text) = crate::external_credentials::read_to_string(grant)? else {\n        return Ok(None);\n    };\n    parse_dsh_deepseek_api_key(&text)\n}\n\n/// Strict subset of dsh-credentials-local: a mapping of POSIX identifiers to\n/// non-empty strings. Nested values, empty strings, and duplicate keys fail\n/// closed. Only `DEEPSEEK_API_KEY` is returned.\npub(crate) fn parse_dsh_deepseek_api_key(text: &str) -> Result<Option<String>> {\n    let mut found = None;\n    let mut seen = std::collections::BTreeSet::new();\n    for (index, raw) in text.lines().enumerate() {\n        let line = raw.trim();","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/dsh_credentials.rs#L1-L36","documentation":"`deepseek_api_key_from_grant` imports a DeepSeek API key from an external credential grant document. It requires the grant's source to be `DshCli` (the DeepSeek Harness CLI); any other credential source is rejected with this error naming the actual source. This prevents misreading credentials minted for a different provider.","triggerScenarios":"Passing an `ExternalCredentialReadGrant` whose `source()` is not `ExternalCredentialSource::DshCli` into the DeepSeek Harness import path — e.g. wiring a github-cli or other provider's grant to the DSH importer by mistake.","commonSituations":"Config or routing logic selecting the wrong stored credential; user stored DeepSeek credentials under a generic source; code refactor passing grants between providers without checking source.","solutions":["Grant the credential through the DeepSeek Harness CLI (`dsh`) so the source is `dsh_cli`, then retry the import.","Check which credential source is configured/selected and switch to the dsh_cli-sourced grant.","If the key genuinely lives in another source, import it through that source's own path instead of the DSH one."],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":null,"typeGuard":"fn is_dsh_cli_grant(grant: &ExternalCredentialReadGrant) -> bool {\n    grant.source() == codewhale_config::ExternalCredentialSource::DshCli\n}","tryCatchPattern":"if !is_dsh_cli_grant(&grant) {\n    // route to the correct provider's import path instead of the DSH one\n}","preventionTips":["Check `grant.source()` before handing a grant to any provider-specific importer.","Create DeepSeek credentials through the dsh CLI so the source is recorded as dsh_cli.","Never reuse grant documents across providers in automation."],"tags":["deepseek","credentials","grant","validation"],"backgroundTag":"invalid-enum-value","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"}