From 52c2b196e2897d1a2fb9247f76261727ed063cd9 Mon Sep 17 00:00:00 2001 From: Stephen Rosenthal Date: Thu, 18 Jun 2026 08:08:02 -0700 Subject: [PATCH 1/2] fix(extensions): add trust gate to extension fast-path The extension dispatch block in main_inner exited early -- before the central trust gate -- so DD_SITE=evil.com pup would ship DD_API_KEY/DD_APP_KEY/DD_ACCESS_TOKEN to a non-Datadog host with no prompt. Built-in commands were not affected because they always go through the central gate. Fix: call ensure_site_trusted in the extension fast-path, after apply_to resolves the effective site, and before exec_extension injects credentials into the subprocess environment. Also thread --trust-site through PreParsedGlobals so the flag works correctly on extension invocations. --- src/extensions/mod.rs | 18 ++++++++++++++++++ src/main.rs | 6 ++++++ 2 files changed, 24 insertions(+) diff --git a/src/extensions/mod.rs b/src/extensions/mod.rs index 72c94be..e9f0501 100644 --- a/src/extensions/mod.rs +++ b/src/extensions/mod.rs @@ -28,6 +28,7 @@ pub(crate) struct PreParsedGlobals { pub agent: bool, pub read_only: bool, pub org: Option, + pub trust_site: bool, } /// Parse the CLI arguments in a single left-to-right pass. @@ -39,6 +40,7 @@ pub(crate) fn parse_extension_args(args: &[String]) -> ParsedArgs { agent: false, read_only: false, org: None, + trust_site: false, }; let mut candidate: Option = None; let mut ext_args: Vec = Vec::new(); @@ -67,6 +69,7 @@ pub(crate) fn parse_extension_args(args: &[String]) -> ParsedArgs { "--yes" | "-y" => globals.yes = true, "--agent" => globals.agent = true, "--read-only" => globals.read_only = true, + "--trust-site" => globals.trust_site = true, // Equals-syntax value flags: --output=table, --org=prod s if s.starts_with("--output=") => { globals.output = Some(s["--output=".len()..].to_string()); @@ -205,6 +208,21 @@ mod tests { assert!(parsed.globals.read_only); } + #[test] + fn test_parse_trust_site_flag() { + let parsed = parse_extension_args(&args("pup --trust-site terraform plan")); + assert_eq!(parsed.candidate.as_deref(), Some("terraform")); + assert_eq!(parsed.ext_args, vec!["plan"]); + assert!(parsed.globals.trust_site); + } + + #[test] + fn test_parse_trust_site_defaults_false() { + let parsed = parse_extension_args(&args("pup terraform plan")); + assert_eq!(parsed.candidate.as_deref(), Some("terraform")); + assert!(!parsed.globals.trust_site); + } + #[test] fn test_parse_short_yes() { let parsed = parse_extension_args(&args("pup -y terraform")); diff --git a/src/main.rs b/src/main.rs index a56d064..f7944bd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10952,6 +10952,12 @@ async fn main_inner() -> anyhow::Result<()> { if let Some(ext_path) = extensions::extension_path(candidate) { let mut cfg = config::Config::from_env()?; parsed.globals.apply_to(&mut cfg)?; + #[cfg(not(feature = "browser"))] + { + let interactive = std::io::stdin().is_terminal() && !cfg.agent_mode; + let trusted_sites = config::configured_trusted_sites(); + cfg.ensure_site_trusted(parsed.globals.trust_site, interactive, &trusted_sites)?; + } let exit_code = extensions::exec_extension(&ext_path, &parsed.ext_args, &cfg)?; std::process::exit(exit_code); } From 5e381887977ff273c0dccaa2d620f3ef7398b7c3 Mon Sep 17 00:00:00 2001 From: Stephen Rosenthal Date: Thu, 18 Jun 2026 08:37:58 -0700 Subject: [PATCH 2/2] fix: cargo fmt --- src/main.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index f7944bd..1c667d6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10956,7 +10956,11 @@ async fn main_inner() -> anyhow::Result<()> { { let interactive = std::io::stdin().is_terminal() && !cfg.agent_mode; let trusted_sites = config::configured_trusted_sites(); - cfg.ensure_site_trusted(parsed.globals.trust_site, interactive, &trusted_sites)?; + cfg.ensure_site_trusted( + parsed.globals.trust_site, + interactive, + &trusted_sites, + )?; } let exit_code = extensions::exec_extension(&ext_path, &parsed.ext_args, &cfg)?; std::process::exit(exit_code);