mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-31 11:01:36 +08:00
fix(hermes): prevent YAML pollution and drop of OAuth mcp auth
DeepLink Hermes import was emitting camelCase (baseUrl / apiKey / apiMode) that the Hermes runtime does not recognise, poisoning `custom_providers:` entries on activation. The MCP sync path was also stripping `auth: oauth` on round-trip, silently downgrading OAuth-type servers to unauthenticated calls. The Hermes deeplink branch now emits snake_case via a dedicated builder; `sanitize_hermes_provider_keys` runs on both `set_provider` and `get_providers` so legacy DB records heal on next access. `HERMES_EXTRA_FIELDS` preserves `auth`. The `api_mode` dropdown gains `codex_responses` (Copilot / OpenCode), and the schema-migrated warning copy no longer hard-codes "v12" (upstream `_config_version` is now 19).
This commit is contained in:
@@ -25,6 +25,10 @@ use super::validation::validate_server_spec;
|
||||
|
||||
/// Hermes-specific fields preserved on merge-on-write, stripped on import.
|
||||
/// Update this list when Hermes adds new per-server config fields.
|
||||
///
|
||||
/// `auth` ("oauth" / absent) is an OAuth-type declaration read by Hermes —
|
||||
/// CC Switch has no OAuth UI, but losing the field on round-trip downgrades
|
||||
/// the server to unauthenticated calls.
|
||||
const HERMES_EXTRA_FIELDS: &[&str] = &[
|
||||
"enabled",
|
||||
"timeout",
|
||||
@@ -32,6 +36,7 @@ const HERMES_EXTRA_FIELDS: &[&str] = &[
|
||||
"tools",
|
||||
"sampling",
|
||||
"roots",
|
||||
"auth",
|
||||
];
|
||||
|
||||
// ============================================================================
|
||||
@@ -506,6 +511,47 @@ mod tests {
|
||||
assert_eq!(merged["enabled"], true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_merge_preserves_auth_field() {
|
||||
let existing = json!({
|
||||
"url": "https://mcp.example.com",
|
||||
"auth": "oauth",
|
||||
"enabled": true
|
||||
});
|
||||
|
||||
let new_spec = json!({
|
||||
"url": "https://mcp.example.com/updated",
|
||||
"headers": { "X-Trace": "abc" },
|
||||
"enabled": true
|
||||
});
|
||||
|
||||
let merged = merge_hermes_spec(&existing, &new_spec);
|
||||
|
||||
assert_eq!(merged["url"], "https://mcp.example.com/updated");
|
||||
assert_eq!(merged["headers"]["X-Trace"], "abc");
|
||||
assert_eq!(
|
||||
merged["auth"], "oauth",
|
||||
"auth declaration must survive CC Switch round-trip"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_convert_hermes_strips_auth_on_import() {
|
||||
let spec = json!({
|
||||
"url": "https://mcp.example.com",
|
||||
"auth": "oauth",
|
||||
"enabled": true
|
||||
});
|
||||
|
||||
let result = convert_from_hermes_format("remote", &spec).unwrap();
|
||||
assert_eq!(result["type"], "sse");
|
||||
assert_eq!(result["url"], "https://mcp.example.com");
|
||||
assert!(
|
||||
result.get("auth").is_none(),
|
||||
"auth stays Hermes-specific; stripped from unified format"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_merge_new_server_no_existing_extra_fields() {
|
||||
let existing = json!({
|
||||
|
||||
Reference in New Issue
Block a user