[plugins] Enforce marketplace source admission requirements (#29753)

## Why

Managed marketplace source requirements only become effective when every
local marketplace mutation path applies the same admission decision.
This change centralizes that decision so CLI, app-server, and
external-agent migration flows cannot add, install from, or refresh a
disallowed source.

## What changed

- Match exact normalized Git repository URLs with an optional exact
`ref`.
- Match Git hosts with managed regular expressions.
- Match local marketplaces by exact absolute path.
- Preserve the expected path/name boundary for managed OpenAI
marketplaces.
- Enforce source admission during marketplace add, plugin install, and
configured Git marketplace upgrade.
- Continue upgrading independent marketplaces when one source is
rejected and return a per-marketplace error.
- Load the effective requirements stack at CLI, app-server, and
external-agent migration entry points.

This PR does not filter already configured marketplaces at runtime; that
remains in draft follow-up #29691.

## Stack

This is PR 2 of 3 and is based on #29690, which introduces the
requirements data shape and merge behavior.

## Test plan

- Source matcher coverage for Git URL/ref, host-pattern, local-path, and
managed marketplace cases.
- Marketplace add and plugin install coverage for allowed and rejected
sources.
- Marketplace upgrade coverage for rejection and per-marketplace
continuation.
This commit is contained in:
xl-openai
2026-06-23 20:13:11 -07:00
committed by GitHub
Unverified
parent 31372078d1
commit 4fe02f4fcf
18 changed files with 1621 additions and 194 deletions
+7 -4
View File
@@ -132,7 +132,7 @@ impl MarketplaceCli {
.map_err(anyhow::Error::msg)?;
match subcommand {
MarketplaceSubcommand::Add(args) => run_add(args).await?,
MarketplaceSubcommand::Add(args) => run_add(overrides, args).await?,
MarketplaceSubcommand::List(args) => run_list(overrides, args).await?,
MarketplaceSubcommand::Upgrade(args) => run_upgrade(overrides, args).await?,
MarketplaceSubcommand::Remove(args) => run_remove(args).await?,
@@ -142,7 +142,7 @@ impl MarketplaceCli {
}
}
async fn run_add(args: AddMarketplaceArgs) -> Result<()> {
async fn run_add(overrides: Vec<(String, toml::Value)>, args: AddMarketplaceArgs) -> Result<()> {
let AddMarketplaceArgs {
source,
ref_name,
@@ -150,9 +150,12 @@ async fn run_add(args: AddMarketplaceArgs) -> Result<()> {
json,
} = args;
let codex_home = find_codex_home().context("failed to resolve CODEX_HOME")?;
let config = Config::load_with_cli_overrides(overrides)
.await
.context("failed to load configuration")?;
let outcome = add_marketplace(
codex_home.to_path_buf(),
config.codex_home.to_path_buf(),
config.config_layer_stack.requirements().clone(),
MarketplaceAddRequest {
source,
ref_name,
+7 -4
View File
@@ -148,10 +148,13 @@ pub async fn run_plugin_add(
&plugin_name,
)?;
let outcome = manager
.install_plugin(PluginInstallRequest {
plugin_name,
marketplace_path: marketplace.path,
})
.install_plugin(
&plugins_input.config_layer_stack,
PluginInstallRequest {
plugin_name,
marketplace_path: marketplace.path,
},
)
.await?;
if json {