use anyhow::Result; use codex_core::plugins::marketplace_install_root; use predicates::str::contains; use std::path::Path; use tempfile::TempDir; fn codex_command(codex_home: &Path) -> Result { let mut cmd = assert_cmd::Command::new(codex_utils_cargo_bin::cargo_bin("codex")?); cmd.env("CODEX_HOME", codex_home); Ok(cmd) } fn write_marketplace_source(source: &Path, 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", "plugins": [ { "name": "sample", "source": { "source": "local", "path": "./plugins/sample" } } ] }"#, )?; std::fs::write( source.join("plugins/sample/.codex-plugin/plugin.json"), r#"{"name":"sample"}"#, )?; std::fs::write(source.join("plugins/sample/marker.txt"), marker)?; Ok(()) } #[tokio::test] async fn marketplace_add_rejects_local_directory_source() -> Result<()> { let codex_home = TempDir::new()?; let source = TempDir::new()?; write_marketplace_source(source.path(), "local ref")?; let source_parent = source.path().parent().unwrap(); let source_arg = format!("./{}", source.path().file_name().unwrap().to_string_lossy()); codex_command(codex_home.path())? .current_dir(source_parent) .args(["marketplace", "add", source_arg.as_str()]) .assert() .failure() .stderr(contains( "local marketplace sources are not supported yet; use an HTTP(S) Git URL, SSH Git URL, or GitHub owner/repo", )); assert!( !marketplace_install_root(codex_home.path()) .join("debug") .exists() ); Ok(()) }