From 972d3a5495cfbd8237bb76de542b84dcc5c4397a Mon Sep 17 00:00:00 2001 From: xli-oai Date: Wed, 8 Apr 2026 21:55:13 -0700 Subject: [PATCH] Reject invalid marketplace names on add --- codex-rs/cli/src/marketplace_cmd.rs | 9 ++++- codex-rs/cli/tests/marketplace_add.rs | 53 +++++++++++++++++++++++---- codex-rs/core/src/plugins/mod.rs | 1 + 3 files changed, 55 insertions(+), 8 deletions(-) diff --git a/codex-rs/cli/src/marketplace_cmd.rs b/codex-rs/cli/src/marketplace_cmd.rs index 3be02effd3..7bae6d6fab 100644 --- a/codex-rs/cli/src/marketplace_cmd.rs +++ b/codex-rs/cli/src/marketplace_cmd.rs @@ -7,6 +7,7 @@ use codex_core::plugins::OPENAI_CURATED_MARKETPLACE_NAME; use codex_core::plugins::marketplace_install_root; use codex_core::plugins::record_installed_marketplace_root; use codex_core::plugins::validate_marketplace_root; +use codex_core::plugins::validate_plugin_segment; use codex_utils_cli::CliConfigOverrides; use std::fs; use std::path::Path; @@ -154,7 +155,7 @@ async fn run_add(args: AddMarketplaceArgs) -> Result<()> { } } - let marketplace_name = validate_marketplace_root(&staged_root) + let marketplace_name = validate_marketplace_source_root(&staged_root) .with_context(|| format!("failed to validate marketplace from {}", source.display()))?; if marketplace_name == OPENAI_CURATED_MARKETPLACE_NAME { bail!( @@ -185,6 +186,12 @@ async fn run_add(args: AddMarketplaceArgs) -> Result<()> { Ok(()) } +fn validate_marketplace_source_root(root: &Path) -> Result { + let marketplace_name = validate_marketplace_root(root)?; + validate_plugin_segment(&marketplace_name, "marketplace name").map_err(anyhow::Error::msg)?; + Ok(marketplace_name) +} + fn parse_marketplace_source( source: &str, explicit_ref: Option, diff --git a/codex-rs/cli/tests/marketplace_add.rs b/codex-rs/cli/tests/marketplace_add.rs index bd5e66c844..975825fa2c 100644 --- a/codex-rs/cli/tests/marketplace_add.rs +++ b/codex-rs/cli/tests/marketplace_add.rs @@ -13,22 +13,32 @@ fn codex_command(codex_home: &Path) -> Result { } fn write_marketplace_source(source: &Path, marker: &str) -> Result<()> { + write_marketplace_source_with_name(source, "debug", marker) +} + +fn write_marketplace_source_with_name( + source: &Path, + marketplace_name: &str, + marker: &str, +) -> Result<()> { std::fs::create_dir_all(source.join(".agents/plugins"))?; std::fs::create_dir_all(source.join("plugins/sample/.codex-plugin"))?; std::fs::write( source.join(".agents/plugins/marketplace.json"), - r#"{ - "name": "debug", + format!( + r#"{{ + "name": "{marketplace_name}", "plugins": [ - { + {{ "name": "sample", - "source": { + "source": {{ "source": "local", "path": "./plugins/sample" - } - } + }} + }} ] -}"#, +}}"# + ), )?; std::fs::write( source.join("plugins/sample/.codex-plugin/plugin.json"), @@ -65,6 +75,35 @@ async fn marketplace_add_local_directory_installs_valid_marketplace_root() -> Re Ok(()) } +#[tokio::test] +async fn marketplace_add_rejects_invalid_marketplace_name() -> Result<()> { + let codex_home = TempDir::new()?; + let source = TempDir::new()?; + write_marketplace_source_with_name(source.path(), "debug.market", "invalid marketplace")?; + + codex_command(codex_home.path())? + .args(["marketplace", "add", source.path().to_str().unwrap()]) + .assert() + .failure() + .stderr(contains( + "invalid marketplace name: only ASCII letters, digits, `_`, and `-` are allowed", + )); + + assert!( + !marketplace_install_root(codex_home.path()) + .join("debug.market") + .exists() + ); + assert!( + !codex_home + .path() + .join(".tmp/known_marketplaces.json") + .exists() + ); + + Ok(()) +} + #[tokio::test] async fn marketplace_add_same_source_is_idempotent() -> Result<()> { let codex_home = TempDir::new()?; diff --git a/codex-rs/core/src/plugins/mod.rs b/codex-rs/core/src/plugins/mod.rs index 29c6674ca2..04837b85dc 100644 --- a/codex-rs/core/src/plugins/mod.rs +++ b/codex-rs/core/src/plugins/mod.rs @@ -20,6 +20,7 @@ pub use codex_plugin::PluginCapabilitySummary; pub use codex_plugin::PluginId; pub use codex_plugin::PluginIdError; pub use codex_plugin::PluginTelemetryMetadata; +pub use codex_plugin::validate_plugin_segment; pub type LoadedPlugin = codex_plugin::LoadedPlugin; pub type PluginLoadOutcome = codex_plugin::PluginLoadOutcome;