Redact command environment variables from log output (#32985)
Before/After (linebreaks added for readability) ```log # before INFO [project::context_server_store::extension] loaded command for context server mcp-server-github: Command { command: "/Users/peter/Library/Application Support/Zed/extensions/work/mcp-server-github/github-mcp-server-v0.5.0/github-mcp-server", args: ["stdio"], env: [("GITHUB_PERSONAL_ACCESS_TOKEN", "gho_WOOOOOOOOOOOOOOO")] } #after INFO [project::context_server_store::extension] loaded command for context server mcp-server-github: Command { command: "/Users/peter/Library/Application Support/Zed/extensions/work/mcp-server-github/github-mcp-server-v0.5.0/github-mcp-server", args: ["stdio"], env: [("GITHUB_PERSONAL_ACCESS_TOKEN", "[REDACTED]")] } ``` Release Notes: - Redact sensitive environment variables from MCP logs
This commit is contained in:
parent
76e3136369
commit
a713c66a9d
4 changed files with 45 additions and 2 deletions
|
@ -16,6 +16,7 @@ use gpui::AsyncApp;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use util::redact::should_redact;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct ContextServerId(pub Arc<str>);
|
pub struct ContextServerId(pub Arc<str>);
|
||||||
|
@ -26,13 +27,29 @@ impl Display for ContextServerId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Clone, PartialEq, Eq, JsonSchema, Debug)]
|
#[derive(Deserialize, Serialize, Clone, PartialEq, Eq, JsonSchema)]
|
||||||
pub struct ContextServerCommand {
|
pub struct ContextServerCommand {
|
||||||
pub path: String,
|
pub path: String,
|
||||||
pub args: Vec<String>,
|
pub args: Vec<String>,
|
||||||
pub env: Option<HashMap<String, String>>,
|
pub env: Option<HashMap<String, String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for ContextServerCommand {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let filtered_env = self.env.as_ref().map(|env| {
|
||||||
|
env.iter()
|
||||||
|
.map(|(k, v)| (k, if should_redact(k) { "[REDACTED]" } else { v }))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
});
|
||||||
|
|
||||||
|
f.debug_struct("ContextServerCommand")
|
||||||
|
.field("path", &self.path)
|
||||||
|
.field("args", &self.args)
|
||||||
|
.field("env", &filtered_env)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enum ContextServerTransport {
|
enum ContextServerTransport {
|
||||||
Stdio(ContextServerCommand),
|
Stdio(ContextServerCommand),
|
||||||
Custom(Arc<dyn crate::transport::Transport>),
|
Custom(Arc<dyn crate::transport::Transport>),
|
||||||
|
|
|
@ -5,6 +5,8 @@ mod slash_command;
|
||||||
|
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
|
use util::redact::should_redact;
|
||||||
|
|
||||||
pub use context_server::*;
|
pub use context_server::*;
|
||||||
pub use dap::*;
|
pub use dap::*;
|
||||||
pub use lsp::*;
|
pub use lsp::*;
|
||||||
|
@ -14,7 +16,6 @@ pub use slash_command::*;
|
||||||
pub type EnvVars = Vec<(String, String)>;
|
pub type EnvVars = Vec<(String, String)>;
|
||||||
|
|
||||||
/// A command.
|
/// A command.
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Command {
|
pub struct Command {
|
||||||
/// The command to execute.
|
/// The command to execute.
|
||||||
pub command: String,
|
pub command: String,
|
||||||
|
@ -24,6 +25,22 @@ pub struct Command {
|
||||||
pub env: EnvVars,
|
pub env: EnvVars,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for Command {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let filtered_env = self
|
||||||
|
.env
|
||||||
|
.iter()
|
||||||
|
.map(|(k, v)| (k, if should_redact(k) { "[REDACTED]" } else { v }))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
f.debug_struct("Command")
|
||||||
|
.field("command", &self.command)
|
||||||
|
.field("args", &self.args)
|
||||||
|
.field("env", &filtered_env)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A label containing some code.
|
/// A label containing some code.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct CodeLabel {
|
pub struct CodeLabel {
|
||||||
|
|
8
crates/util/src/redact.rs
Normal file
8
crates/util/src/redact.rs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
/// Whether a given environment variable name should have its value redacted
|
||||||
|
pub fn should_redact(env_var_name: &str) -> bool {
|
||||||
|
const REDACTED_SUFFIXES: &[&str] =
|
||||||
|
&["KEY", "TOKEN", "PASSWORD", "SECRET", "PASS", "CREDENTIALS"];
|
||||||
|
REDACTED_SUFFIXES
|
||||||
|
.iter()
|
||||||
|
.any(|suffix| env_var_name.ends_with(suffix))
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ pub mod command;
|
||||||
pub mod fs;
|
pub mod fs;
|
||||||
pub mod markdown;
|
pub mod markdown;
|
||||||
pub mod paths;
|
pub mod paths;
|
||||||
|
pub mod redact;
|
||||||
pub mod serde;
|
pub mod serde;
|
||||||
pub mod shell_env;
|
pub mod shell_env;
|
||||||
pub mod size;
|
pub mod size;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue