修复: unwrap 吞错 + lock 中毒 panic 高危项(数据吞 warn 跳过 / lock 降级返 Err)

This commit is contained in:
lxy
2026-08-01 12:21:52 +08:00
parent 143b859727
commit 484080ac12
6 changed files with 184 additions and 27 deletions
+35 -2
View File
@@ -114,22 +114,55 @@ pub async fn get_provider_secret_async(id: String) -> Option<String> {
}
/// 消费点用:解析 provider 真实密钥 — DB 优先,fallback keyring(兼容未迁移老库)
///
/// **不静默压空**:keyring 无记录/读取故障(None 已合并 keyring Err)时,这里**不**用 `unwrap_or_default()`
/// 静默吞成空串 —— 那会让调用方拿空 api_key 发请求吃 401,错误伪装成「密钥无效」且无线索。改为
/// warn 留痕(区分「真正未配置密钥」与「keyring 后端故障」),仍返空串交由下游 `ensure_resolved_key`
/// 早失败给出用户可读错误 —— 签名不变,调用方零改动。
pub fn resolve_provider_secret(record: &AiProviderRecord) -> String {
if !record.api_key.is_empty() {
return record.api_key.clone();
}
get_provider_secret(&record.id).unwrap_or_default()
match get_provider_secret(&record.id) {
Some(k) => k,
None => {
tracing::warn!(
"[密钥解析] provider {} (id={}) 系统钥匙串无密钥或读取故障 —— \
下游 ensure_resolved_key 将报「密钥缺失」。排查:1) 设置中是否保存过密钥;\
2) OS 钥匙串后端是否可用(Win Credential Manager / macOS Keychain / Linux Secret Service)",
record.name, record.id
);
String::new()
}
}
}
/// [`resolve_provider_secret`] 的 async 版本 — DB 有明文时同步返(不触 keyring),
/// 否则 `spawn_blocking` 调 keyring 防 D-Bus / COM 阻塞 tokio runtime。
///
/// 注:DB 明文路径直接 clone 同步返,只有 fallback keyring 才走 spawn_blocking。
///
/// **不静默压空**:同同步版,keyring 无记录/读取故障时 warn 留痕(不吞成空串致 401 难定位),
/// 仍返空串交由下游 `ensure_resolved_key` 早失败给用户可读错误 —— 签名不变,调用方零改动。
pub async fn resolve_provider_secret_async(record: AiProviderRecord) -> String {
if !record.api_key.is_empty() {
return record.api_key;
}
get_provider_secret_async(record.id).await.unwrap_or_default()
// 先取 id/name 再 await,避免 record 部分移动后无法在 warn 中引用。
let id = record.id.clone();
let name = record.name.clone();
match get_provider_secret_async(id.clone()).await {
Some(k) => k,
None => {
tracing::warn!(
"[密钥解析] provider {} (id={}) 系统钥匙串无密钥或读取故障 —— \
下游 ensure_resolved_key 将报「密钥缺失」。排查:1) 设置中是否保存过密钥;\
2) OS 钥匙串后端是否可用(Win Credential Manager / macOS Keychain / Linux Secret Service)",
name, id
);
String::new()
}
}
}
/// 写入密钥到 keyring(覆盖)