{"record":{"id":"cbe462233b6a2106","repo":"jlcodes99/cockpit-tools","slug":"oauth-client","errorCode":null,"errorMessage":"默认 OAuth client 配置无效","messagePattern":"默认 OAuth client 配置无效","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/cockpit-core/src/modules/oauth.rs","lineNumber":77,"sourceCode":"        Some(key) if key.is_empty() => Ok(DEFAULT_OAUTH_CLIENT_KEY.to_string()),\n        Some(key) => Err(format!(\n            \"未知 OAuth client: {}，当前版本仅支持 {}\",\n            key, DEFAULT_OAUTH_CLIENT_KEY\n        )),\n        None => Ok(DEFAULT_OAUTH_CLIENT_KEY.to_string()),\n    }\n}\n\nfn oauth_client_config(\n    preferred: Option<&str>,\n) -> Result<(&'static str, &'static str, String), String> {\n    let key = resolve_oauth_client_key(preferred)?;\n    Ok((CLIENT_ID, CLIENT_SECRET, key))\n}\n\n/// 生成 OAuth 授权 URL\npub fn get_auth_url(redirect_uri: &str, state: Option<&str>) -> String {\n    let (client_id, _, _) = oauth_client_config(None).expect(\"默认 OAuth client 配置无效\");\n    let scopes = vec![\n        \"openid\",\n        \"https://www.googleapis.com/auth/cloud-platform\",\n        \"https://www.googleapis.com/auth/userinfo.email\",\n        \"https://www.googleapis.com/auth/userinfo.profile\",\n        \"https://www.googleapis.com/auth/cclog\",\n        \"https://www.googleapis.com/auth/experimentsandconfigs\",\n    ]\n    .join(\" \");\n\n    let mut params = vec![\n        (\"client_id\", client_id),\n        (\"redirect_uri\", redirect_uri),\n        (\"response_type\", \"code\"),\n        (\"scope\", &scopes),\n        (\"access_type\", \"offline\"),\n        (\"prompt\", \"consent\"),\n    ];","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/jlcodes99/cockpit-tools/blob/1ed8b77992d62ca81fabf744deb0839ad361d5bf/crates/cockpit-core/src/modules/oauth.rs#L59-L95","documentation":"get_auth_url in crates/cockpit-core/src/modules/oauth.rs:77 builds the Google OAuth authorization URL and calls oauth_client_config(None).expect(\"默认 OAuth client 配置无效\"). The Err path comes from resolve_oauth_client_key, which only fails when a preferred client key that is not the default is supplied. Since get_auth_url passes None, the resolver always returns the default key, so this panic is a defensive guard and is effectively unreachable at runtime unless the code is changed to forward a user-specified client key.","triggerScenarios":"Only when the call chain is modified so that get_auth_url forwards a preferred client identifier that is non-empty and does not equal DEFAULT_OAUTH_CLIENT_KEY (case-insensitively), causing resolve_oauth_client_key to return Err and .expect to panic.","commonSituations":"A developer adds multi-client support or a configurable client key and passes an unsupported/renamed key (e.g. a provider preset renamed or removed in a new version) into get_auth_url; end users never hit this directly.","solutions":["Keep calling get_auth_url with no preferred client (the only currently supported key) so the resolver returns the default.","If adding a custom client, extend resolve_oauth_client_key to accept the new key instead of passing an unknown one.","Change get_auth_url to return Result<String, String> and propagate the error from oauth_client_config instead of using .expect."],"exampleFix":"// before\nlet (client_id, _, _) = oauth_client_config(None).expect(\"默认 OAuth client 配置无效\");\n// after\nlet (client_id, _, _) = oauth_client_config(None)?; // fn get_auth_url(...) -> Result<String, String>","handlingStrategy":"validation","validationCode":"// Callers of get_auth_url today cannot trigger this (None is always Ok), but if you pass a preferred key:\nconst supported = [\"default\"];\nif (preferred && !supported.includes(preferred.trim().toLowerCase())) {\n  throw new Error(`未知 OAuth client: ${preferred}`);\n}","typeGuard":"function isSupportedOAuthClient(key: string): boolean {\n  return key.trim().toLowerCase() === 'default';\n}","tryCatchPattern":"// Rust callers of a Result-returning variant:\nlet url = get_auth_url_checked(redirect_uri, state)\n    .unwrap_or_else(|e| { log::error!(\"oauth config: {e}\"); String::new() });","preventionTips":["Never pass an unknown preferred client key; use only the supported default.","Prefer returning Result over .expect when adding configurable client support.","Add a unit test asserting oauth_client_config(None) is Ok."],"tags":["rust","oauth","panic","configuration"],"backgroundTag":"invalid-oauth-client-config","analyzedSha":"1ed8b77992d62ca81fabf744deb0839ad361d5bf","analyzedAt":"2026-09-05T09:51:41.178Z","contentChangedAt":"2026-09-05T09:51:41.178Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}