fix(cli): require configured plugin marketplaces

This commit is contained in:
Casey Chow
2026-05-12 09:23:16 -07:00
parent fbf4349d00
commit d887f33249
2 changed files with 104 additions and 7 deletions

View File

@@ -9,7 +9,6 @@ use codex_core_plugins::PluginInstallRequest;
use codex_core_plugins::PluginsConfigInput;
use codex_core_plugins::PluginsManager;
use codex_plugin::PluginId;
use codex_utils_absolute_path::AbsolutePathBuf;
use codex_utils_cli::CliConfigOverrides;
use crate::marketplace_cmd::MarketplaceCli;
@@ -112,10 +111,8 @@ pub async fn run_plugin_list(
manager,
..
} = load_plugin_command_context(overrides).await?;
let current_dir = AbsolutePathBuf::try_from(std::env::current_dir()?)
.context("failed to resolve current directory")?;
let outcome = manager
.list_marketplaces_for_config(&plugins_input, &[current_dir])
.list_marketplaces_for_config(&plugins_input, &[])
.context("failed to list marketplace plugins")?;
let marketplaces = outcome
@@ -248,10 +245,8 @@ fn find_marketplace_for_plugin(
marketplace_name: &str,
plugin_name: &str,
) -> Result<ConfiguredMarketplace> {
let current_dir = AbsolutePathBuf::try_from(std::env::current_dir()?)
.context("failed to resolve current directory")?;
let matches = manager
.list_marketplaces_for_config(plugins_input, &[current_dir])
.list_marketplaces_for_config(plugins_input, &[])
.context("failed to list marketplace plugins")?
.marketplaces
.into_iter()

View File

@@ -2,6 +2,7 @@ use anyhow::Result;
use codex_config::CONFIG_TOML_FILE;
use codex_config::MarketplaceConfigUpdate;
use codex_config::record_user_marketplace;
use predicates::prelude::PredicateBooleanExt;
use predicates::str::contains;
use std::path::Path;
use tempfile::TempDir;
@@ -12,6 +13,12 @@ fn codex_command(codex_home: &Path) -> Result<assert_cmd::Command> {
Ok(cmd)
}
fn codex_command_in(codex_home: &Path, current_dir: &Path) -> Result<assert_cmd::Command> {
let mut cmd = codex_command(codex_home)?;
cmd.current_dir(current_dir);
Ok(cmd)
}
fn configured_local_marketplace(source: &str) -> MarketplaceConfigUpdate<'_> {
MarketplaceConfigUpdate {
last_updated: "2026-05-06T00:00:00Z",
@@ -72,6 +79,14 @@ fn setup_local_marketplace() -> Result<(TempDir, TempDir)> {
Ok((codex_home, source))
}
fn setup_unconfigured_local_marketplace() -> Result<(TempDir, TempDir)> {
let codex_home = TempDir::new()?;
let source = TempDir::new()?;
write_plugins_enabled_config(codex_home.path())?;
write_marketplace_source(source.path())?;
Ok((codex_home, source))
}
#[tokio::test]
async fn marketplace_list_shows_configured_marketplace_names() -> Result<()> {
let (codex_home, source) = setup_local_marketplace()?;
@@ -100,6 +115,20 @@ async fn plugin_list_shows_plugins_grouped_by_marketplace() -> Result<()> {
Ok(())
}
#[tokio::test]
async fn plugin_list_excludes_unconfigured_repo_local_marketplaces() -> Result<()> {
let (codex_home, source) = setup_unconfigured_local_marketplace()?;
codex_command_in(codex_home.path(), source.path())?
.args(["plugin", "list"])
.assert()
.success()
.stdout(contains("No marketplace plugins found."))
.stdout(predicates::str::is_match("sample@debug").unwrap().not());
Ok(())
}
#[tokio::test]
async fn plugin_add_and_remove_updates_installed_plugin_config() -> Result<()> {
let (codex_home, _source) = setup_local_marketplace()?;
@@ -127,6 +156,46 @@ async fn plugin_add_and_remove_updates_installed_plugin_config() -> Result<()> {
Ok(())
}
#[tokio::test]
async fn plugin_add_rejects_unconfigured_repo_local_marketplaces() -> Result<()> {
let (codex_home, source) = setup_unconfigured_local_marketplace()?;
codex_command_in(codex_home.path(), source.path())?
.args(["plugin", "add", "sample@debug"])
.assert()
.failure()
.stderr(contains(
"plugin `sample` was not found in marketplace `debug`",
));
Ok(())
}
#[tokio::test]
async fn plugin_add_reinstalls_from_configured_marketplace_snapshot() -> Result<()> {
let (codex_home, _source) = setup_local_marketplace()?;
codex_command(codex_home.path())?
.args(["plugin", "add", "sample@debug"])
.assert()
.success();
codex_command(codex_home.path())?
.args(["plugin", "add", "sample@debug"])
.assert()
.success()
.stdout(contains("Added plugin `sample` from marketplace `debug`."));
assert!(
codex_home
.path()
.join("plugins/cache/debug/sample/local/.codex-plugin/plugin.json")
.is_file()
);
Ok(())
}
#[tokio::test]
async fn plugin_remove_works_after_marketplace_is_removed() -> Result<()> {
let (codex_home, _source) = setup_local_marketplace()?;
@@ -154,3 +223,36 @@ async fn plugin_remove_works_after_marketplace_is_removed() -> Result<()> {
Ok(())
}
#[tokio::test]
async fn plugin_add_rejects_cached_plugins_without_authorizing_marketplace_snapshot() -> Result<()>
{
let (codex_home, _source) = setup_local_marketplace()?;
codex_command(codex_home.path())?
.args(["plugin", "add", "sample@debug"])
.assert()
.success();
codex_command(codex_home.path())?
.args(["plugin", "marketplace", "remove", "debug"])
.assert()
.success();
assert!(
codex_home
.path()
.join("plugins/cache/debug/sample/local/.codex-plugin/plugin.json")
.is_file()
);
codex_command(codex_home.path())?
.args(["plugin", "add", "sample@debug"])
.assert()
.failure()
.stderr(contains(
"plugin `sample` was not found in marketplace `debug`",
));
Ok(())
}