mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
[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:
@@ -877,6 +877,16 @@ impl ExternalAgentConfigService {
|
||||
"plugins migration item is missing details".to_string(),
|
||||
));
|
||||
};
|
||||
let config = ConfigBuilder::default()
|
||||
.codex_home(self.codex_home.clone())
|
||||
.fallback_cwd(Some(
|
||||
cwd.map(Path::to_path_buf)
|
||||
.unwrap_or_else(|| self.codex_home.clone()),
|
||||
))
|
||||
.build()
|
||||
.await
|
||||
.map_err(|err| io::Error::other(format!("failed to load config: {err}")))?;
|
||||
let requirements = config.config_layer_stack.requirements().clone();
|
||||
let mut outcome = PluginImportOutcome::default();
|
||||
let plugins_manager = PluginsManager::new(self.codex_home.clone());
|
||||
for plugin_group in plugins {
|
||||
@@ -916,7 +926,8 @@ impl ExternalAgentConfigService {
|
||||
ref_name: import_source.ref_name,
|
||||
sparse_paths: Vec::new(),
|
||||
};
|
||||
let add_marketplace_outcome = add_marketplace(self.codex_home.clone(), request).await;
|
||||
let add_marketplace_outcome =
|
||||
add_marketplace(self.codex_home.clone(), requirements.clone(), request).await;
|
||||
let marketplace_path = match add_marketplace_outcome {
|
||||
Ok(add_marketplace_outcome) => {
|
||||
let Some(marketplace_path) = find_marketplace_manifest_path(
|
||||
@@ -954,12 +965,37 @@ impl ExternalAgentConfigService {
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let install_config = match ConfigBuilder::default()
|
||||
.codex_home(self.codex_home.clone())
|
||||
.fallback_cwd(Some(
|
||||
cwd.map(Path::to_path_buf)
|
||||
.unwrap_or_else(|| self.codex_home.clone()),
|
||||
))
|
||||
.build()
|
||||
.await
|
||||
{
|
||||
Ok(config) => config,
|
||||
Err(err) => {
|
||||
record_plugin_import_errors(
|
||||
&mut outcome,
|
||||
cwd,
|
||||
&plugin_ids,
|
||||
"plugin_import",
|
||||
format!("failed to reload config after adding marketplace: {err}"),
|
||||
);
|
||||
outcome.failed_plugin_ids.extend(plugin_ids);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
for plugin_name in plugin_names {
|
||||
match plugins_manager
|
||||
.install_plugin(PluginInstallRequest {
|
||||
plugin_name: plugin_name.clone(),
|
||||
marketplace_path: marketplace_path.clone(),
|
||||
})
|
||||
.install_plugin(
|
||||
&install_config.config_layer_stack,
|
||||
PluginInstallRequest {
|
||||
plugin_name: plugin_name.clone(),
|
||||
marketplace_path: marketplace_path.clone(),
|
||||
},
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(_) => outcome
|
||||
|
||||
@@ -105,8 +105,10 @@ impl MarketplaceRequestProcessor {
|
||||
&self,
|
||||
params: MarketplaceAddParams,
|
||||
) -> Result<MarketplaceAddResponse, JSONRPCErrorError> {
|
||||
let config = self.load_latest_config(/*fallback_cwd*/ None).await?;
|
||||
add_marketplace_to_codex_home(
|
||||
self.config.codex_home.to_path_buf(),
|
||||
config.config_layer_stack.requirements().clone(),
|
||||
MarketplaceAddRequest {
|
||||
source: params.source,
|
||||
ref_name: params.ref_name,
|
||||
|
||||
@@ -1449,7 +1449,10 @@ impl PluginRequestProcessor {
|
||||
marketplace_path,
|
||||
};
|
||||
|
||||
let result = match plugins_manager.install_plugin(request).await {
|
||||
let result = match plugins_manager
|
||||
.install_plugin(&config.config_layer_stack, request)
|
||||
.await
|
||||
{
|
||||
Ok(result) => result,
|
||||
Err(err) => {
|
||||
warn!(
|
||||
|
||||
Reference in New Issue
Block a user