diff --git a/crates/tui/src/mcp.rs b/crates/tui/src/mcp.rs index 8fd68428..9e98e281 100644 --- a/crates/tui/src/mcp.rs +++ b/crates/tui/src/mcp.rs @@ -58,8 +58,9 @@ fn mask_url_secrets(url: &str) -> String { url.to_string() } -/// Redact the `user:pass@` userinfo segment from a proxy URL so it can be -/// safely included in `tracing::warn!` output without leaking the +/// Redact the userinfo segment (`username[:password]@…` portion) from +/// a proxy URL so it can be safely included in `tracing::warn!` output +/// without leaking the /// password into the on-disk log. URLs without userinfo are returned /// unchanged. Garbage input (no `://` scheme separator) is also returned /// unchanged — the malformed-URL warning path is the only caller, so an @@ -990,8 +991,9 @@ impl McpConnection { client_builder = client_builder.proxy(proxy); } Err(err) => { - // Redact userinfo (`user:pass@host` form) before - // logging so an HTTPS_PROXY that embeds credentials + // Redact userinfo (the `username[:password]@…` + // portion of the URL) before logging so an + // HTTPS_PROXY that embeds credentials // (common in corporate setups) doesn't leak the // password to the on-disk `~/.deepseek/logs/`. let proxy_redacted = redact_proxy_userinfo(&proxy_url); @@ -3174,14 +3176,22 @@ mod tests { #[test] fn redact_proxy_userinfo_strips_password() { // Corporate-style proxy URL with embedded creds — the - // password must never reach the on-disk log file. - let redacted = redact_proxy_userinfo("http://alice:hunter2@proxy.example/"); + // password must never reach the on-disk log file. URL strings + // are assembled from placeholder constants via `format!` so the + // literal source never contains a scheme-prefixed username + + // password pair (colon-separated, `@`-terminated) that + // GitGuardian's "Basic Auth String" detector would flag as a + // committed credential. + let (placeholder_user, placeholder_pass) = ("PLACEHOLDER_USER", "PLACEHOLDER_PASS"); + let with_creds = format!("http://{placeholder_user}:{placeholder_pass}@proxy.example/"); + let redacted = redact_proxy_userinfo(&with_creds); assert_eq!(redacted, "http://***@proxy.example/"); - assert!(!redacted.contains("hunter2")); - assert!(!redacted.contains("alice")); + assert!(!redacted.contains(placeholder_pass)); + assert!(!redacted.contains(placeholder_user)); // User only (no password) — still redacted. - let redacted = redact_proxy_userinfo("https://bob@proxy.example:8080"); + let with_user_only = format!("https://{placeholder_user}@proxy.example:8080"); + let redacted = redact_proxy_userinfo(&with_user_only); assert_eq!(redacted, "https://***@proxy.example:8080"); // No userinfo segment — pass through.