mirror of
https://github.com/openai/codex.git
synced 2026-10-22 17:58:46 +00:00
Use request originator for remote plugin requests
This commit is contained in:
@@ -1096,33 +1096,49 @@ impl MessageProcessor {
|
||||
self.marketplace_processor.marketplace_upgrade(params).await
|
||||
}
|
||||
ClientRequest::PluginList { params, .. } => {
|
||||
self.plugin_processor.plugin_list(params).await
|
||||
self.plugin_processor
|
||||
.plugin_list(params, &request_context)
|
||||
.await
|
||||
}
|
||||
ClientRequest::PluginInstalled { params, .. } => {
|
||||
self.plugin_processor.plugin_installed(params).await
|
||||
self.plugin_processor
|
||||
.plugin_installed(params, &request_context)
|
||||
.await
|
||||
}
|
||||
ClientRequest::PluginRead { params, .. } => {
|
||||
self.plugin_processor.plugin_read(params).await
|
||||
self.plugin_processor
|
||||
.plugin_read(params, &request_context)
|
||||
.await
|
||||
}
|
||||
ClientRequest::PluginSkillRead { params, .. } => {
|
||||
self.plugin_processor.plugin_skill_read(params).await
|
||||
self.plugin_processor
|
||||
.plugin_skill_read(params, &request_context)
|
||||
.await
|
||||
}
|
||||
ClientRequest::PluginShareSave { params, .. } => {
|
||||
self.plugin_processor.plugin_share_save(params).await
|
||||
self.plugin_processor
|
||||
.plugin_share_save(params, &request_context)
|
||||
.await
|
||||
}
|
||||
ClientRequest::PluginShareUpdateTargets { params, .. } => {
|
||||
self.plugin_processor
|
||||
.plugin_share_update_targets(params)
|
||||
.plugin_share_update_targets(params, &request_context)
|
||||
.await
|
||||
}
|
||||
ClientRequest::PluginShareList { params, .. } => {
|
||||
self.plugin_processor.plugin_share_list(params).await
|
||||
self.plugin_processor
|
||||
.plugin_share_list(params, &request_context)
|
||||
.await
|
||||
}
|
||||
ClientRequest::PluginShareCheckout { params, .. } => {
|
||||
self.plugin_processor.plugin_share_checkout(params).await
|
||||
self.plugin_processor
|
||||
.plugin_share_checkout(params, &request_context)
|
||||
.await
|
||||
}
|
||||
ClientRequest::PluginShareDelete { params, .. } => {
|
||||
self.plugin_processor.plugin_share_delete(params).await
|
||||
self.plugin_processor
|
||||
.plugin_share_delete(params, &request_context)
|
||||
.await
|
||||
}
|
||||
ClientRequest::AppsList { params, .. } => {
|
||||
self.apps_processor
|
||||
@@ -1134,12 +1150,12 @@ impl MessageProcessor {
|
||||
}
|
||||
ClientRequest::PluginInstall { params, .. } => {
|
||||
self.plugin_processor
|
||||
.plugin_install(params, request_context.originator())
|
||||
.plugin_install(params, &request_context)
|
||||
.await
|
||||
}
|
||||
ClientRequest::PluginUninstall { params, .. } => {
|
||||
self.plugin_processor
|
||||
.plugin_uninstall(params, request_context.originator())
|
||||
.plugin_uninstall(params, &request_context)
|
||||
.await
|
||||
}
|
||||
ClientRequest::ModelList { params, .. } => {
|
||||
|
||||
@@ -9,7 +9,6 @@ use codex_config::types::McpServerConfig;
|
||||
use codex_core_plugins::remote::RemotePluginScope;
|
||||
use codex_core_plugins::remote::is_valid_remote_plugin_id;
|
||||
use codex_core_plugins::remote::validate_remote_plugin_id;
|
||||
use codex_login::default_client::Originator;
|
||||
use codex_mcp::McpOAuthLoginSupport;
|
||||
use codex_mcp::oauth_login_support;
|
||||
use codex_mcp::should_retry_without_scopes;
|
||||
@@ -297,8 +296,9 @@ impl PluginRequestProcessor {
|
||||
pub(crate) async fn plugin_list(
|
||||
&self,
|
||||
params: PluginListParams,
|
||||
request_context: &RequestContext,
|
||||
) -> Result<Option<ClientResponsePayload>, JSONRPCErrorError> {
|
||||
self.plugin_list_response(params)
|
||||
self.plugin_list_response(params, request_context.originator())
|
||||
.await
|
||||
.map(|response| Some(response.into()))
|
||||
}
|
||||
@@ -306,8 +306,9 @@ impl PluginRequestProcessor {
|
||||
pub(crate) async fn plugin_installed(
|
||||
&self,
|
||||
params: PluginInstalledParams,
|
||||
request_context: &RequestContext,
|
||||
) -> Result<Option<ClientResponsePayload>, JSONRPCErrorError> {
|
||||
self.plugin_installed_response(params)
|
||||
self.plugin_installed_response(params, request_context.originator())
|
||||
.await
|
||||
.map(|response| Some(response.into()))
|
||||
}
|
||||
@@ -315,8 +316,9 @@ impl PluginRequestProcessor {
|
||||
pub(crate) async fn plugin_read(
|
||||
&self,
|
||||
params: PluginReadParams,
|
||||
request_context: &RequestContext,
|
||||
) -> Result<Option<ClientResponsePayload>, JSONRPCErrorError> {
|
||||
self.plugin_read_response(params)
|
||||
self.plugin_read_response(params, request_context.originator())
|
||||
.await
|
||||
.map(|response| Some(response.into()))
|
||||
}
|
||||
@@ -324,8 +326,9 @@ impl PluginRequestProcessor {
|
||||
pub(crate) async fn plugin_skill_read(
|
||||
&self,
|
||||
params: PluginSkillReadParams,
|
||||
request_context: &RequestContext,
|
||||
) -> Result<Option<ClientResponsePayload>, JSONRPCErrorError> {
|
||||
self.plugin_skill_read_response(params)
|
||||
self.plugin_skill_read_response(params, request_context.originator())
|
||||
.await
|
||||
.map(|response| Some(response.into()))
|
||||
}
|
||||
@@ -333,8 +336,9 @@ impl PluginRequestProcessor {
|
||||
pub(crate) async fn plugin_share_save(
|
||||
&self,
|
||||
params: PluginShareSaveParams,
|
||||
request_context: &RequestContext,
|
||||
) -> Result<Option<ClientResponsePayload>, JSONRPCErrorError> {
|
||||
self.plugin_share_save_response(params)
|
||||
self.plugin_share_save_response(params, request_context.originator())
|
||||
.await
|
||||
.map(|response| Some(response.into()))
|
||||
}
|
||||
@@ -342,8 +346,9 @@ impl PluginRequestProcessor {
|
||||
pub(crate) async fn plugin_share_update_targets(
|
||||
&self,
|
||||
params: PluginShareUpdateTargetsParams,
|
||||
request_context: &RequestContext,
|
||||
) -> Result<Option<ClientResponsePayload>, JSONRPCErrorError> {
|
||||
self.plugin_share_update_targets_response(params)
|
||||
self.plugin_share_update_targets_response(params, request_context.originator())
|
||||
.await
|
||||
.map(|response| Some(response.into()))
|
||||
}
|
||||
@@ -351,8 +356,9 @@ impl PluginRequestProcessor {
|
||||
pub(crate) async fn plugin_share_list(
|
||||
&self,
|
||||
params: PluginShareListParams,
|
||||
request_context: &RequestContext,
|
||||
) -> Result<Option<ClientResponsePayload>, JSONRPCErrorError> {
|
||||
self.plugin_share_list_response(params)
|
||||
self.plugin_share_list_response(params, request_context.originator())
|
||||
.await
|
||||
.map(|response| Some(response.into()))
|
||||
}
|
||||
@@ -360,8 +366,9 @@ impl PluginRequestProcessor {
|
||||
pub(crate) async fn plugin_share_checkout(
|
||||
&self,
|
||||
params: PluginShareCheckoutParams,
|
||||
request_context: &RequestContext,
|
||||
) -> Result<Option<ClientResponsePayload>, JSONRPCErrorError> {
|
||||
self.plugin_share_checkout_response(params)
|
||||
self.plugin_share_checkout_response(params, request_context.originator())
|
||||
.await
|
||||
.map(|response| Some(response.into()))
|
||||
}
|
||||
@@ -369,8 +376,9 @@ impl PluginRequestProcessor {
|
||||
pub(crate) async fn plugin_share_delete(
|
||||
&self,
|
||||
params: PluginShareDeleteParams,
|
||||
request_context: &RequestContext,
|
||||
) -> Result<Option<ClientResponsePayload>, JSONRPCErrorError> {
|
||||
self.plugin_share_delete_response(params)
|
||||
self.plugin_share_delete_response(params, request_context.originator())
|
||||
.await
|
||||
.map(|response| Some(response.into()))
|
||||
}
|
||||
@@ -378,9 +386,9 @@ impl PluginRequestProcessor {
|
||||
pub(crate) async fn plugin_install(
|
||||
&self,
|
||||
params: PluginInstallParams,
|
||||
originator: &Originator,
|
||||
request_context: &RequestContext,
|
||||
) -> Result<Option<ClientResponsePayload>, JSONRPCErrorError> {
|
||||
self.plugin_install_response(params, originator)
|
||||
self.plugin_install_response(params, request_context.originator())
|
||||
.await
|
||||
.map(|response| Some(response.into()))
|
||||
}
|
||||
@@ -388,9 +396,9 @@ impl PluginRequestProcessor {
|
||||
pub(crate) async fn plugin_uninstall(
|
||||
&self,
|
||||
params: PluginUninstallParams,
|
||||
originator: &Originator,
|
||||
request_context: &RequestContext,
|
||||
) -> Result<Option<ClientResponsePayload>, JSONRPCErrorError> {
|
||||
self.plugin_uninstall_response(params, originator)
|
||||
self.plugin_uninstall_response(params, request_context.originator())
|
||||
.await
|
||||
.map(|response| Some(response.into()))
|
||||
}
|
||||
@@ -467,6 +475,7 @@ impl PluginRequestProcessor {
|
||||
async fn plugin_list_response(
|
||||
&self,
|
||||
params: PluginListParams,
|
||||
originator: &Originator,
|
||||
) -> Result<PluginListResponse, JSONRPCErrorError> {
|
||||
let plugins_manager = self.thread_manager.plugins_manager();
|
||||
let PluginListParams {
|
||||
@@ -586,6 +595,7 @@ impl PluginRequestProcessor {
|
||||
match codex_core_plugins::remote::fetch_remote_marketplaces(
|
||||
&remote_plugin_service_config,
|
||||
auth.as_ref(),
|
||||
originator,
|
||||
&remote_sources,
|
||||
)
|
||||
.await
|
||||
@@ -664,6 +674,7 @@ impl PluginRequestProcessor {
|
||||
async fn plugin_installed_response(
|
||||
&self,
|
||||
params: PluginInstalledParams,
|
||||
originator: &Originator,
|
||||
) -> Result<PluginInstalledResponse, JSONRPCErrorError> {
|
||||
let plugins_manager = self.thread_manager.plugins_manager();
|
||||
let PluginInstalledParams {
|
||||
@@ -717,6 +728,7 @@ impl PluginRequestProcessor {
|
||||
&plugins_input,
|
||||
&remote_installed_plugin_visible_scopes,
|
||||
auth.as_ref(),
|
||||
originator,
|
||||
)
|
||||
.await,
|
||||
);
|
||||
@@ -813,6 +825,7 @@ impl PluginRequestProcessor {
|
||||
plugins_input: &codex_core_plugins::PluginsConfigInput,
|
||||
visible_scopes: &[RemotePluginScope],
|
||||
auth: Option<&CodexAuth>,
|
||||
originator: &Originator,
|
||||
) -> Vec<PluginMarketplaceEntry> {
|
||||
let remote_marketplaces = if let Some(remote_marketplaces) =
|
||||
plugins_manager.build_remote_installed_plugin_marketplaces_from_cache(visible_scopes)
|
||||
@@ -823,6 +836,7 @@ impl PluginRequestProcessor {
|
||||
.build_and_cache_remote_installed_plugin_marketplaces(
|
||||
plugins_input,
|
||||
auth,
|
||||
originator,
|
||||
visible_scopes,
|
||||
Some(self.effective_plugins_changed_callback()),
|
||||
)
|
||||
@@ -851,6 +865,7 @@ impl PluginRequestProcessor {
|
||||
async fn plugin_read_response(
|
||||
&self,
|
||||
params: PluginReadParams,
|
||||
originator: &Originator,
|
||||
) -> Result<PluginReadResponse, JSONRPCErrorError> {
|
||||
let plugins_manager = self.thread_manager.plugins_manager();
|
||||
let PluginReadParams {
|
||||
@@ -899,6 +914,7 @@ impl PluginRequestProcessor {
|
||||
match codex_core_plugins::remote::fetch_remote_plugin_share_context(
|
||||
&remote_plugin_service_config,
|
||||
auth.as_ref(),
|
||||
originator,
|
||||
&context.remote_plugin_id,
|
||||
)
|
||||
.await
|
||||
@@ -939,9 +955,13 @@ impl PluginRequestProcessor {
|
||||
None => None,
|
||||
};
|
||||
let environment_manager = self.thread_manager.environment_manager();
|
||||
let app_summaries =
|
||||
load_plugin_app_summaries(&config, &outcome.plugin.apps, &environment_manager)
|
||||
.await;
|
||||
let app_summaries = load_plugin_app_summaries(
|
||||
&config,
|
||||
&outcome.plugin.apps,
|
||||
&environment_manager,
|
||||
originator,
|
||||
)
|
||||
.await;
|
||||
let visible_skills = outcome
|
||||
.plugin
|
||||
.skills
|
||||
@@ -1003,6 +1023,7 @@ impl PluginRequestProcessor {
|
||||
let remote_detail = codex_core_plugins::remote::fetch_remote_plugin_detail(
|
||||
&remote_plugin_service_config,
|
||||
auth.as_ref(),
|
||||
originator,
|
||||
&remote_marketplace_name,
|
||||
&plugin_name,
|
||||
)
|
||||
@@ -1017,8 +1038,13 @@ impl PluginRequestProcessor {
|
||||
.map(codex_plugin::AppConnectorId)
|
||||
.collect::<Vec<_>>();
|
||||
let environment_manager = self.thread_manager.environment_manager();
|
||||
let app_summaries =
|
||||
load_plugin_app_summaries(&config, &plugin_apps, &environment_manager).await;
|
||||
let app_summaries = load_plugin_app_summaries(
|
||||
&config,
|
||||
&plugin_apps,
|
||||
&environment_manager,
|
||||
originator,
|
||||
)
|
||||
.await;
|
||||
remote_plugin_detail_to_info(remote_detail, app_summaries)
|
||||
}
|
||||
};
|
||||
@@ -1029,6 +1055,7 @@ impl PluginRequestProcessor {
|
||||
async fn plugin_skill_read_response(
|
||||
&self,
|
||||
params: PluginSkillReadParams,
|
||||
originator: &Originator,
|
||||
) -> Result<PluginSkillReadResponse, JSONRPCErrorError> {
|
||||
let PluginSkillReadParams {
|
||||
remote_marketplace_name,
|
||||
@@ -1056,6 +1083,7 @@ impl PluginRequestProcessor {
|
||||
let remote_skill_detail = codex_core_plugins::remote::fetch_remote_plugin_skill_detail(
|
||||
&remote_plugin_service_config,
|
||||
auth.as_ref(),
|
||||
originator,
|
||||
&remote_marketplace_name,
|
||||
&remote_plugin_id,
|
||||
&skill_name,
|
||||
@@ -1073,6 +1101,7 @@ impl PluginRequestProcessor {
|
||||
async fn plugin_share_save_response(
|
||||
&self,
|
||||
params: PluginShareSaveParams,
|
||||
originator: &Originator,
|
||||
) -> Result<PluginShareSaveResponse, JSONRPCErrorError> {
|
||||
let (config, auth) = self.load_plugin_share_config_and_auth().await?;
|
||||
if !config.features.enabled(Feature::PluginSharing) {
|
||||
@@ -1113,6 +1142,7 @@ impl PluginRequestProcessor {
|
||||
let result = codex_core_plugins::remote::save_remote_plugin_share(
|
||||
&remote_plugin_service_config,
|
||||
auth.as_ref(),
|
||||
originator,
|
||||
config.codex_home.as_path(),
|
||||
&plugin_path,
|
||||
remote_plugin_id.as_deref(),
|
||||
@@ -1131,6 +1161,7 @@ impl PluginRequestProcessor {
|
||||
async fn plugin_share_update_targets_response(
|
||||
&self,
|
||||
params: PluginShareUpdateTargetsParams,
|
||||
originator: &Originator,
|
||||
) -> Result<PluginShareUpdateTargetsResponse, JSONRPCErrorError> {
|
||||
let (config, auth) = self.load_plugin_share_config_and_auth().await?;
|
||||
if !config.features.enabled(Feature::PluginSharing) {
|
||||
@@ -1152,6 +1183,7 @@ impl PluginRequestProcessor {
|
||||
let result = codex_core_plugins::remote::update_remote_plugin_share_targets(
|
||||
&remote_plugin_service_config,
|
||||
auth.as_ref(),
|
||||
originator,
|
||||
&remote_plugin_id,
|
||||
remote_plugin_share_targets(share_targets),
|
||||
remote_plugin_share_update_discoverability(discoverability),
|
||||
@@ -1174,6 +1206,7 @@ impl PluginRequestProcessor {
|
||||
async fn plugin_share_list_response(
|
||||
&self,
|
||||
_params: PluginShareListParams,
|
||||
originator: &Originator,
|
||||
) -> Result<PluginShareListResponse, JSONRPCErrorError> {
|
||||
let (config, auth) = self.load_plugin_share_config_and_auth().await?;
|
||||
let remote_plugin_service_config = RemotePluginServiceConfig {
|
||||
@@ -1182,6 +1215,7 @@ impl PluginRequestProcessor {
|
||||
let data = codex_core_plugins::remote::list_remote_plugin_shares(
|
||||
&remote_plugin_service_config,
|
||||
auth.as_ref(),
|
||||
originator,
|
||||
config.codex_home.as_path(),
|
||||
)
|
||||
.await
|
||||
@@ -1205,6 +1239,7 @@ impl PluginRequestProcessor {
|
||||
async fn plugin_share_checkout_response(
|
||||
&self,
|
||||
params: PluginShareCheckoutParams,
|
||||
originator: &Originator,
|
||||
) -> Result<PluginShareCheckoutResponse, JSONRPCErrorError> {
|
||||
let (config, auth) = self.load_plugin_share_config_and_auth().await?;
|
||||
if !config.features.enabled(Feature::PluginSharing) {
|
||||
@@ -1221,6 +1256,7 @@ impl PluginRequestProcessor {
|
||||
let result = codex_core_plugins::remote::checkout_remote_plugin_share(
|
||||
&remote_plugin_service_config,
|
||||
auth.as_ref(),
|
||||
originator,
|
||||
config.codex_home.as_path(),
|
||||
&remote_plugin_id,
|
||||
)
|
||||
@@ -1241,6 +1277,7 @@ impl PluginRequestProcessor {
|
||||
async fn plugin_share_delete_response(
|
||||
&self,
|
||||
params: PluginShareDeleteParams,
|
||||
originator: &Originator,
|
||||
) -> Result<PluginShareDeleteResponse, JSONRPCErrorError> {
|
||||
let (config, auth) = self.load_plugin_share_config_and_auth().await?;
|
||||
let PluginShareDeleteParams { remote_plugin_id } = params;
|
||||
@@ -1254,6 +1291,7 @@ impl PluginRequestProcessor {
|
||||
codex_core_plugins::remote::delete_remote_plugin_share(
|
||||
&remote_plugin_service_config,
|
||||
auth.as_ref(),
|
||||
originator,
|
||||
config.codex_home.as_path(),
|
||||
&remote_plugin_id,
|
||||
)
|
||||
@@ -1350,6 +1388,7 @@ impl PluginRequestProcessor {
|
||||
auth.as_ref().is_some_and(CodexAuth::is_chatgpt_auth),
|
||||
&result.plugin_id.as_key(),
|
||||
&plugin_apps,
|
||||
originator,
|
||||
)
|
||||
.await;
|
||||
|
||||
@@ -1381,6 +1420,7 @@ impl PluginRequestProcessor {
|
||||
codex_core_plugins::remote::fetch_remote_plugin_detail_with_download_urls(
|
||||
&remote_plugin_service_config,
|
||||
auth.as_ref(),
|
||||
originator,
|
||||
&remote_marketplace_name,
|
||||
&remote_plugin_id,
|
||||
)
|
||||
@@ -1432,6 +1472,7 @@ impl PluginRequestProcessor {
|
||||
codex_core_plugins::remote::install_remote_plugin(
|
||||
&remote_plugin_service_config,
|
||||
auth.as_ref(),
|
||||
originator,
|
||||
&actual_remote_marketplace_name,
|
||||
&remote_plugin_id,
|
||||
)
|
||||
@@ -1465,6 +1506,7 @@ impl PluginRequestProcessor {
|
||||
auth.as_ref().is_some_and(CodexAuth::is_chatgpt_auth),
|
||||
&result.plugin_id.as_key(),
|
||||
&plugin_apps,
|
||||
originator,
|
||||
)
|
||||
.await;
|
||||
|
||||
@@ -1480,25 +1522,23 @@ impl PluginRequestProcessor {
|
||||
is_chatgpt_auth: bool,
|
||||
plugin_id: &str,
|
||||
plugin_apps: &[codex_plugin::AppConnectorId],
|
||||
originator: &Originator,
|
||||
) -> Vec<AppSummary> {
|
||||
if plugin_apps.is_empty() || !config.features.apps_enabled_for_auth(is_chatgpt_auth) {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
let environment_manager = self.thread_manager.environment_manager();
|
||||
let originator = Originator::process_default();
|
||||
let originator_value = originator.value().to_string();
|
||||
let (all_connectors_result, accessible_connectors_result) = tokio::join!(
|
||||
connectors::list_all_connectors_with_options_and_originator(
|
||||
config,
|
||||
/*force_refetch*/ true,
|
||||
&originator,
|
||||
config, /*force_refetch*/ true, originator,
|
||||
),
|
||||
connectors::list_accessible_connectors_from_mcp_tools_with_environment_manager(
|
||||
config,
|
||||
/*force_refetch*/ true,
|
||||
&environment_manager,
|
||||
&originator_value,
|
||||
&originator_value
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1509,7 +1549,7 @@ impl PluginRequestProcessor {
|
||||
plugin = plugin_id,
|
||||
"failed to load app metadata after plugin install: {err:#}"
|
||||
);
|
||||
connectors::list_cached_all_connectors_with_originator(config, &originator)
|
||||
connectors::list_cached_all_connectors_with_originator(config, originator)
|
||||
.await
|
||||
.unwrap_or_default()
|
||||
}
|
||||
@@ -1645,7 +1685,9 @@ impl PluginRequestProcessor {
|
||||
return Err(invalid_request("invalid remote plugin id"));
|
||||
}
|
||||
if is_valid_remote_plugin_id(&plugin_id) {
|
||||
return self.remote_plugin_uninstall_response(plugin_id).await;
|
||||
return self
|
||||
.remote_plugin_uninstall_response(plugin_id, originator)
|
||||
.await;
|
||||
}
|
||||
let plugins_manager = self.thread_manager.plugins_manager();
|
||||
|
||||
@@ -1728,6 +1770,7 @@ impl PluginRequestProcessor {
|
||||
async fn remote_plugin_uninstall_response(
|
||||
&self,
|
||||
plugin_id: String,
|
||||
originator: &Originator,
|
||||
) -> Result<PluginUninstallResponse, JSONRPCErrorError> {
|
||||
let config = self.load_latest_config(/*fallback_cwd*/ None).await?;
|
||||
if !config.features.enabled(Feature::Plugins) {
|
||||
@@ -1742,6 +1785,7 @@ impl PluginRequestProcessor {
|
||||
let uninstall_result = codex_core_plugins::remote::uninstall_remote_plugin(
|
||||
&remote_plugin_service_config,
|
||||
auth.as_ref(),
|
||||
originator,
|
||||
config.codex_home.to_path_buf(),
|
||||
&plugin_id,
|
||||
)
|
||||
@@ -1773,24 +1817,22 @@ async fn load_plugin_app_summaries(
|
||||
config: &Config,
|
||||
plugin_apps: &[codex_plugin::AppConnectorId],
|
||||
environment_manager: &EnvironmentManager,
|
||||
originator: &Originator,
|
||||
) -> Vec<AppSummary> {
|
||||
if plugin_apps.is_empty() {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
let originator = Originator::process_default();
|
||||
let originator_value = originator.value().to_string();
|
||||
let connectors = match connectors::list_all_connectors_with_options_and_originator(
|
||||
config,
|
||||
/*force_refetch*/ false,
|
||||
&originator,
|
||||
config, /*force_refetch*/ false, originator,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(connectors) => connectors,
|
||||
Err(err) => {
|
||||
warn!("failed to load app metadata for plugin/read: {err:#}");
|
||||
connectors::list_cached_all_connectors_with_originator(config, &originator)
|
||||
connectors::list_cached_all_connectors_with_originator(config, originator)
|
||||
.await
|
||||
.unwrap_or_default()
|
||||
}
|
||||
@@ -1801,7 +1843,6 @@ async fn load_plugin_app_summaries(
|
||||
plugin_apps,
|
||||
&originator_value,
|
||||
);
|
||||
|
||||
let accessible_connectors =
|
||||
match connectors::list_accessible_connectors_from_mcp_tools_with_environment_manager(
|
||||
config,
|
||||
|
||||
@@ -615,12 +615,14 @@ impl PluginsManager {
|
||||
&self,
|
||||
config: &PluginsConfigInput,
|
||||
auth: Option<&CodexAuth>,
|
||||
originator: &Originator,
|
||||
visible_scopes: &[RemotePluginScope],
|
||||
on_effective_plugins_changed: Option<Arc<dyn Fn() + Send + Sync + 'static>>,
|
||||
) -> Result<Vec<crate::remote::RemoteMarketplace>, RemotePluginCatalogError> {
|
||||
let plugins = crate::remote::fetch_remote_installed_plugins(
|
||||
&remote_plugin_service_config(config),
|
||||
auth,
|
||||
originator,
|
||||
)
|
||||
.await?;
|
||||
let marketplaces =
|
||||
@@ -1814,9 +1816,11 @@ impl PluginsManager {
|
||||
}
|
||||
};
|
||||
|
||||
let originator = Originator::process_default();
|
||||
let installed_plugins = crate::remote::fetch_remote_installed_plugins(
|
||||
&request.service_config,
|
||||
request.auth.as_ref(),
|
||||
&originator,
|
||||
)
|
||||
.await;
|
||||
match installed_plugins {
|
||||
|
||||
@@ -24,11 +24,6 @@ use url::Url;
|
||||
mod remote_installed_plugin_sync;
|
||||
mod share;
|
||||
|
||||
fn build_process_reqwest_client() -> reqwest::Client {
|
||||
let originator = Originator::process_default();
|
||||
build_reqwest_client(&originator)
|
||||
}
|
||||
|
||||
pub use remote_installed_plugin_sync::RemoteInstalledPluginBundleSyncError;
|
||||
pub use remote_installed_plugin_sync::RemoteInstalledPluginBundleSyncOutcome;
|
||||
pub use remote_installed_plugin_sync::RemotePluginCacheMutationGuard;
|
||||
@@ -489,6 +484,7 @@ struct RemotePluginMutationResponse {
|
||||
pub async fn fetch_remote_marketplaces(
|
||||
config: &RemotePluginServiceConfig,
|
||||
auth: Option<&CodexAuth>,
|
||||
originator: &Originator,
|
||||
sources: &[RemoteMarketplaceSource],
|
||||
) -> Result<Vec<RemoteMarketplace>, RemotePluginCatalogError> {
|
||||
let auth = ensure_chatgpt_auth(auth)?;
|
||||
@@ -500,7 +496,15 @@ pub async fn fetch_remote_marketplaces(
|
||||
)
|
||||
});
|
||||
let workspace_installed_plugins = if needs_workspace_installed {
|
||||
Some(fetch_installed_plugins_for_scope(config, auth, RemotePluginScope::Workspace).await?)
|
||||
Some(
|
||||
fetch_installed_plugins_for_scope(
|
||||
config,
|
||||
auth,
|
||||
originator,
|
||||
RemotePluginScope::Workspace,
|
||||
)
|
||||
.await?,
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@@ -510,8 +514,8 @@ pub async fn fetch_remote_marketplaces(
|
||||
RemoteMarketplaceSource::Global => {
|
||||
let scope = RemotePluginScope::Global;
|
||||
let (directory_plugins, installed_plugins) = tokio::try_join!(
|
||||
fetch_directory_plugins_for_scope(config, auth, scope),
|
||||
fetch_installed_plugins_for_scope(config, auth, scope),
|
||||
fetch_directory_plugins_for_scope(config, auth, originator, scope),
|
||||
fetch_installed_plugins_for_scope(config, auth, originator, scope),
|
||||
)?;
|
||||
if let Some(marketplace) = build_remote_marketplace(
|
||||
scope.marketplace_name(),
|
||||
@@ -526,7 +530,7 @@ pub async fn fetch_remote_marketplaces(
|
||||
RemoteMarketplaceSource::WorkspaceDirectory => {
|
||||
let scope = RemotePluginScope::Workspace;
|
||||
let directory_plugins =
|
||||
fetch_directory_plugins_for_scope(config, auth, scope).await?;
|
||||
fetch_directory_plugins_for_scope(config, auth, originator, scope).await?;
|
||||
if let Some(marketplace) = build_remote_marketplace(
|
||||
scope.marketplace_name(),
|
||||
scope.marketplace_display_name(),
|
||||
@@ -541,7 +545,8 @@ pub async fn fetch_remote_marketplaces(
|
||||
// The shared endpoint is the source of truth for plugins explicitly shared
|
||||
// with the user. Installed unlisted plugins that are not returned there are
|
||||
// link-installed and stay in the separate unlisted bucket.
|
||||
let shared_plugins = fetch_shared_workspace_plugins(config, auth).await?;
|
||||
let shared_plugins =
|
||||
fetch_shared_workspace_plugins(config, auth, originator).await?;
|
||||
let shared_plugin_ids = shared_plugins
|
||||
.iter()
|
||||
.map(|plugin| plugin.id.clone())
|
||||
@@ -652,16 +657,19 @@ fn build_remote_marketplace(
|
||||
pub(crate) async fn fetch_remote_installed_plugins(
|
||||
config: &RemotePluginServiceConfig,
|
||||
auth: Option<&CodexAuth>,
|
||||
originator: &Originator,
|
||||
) -> Result<Vec<RemoteInstalledPlugin>, RemotePluginCatalogError> {
|
||||
let auth = ensure_chatgpt_auth(auth)?;
|
||||
let global = async {
|
||||
let scope = RemotePluginScope::Global;
|
||||
let installed_plugins = fetch_installed_plugins_for_scope(config, auth, scope).await?;
|
||||
let installed_plugins =
|
||||
fetch_installed_plugins_for_scope(config, auth, originator, scope).await?;
|
||||
Ok::<_, RemotePluginCatalogError>((scope, installed_plugins))
|
||||
};
|
||||
let workspace = async {
|
||||
let scope = RemotePluginScope::Workspace;
|
||||
let installed_plugins = fetch_installed_plugins_for_scope(config, auth, scope).await?;
|
||||
let installed_plugins =
|
||||
fetch_installed_plugins_for_scope(config, auth, originator, scope).await?;
|
||||
Ok::<_, RemotePluginCatalogError>((scope, installed_plugins))
|
||||
};
|
||||
|
||||
@@ -731,12 +739,14 @@ pub fn group_remote_installed_plugins_by_marketplaces(
|
||||
pub async fn fetch_remote_plugin_detail(
|
||||
config: &RemotePluginServiceConfig,
|
||||
auth: Option<&CodexAuth>,
|
||||
originator: &Originator,
|
||||
marketplace_name: &str,
|
||||
plugin_id: &str,
|
||||
) -> Result<RemotePluginDetail, RemotePluginCatalogError> {
|
||||
fetch_remote_plugin_detail_with_download_url_option(
|
||||
config,
|
||||
auth,
|
||||
originator,
|
||||
marketplace_name,
|
||||
plugin_id,
|
||||
/*include_download_urls*/ false,
|
||||
@@ -747,11 +757,12 @@ pub async fn fetch_remote_plugin_detail(
|
||||
pub async fn fetch_remote_plugin_share_context(
|
||||
config: &RemotePluginServiceConfig,
|
||||
auth: Option<&CodexAuth>,
|
||||
originator: &Originator,
|
||||
plugin_id: &str,
|
||||
) -> Result<Option<RemotePluginShareContext>, RemotePluginCatalogError> {
|
||||
let auth = ensure_chatgpt_auth(auth)?;
|
||||
let plugin = fetch_plugin_detail(
|
||||
config, auth, plugin_id, /*include_download_urls*/ false,
|
||||
config, auth, originator, plugin_id, /*include_download_urls*/ false,
|
||||
)
|
||||
.await?;
|
||||
remote_plugin_share_context(&plugin)
|
||||
@@ -760,12 +771,14 @@ pub async fn fetch_remote_plugin_share_context(
|
||||
pub async fn fetch_remote_plugin_detail_with_download_urls(
|
||||
config: &RemotePluginServiceConfig,
|
||||
auth: Option<&CodexAuth>,
|
||||
originator: &Originator,
|
||||
marketplace_name: &str,
|
||||
plugin_id: &str,
|
||||
) -> Result<RemotePluginDetail, RemotePluginCatalogError> {
|
||||
fetch_remote_plugin_detail_with_download_url_option(
|
||||
config,
|
||||
auth,
|
||||
originator,
|
||||
marketplace_name,
|
||||
plugin_id,
|
||||
/*include_download_urls*/ true,
|
||||
@@ -776,6 +789,7 @@ pub async fn fetch_remote_plugin_detail_with_download_urls(
|
||||
pub async fn fetch_remote_plugin_skill_detail(
|
||||
config: &RemotePluginServiceConfig,
|
||||
auth: Option<&CodexAuth>,
|
||||
originator: &Originator,
|
||||
marketplace_name: &str,
|
||||
plugin_id: &str,
|
||||
skill_name: &str,
|
||||
@@ -788,7 +802,7 @@ pub async fn fetch_remote_plugin_skill_detail(
|
||||
}
|
||||
|
||||
let url = remote_plugin_skill_detail_url(config, plugin_id, skill_name)?;
|
||||
let client = build_process_reqwest_client();
|
||||
let client = build_reqwest_client(originator);
|
||||
let request = authenticated_request(client.get(&url), auth)?;
|
||||
let response: RemotePluginSkillDetailResponse = send_and_decode(request, &url).await?;
|
||||
if response.plugin_id != plugin_id {
|
||||
@@ -812,30 +826,42 @@ pub async fn fetch_remote_plugin_skill_detail(
|
||||
async fn fetch_remote_plugin_detail_with_download_url_option(
|
||||
config: &RemotePluginServiceConfig,
|
||||
auth: Option<&CodexAuth>,
|
||||
originator: &Originator,
|
||||
_marketplace_name: &str,
|
||||
plugin_id: &str,
|
||||
include_download_urls: bool,
|
||||
) -> Result<RemotePluginDetail, RemotePluginCatalogError> {
|
||||
let auth = ensure_chatgpt_auth(auth)?;
|
||||
let plugin = fetch_plugin_detail(config, auth, plugin_id, include_download_urls).await?;
|
||||
let plugin =
|
||||
fetch_plugin_detail(config, auth, originator, plugin_id, include_download_urls).await?;
|
||||
let scope = plugin.scope;
|
||||
let marketplace_name = remote_plugin_canonical_marketplace_name(&plugin)?.to_string();
|
||||
// Remote plugin IDs uniquely identify remote plugins, so the caller-provided
|
||||
// marketplace name is not validated here. The backend detail response is the
|
||||
// source of truth for the plugin's actual scope/marketplace.
|
||||
|
||||
build_remote_plugin_detail(config, auth, scope, marketplace_name, plugin_id, plugin).await
|
||||
build_remote_plugin_detail(
|
||||
config,
|
||||
auth,
|
||||
originator,
|
||||
scope,
|
||||
marketplace_name,
|
||||
plugin_id,
|
||||
plugin,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn build_remote_plugin_detail(
|
||||
config: &RemotePluginServiceConfig,
|
||||
auth: &CodexAuth,
|
||||
originator: &Originator,
|
||||
scope: RemotePluginScope,
|
||||
marketplace_name: String,
|
||||
plugin_id: &str,
|
||||
plugin: RemotePluginDirectoryItem,
|
||||
) -> Result<RemotePluginDetail, RemotePluginCatalogError> {
|
||||
let installed_plugin = fetch_installed_plugins_for_scope(config, auth, scope)
|
||||
let installed_plugin = fetch_installed_plugins_for_scope(config, auth, originator, scope)
|
||||
.await?
|
||||
.into_iter()
|
||||
.find(|installed_plugin| installed_plugin.plugin.id == plugin_id);
|
||||
@@ -880,6 +906,7 @@ async fn build_remote_plugin_detail(
|
||||
pub async fn install_remote_plugin(
|
||||
config: &RemotePluginServiceConfig,
|
||||
auth: Option<&CodexAuth>,
|
||||
originator: &Originator,
|
||||
_marketplace_name: &str,
|
||||
plugin_id: &str,
|
||||
) -> Result<(), RemotePluginCatalogError> {
|
||||
@@ -889,7 +916,7 @@ pub async fn install_remote_plugin(
|
||||
|
||||
let base_url = config.chatgpt_base_url.trim_end_matches('/');
|
||||
let url = format!("{base_url}/ps/plugins/{plugin_id}/install");
|
||||
let client = build_process_reqwest_client();
|
||||
let client = build_reqwest_client(originator);
|
||||
let request = authenticated_request(client.post(&url), auth)?;
|
||||
let response: RemotePluginMutationResponse = send_and_decode(request, &url).await?;
|
||||
if response.id != plugin_id {
|
||||
@@ -912,12 +939,13 @@ pub async fn install_remote_plugin(
|
||||
pub async fn uninstall_remote_plugin(
|
||||
config: &RemotePluginServiceConfig,
|
||||
auth: Option<&CodexAuth>,
|
||||
originator: &Originator,
|
||||
codex_home: PathBuf,
|
||||
plugin_id: &str,
|
||||
) -> Result<(), RemotePluginCatalogError> {
|
||||
let auth = ensure_chatgpt_auth(auth)?;
|
||||
let plugin = fetch_plugin_detail(
|
||||
config, auth, plugin_id, /*include_download_urls*/ false,
|
||||
config, auth, originator, plugin_id, /*include_download_urls*/ false,
|
||||
)
|
||||
.await?;
|
||||
let marketplace_name = remote_plugin_canonical_marketplace_name(&plugin)?.to_string();
|
||||
@@ -925,7 +953,7 @@ pub async fn uninstall_remote_plugin(
|
||||
|
||||
let base_url = config.chatgpt_base_url.trim_end_matches('/');
|
||||
let url = format!("{base_url}/plugins/{plugin_id}/uninstall");
|
||||
let client = build_process_reqwest_client();
|
||||
let client = build_reqwest_client(originator);
|
||||
let request = authenticated_request(client.post(&url), auth)?;
|
||||
let response: RemotePluginMutationResponse = send_and_decode(request, &url).await?;
|
||||
if response.id != plugin_id {
|
||||
@@ -1179,13 +1207,15 @@ fn normalize_remote_default_prompt(prompt: &str) -> Option<Vec<String>> {
|
||||
async fn fetch_directory_plugins_for_scope(
|
||||
config: &RemotePluginServiceConfig,
|
||||
auth: &CodexAuth,
|
||||
originator: &Originator,
|
||||
scope: RemotePluginScope,
|
||||
) -> Result<Vec<RemotePluginDirectoryItem>, RemotePluginCatalogError> {
|
||||
let mut plugins = Vec::new();
|
||||
let mut page_token = None;
|
||||
loop {
|
||||
let response =
|
||||
get_remote_plugin_list_page(config, auth, scope, page_token.as_deref()).await?;
|
||||
get_remote_plugin_list_page(config, auth, originator, scope, page_token.as_deref())
|
||||
.await?;
|
||||
plugins.extend(response.plugins);
|
||||
let Some(next_page_token) = response.pagination.next_page_token else {
|
||||
break;
|
||||
@@ -1198,12 +1228,18 @@ async fn fetch_directory_plugins_for_scope(
|
||||
async fn fetch_shared_workspace_plugins(
|
||||
config: &RemotePluginServiceConfig,
|
||||
auth: &CodexAuth,
|
||||
originator: &Originator,
|
||||
) -> Result<Vec<RemotePluginDirectoryItem>, RemotePluginCatalogError> {
|
||||
let mut plugins = Vec::new();
|
||||
let mut page_token = None;
|
||||
loop {
|
||||
let response =
|
||||
get_remote_shared_workspace_plugins_page(config, auth, page_token.as_deref()).await?;
|
||||
let response = get_remote_shared_workspace_plugins_page(
|
||||
config,
|
||||
auth,
|
||||
originator,
|
||||
page_token.as_deref(),
|
||||
)
|
||||
.await?;
|
||||
plugins.extend(response.plugins);
|
||||
let Some(next_page_token) = response.pagination.next_page_token else {
|
||||
break;
|
||||
@@ -1216,10 +1252,11 @@ async fn fetch_shared_workspace_plugins(
|
||||
async fn fetch_installed_plugins_for_scope(
|
||||
config: &RemotePluginServiceConfig,
|
||||
auth: &CodexAuth,
|
||||
originator: &Originator,
|
||||
scope: RemotePluginScope,
|
||||
) -> Result<Vec<RemotePluginInstalledItem>, RemotePluginCatalogError> {
|
||||
fetch_installed_plugins_for_scope_with_download_url(
|
||||
config, auth, scope, /*include_download_urls*/ false,
|
||||
config, auth, originator, scope, /*include_download_urls*/ false,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@@ -1227,6 +1264,7 @@ async fn fetch_installed_plugins_for_scope(
|
||||
async fn fetch_installed_plugins_for_scope_with_download_url(
|
||||
config: &RemotePluginServiceConfig,
|
||||
auth: &CodexAuth,
|
||||
originator: &Originator,
|
||||
scope: RemotePluginScope,
|
||||
include_download_urls: bool,
|
||||
) -> Result<Vec<RemotePluginInstalledItem>, RemotePluginCatalogError> {
|
||||
@@ -1236,6 +1274,7 @@ async fn fetch_installed_plugins_for_scope_with_download_url(
|
||||
let response = get_remote_plugin_installed_page(
|
||||
config,
|
||||
auth,
|
||||
originator,
|
||||
scope,
|
||||
page_token.as_deref(),
|
||||
include_download_urls,
|
||||
@@ -1253,12 +1292,13 @@ async fn fetch_installed_plugins_for_scope_with_download_url(
|
||||
async fn get_remote_plugin_list_page(
|
||||
config: &RemotePluginServiceConfig,
|
||||
auth: &CodexAuth,
|
||||
originator: &Originator,
|
||||
scope: RemotePluginScope,
|
||||
page_token: Option<&str>,
|
||||
) -> Result<RemotePluginListResponse, RemotePluginCatalogError> {
|
||||
let base_url = config.chatgpt_base_url.trim_end_matches('/');
|
||||
let url = format!("{base_url}/ps/plugins/list");
|
||||
let client = build_process_reqwest_client();
|
||||
let client = build_reqwest_client(originator);
|
||||
let mut request = authenticated_request(client.get(&url), auth)?;
|
||||
request = request.query(&[("scope", scope.api_value())]);
|
||||
request = request.query(&[("limit", REMOTE_PLUGIN_LIST_PAGE_LIMIT)]);
|
||||
@@ -1271,11 +1311,12 @@ async fn get_remote_plugin_list_page(
|
||||
async fn get_remote_shared_workspace_plugins_page(
|
||||
config: &RemotePluginServiceConfig,
|
||||
auth: &CodexAuth,
|
||||
originator: &Originator,
|
||||
page_token: Option<&str>,
|
||||
) -> Result<RemotePluginListResponse, RemotePluginCatalogError> {
|
||||
let base_url = config.chatgpt_base_url.trim_end_matches('/');
|
||||
let url = format!("{base_url}/ps/plugins/workspace/shared");
|
||||
let client = build_process_reqwest_client();
|
||||
let client = build_reqwest_client(originator);
|
||||
let mut request = authenticated_request(client.get(&url), auth)?;
|
||||
request = request.query(&[("limit", REMOTE_PLUGIN_LIST_PAGE_LIMIT)]);
|
||||
if let Some(page_token) = page_token {
|
||||
@@ -1287,13 +1328,14 @@ async fn get_remote_shared_workspace_plugins_page(
|
||||
async fn get_remote_plugin_installed_page(
|
||||
config: &RemotePluginServiceConfig,
|
||||
auth: &CodexAuth,
|
||||
originator: &Originator,
|
||||
scope: RemotePluginScope,
|
||||
page_token: Option<&str>,
|
||||
include_download_urls: bool,
|
||||
) -> Result<RemotePluginInstalledResponse, RemotePluginCatalogError> {
|
||||
let base_url = config.chatgpt_base_url.trim_end_matches('/');
|
||||
let url = format!("{base_url}/ps/plugins/installed");
|
||||
let client = build_process_reqwest_client();
|
||||
let client = build_reqwest_client(originator);
|
||||
let mut request = authenticated_request(client.get(&url), auth)?;
|
||||
request = request.query(&[("scope", scope.api_value())]);
|
||||
if include_download_urls {
|
||||
@@ -1308,12 +1350,13 @@ async fn get_remote_plugin_installed_page(
|
||||
async fn fetch_plugin_detail(
|
||||
config: &RemotePluginServiceConfig,
|
||||
auth: &CodexAuth,
|
||||
originator: &Originator,
|
||||
plugin_id: &str,
|
||||
include_download_urls: bool,
|
||||
) -> Result<RemotePluginDirectoryItem, RemotePluginCatalogError> {
|
||||
let base_url = config.chatgpt_base_url.trim_end_matches('/');
|
||||
let url = format!("{base_url}/ps/plugins/{plugin_id}");
|
||||
let client = build_process_reqwest_client();
|
||||
let client = build_reqwest_client(originator);
|
||||
let mut request = authenticated_request(client.get(&url), auth)?;
|
||||
if include_download_urls {
|
||||
request = request.query(&[("includeDownloadUrls", true)]);
|
||||
|
||||
@@ -13,6 +13,7 @@ use crate::store::PLUGINS_CACHE_DIR;
|
||||
use crate::store::PluginStore;
|
||||
use crate::store::PluginStoreError;
|
||||
use codex_login::CodexAuth;
|
||||
use codex_login::default_client::Originator;
|
||||
use codex_plugin::PluginId;
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::BTreeSet;
|
||||
@@ -128,10 +129,15 @@ pub async fn sync_remote_installed_plugin_bundles_once(
|
||||
auth: Option<&CodexAuth>,
|
||||
) -> Result<RemoteInstalledPluginBundleSyncOutcome, RemoteInstalledPluginBundleSyncError> {
|
||||
let auth = ensure_chatgpt_auth(auth)?;
|
||||
let originator = Originator::process_default();
|
||||
let global = async {
|
||||
let scope = RemotePluginScope::Global;
|
||||
let installed_plugins = fetch_installed_plugins_for_scope_with_download_url(
|
||||
config, auth, scope, /*include_download_urls*/ true,
|
||||
config,
|
||||
auth,
|
||||
&originator,
|
||||
scope,
|
||||
/*include_download_urls*/ true,
|
||||
)
|
||||
.await?;
|
||||
Ok::<_, RemotePluginCatalogError>((scope, installed_plugins))
|
||||
@@ -139,7 +145,11 @@ pub async fn sync_remote_installed_plugin_bundles_once(
|
||||
let workspace = async {
|
||||
let scope = RemotePluginScope::Workspace;
|
||||
let installed_plugins = fetch_installed_plugins_for_scope_with_download_url(
|
||||
config, auth, scope, /*include_download_urls*/ true,
|
||||
config,
|
||||
auth,
|
||||
&originator,
|
||||
scope,
|
||||
/*include_download_urls*/ true,
|
||||
)
|
||||
.await?;
|
||||
Ok::<_, RemotePluginCatalogError>((scope, installed_plugins))
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use super::*;
|
||||
use codex_login::CodexAuth;
|
||||
use codex_login::default_client::Originator;
|
||||
use codex_login::default_client::build_reqwest_client;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use flate2::Compression;
|
||||
use flate2::write::GzEncoder;
|
||||
@@ -140,6 +142,7 @@ struct RemotePluginShareUpdateTargetsResponse {
|
||||
pub async fn save_remote_plugin_share(
|
||||
config: &RemotePluginServiceConfig,
|
||||
auth: Option<&CodexAuth>,
|
||||
originator: &Originator,
|
||||
codex_home: &Path,
|
||||
plugin_path: &AbsolutePathBuf,
|
||||
remote_plugin_id: Option<&str>,
|
||||
@@ -157,6 +160,7 @@ pub async fn save_remote_plugin_share(
|
||||
let upload = create_workspace_plugin_upload(
|
||||
config,
|
||||
auth,
|
||||
originator,
|
||||
&filename,
|
||||
archive_bytes.len(),
|
||||
remote_plugin_id,
|
||||
@@ -165,13 +169,14 @@ pub async fn save_remote_plugin_share(
|
||||
let etag = upload
|
||||
.etag
|
||||
.ok_or(RemotePluginCatalogError::MissingUploadEtag)?;
|
||||
put_workspace_plugin_upload(&upload.upload_url, archive_bytes).await?;
|
||||
put_workspace_plugin_upload(originator, &upload.upload_url, archive_bytes).await?;
|
||||
let share_targets = access_policy.share_targets;
|
||||
let share_targets =
|
||||
ensure_unlisted_workspace_target(auth, access_policy.discoverability, share_targets)?;
|
||||
let response = finalize_workspace_plugin_upload(
|
||||
config,
|
||||
auth,
|
||||
originator,
|
||||
remote_plugin_id,
|
||||
RemoteWorkspacePluginCreateRequest {
|
||||
file_id: upload.file_id,
|
||||
@@ -207,16 +212,17 @@ pub async fn save_remote_plugin_share(
|
||||
pub async fn list_remote_plugin_shares(
|
||||
config: &RemotePluginServiceConfig,
|
||||
auth: Option<&CodexAuth>,
|
||||
originator: &Originator,
|
||||
codex_home: &Path,
|
||||
) -> Result<Vec<RemotePluginShareSummary>, RemotePluginCatalogError> {
|
||||
let auth = ensure_chatgpt_auth(auth)?;
|
||||
let created_plugins = fetch_created_workspace_plugins(config, auth).await?;
|
||||
let created_plugins = fetch_created_workspace_plugins(config, auth, originator).await?;
|
||||
if created_plugins.is_empty() {
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
|
||||
let installed_by_id =
|
||||
fetch_installed_plugins_for_scope(config, auth, RemotePluginScope::Workspace)
|
||||
fetch_installed_plugins_for_scope(config, auth, originator, RemotePluginScope::Workspace)
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|plugin| (plugin.plugin.id.clone(), plugin))
|
||||
@@ -275,13 +281,14 @@ pub fn load_plugin_share_remote_ids_by_local_path(
|
||||
pub async fn delete_remote_plugin_share(
|
||||
config: &RemotePluginServiceConfig,
|
||||
auth: Option<&CodexAuth>,
|
||||
originator: &Originator,
|
||||
codex_home: &Path,
|
||||
remote_plugin_id: &str,
|
||||
) -> Result<(), RemotePluginCatalogError> {
|
||||
let auth = ensure_chatgpt_auth(auth)?;
|
||||
let base_url = config.chatgpt_base_url.trim_end_matches('/');
|
||||
let url = format!("{base_url}/public/plugins/workspace/{remote_plugin_id}");
|
||||
let client = build_process_reqwest_client();
|
||||
let client = build_reqwest_client(originator);
|
||||
let request = authenticated_request(client.delete(&url), auth)?;
|
||||
send_and_expect_status(request, &url, &[StatusCode::NO_CONTENT]).await?;
|
||||
if let Err(err) = local_paths::remove_plugin_share_local_path(codex_home, remote_plugin_id) {
|
||||
@@ -296,6 +303,7 @@ pub async fn delete_remote_plugin_share(
|
||||
pub async fn update_remote_plugin_share_targets(
|
||||
config: &RemotePluginServiceConfig,
|
||||
auth: Option<&CodexAuth>,
|
||||
originator: &Originator,
|
||||
remote_plugin_id: &str,
|
||||
targets: Vec<RemotePluginShareTarget>,
|
||||
discoverability: RemotePluginShareUpdateDiscoverability,
|
||||
@@ -314,7 +322,7 @@ pub async fn update_remote_plugin_share_targets(
|
||||
.unwrap_or_default();
|
||||
let base_url = config.chatgpt_base_url.trim_end_matches('/');
|
||||
let url = format!("{base_url}/ps/plugins/{remote_plugin_id}/shares");
|
||||
let client = build_process_reqwest_client();
|
||||
let client = build_reqwest_client(originator);
|
||||
let request = authenticated_request(client.put(&url), auth)?.json(
|
||||
&RemotePluginShareUpdateTargetsRequest {
|
||||
discoverability,
|
||||
@@ -358,12 +366,14 @@ fn ensure_unlisted_workspace_target(
|
||||
async fn fetch_created_workspace_plugins(
|
||||
config: &RemotePluginServiceConfig,
|
||||
auth: &CodexAuth,
|
||||
originator: &Originator,
|
||||
) -> Result<Vec<RemotePluginDirectoryItem>, RemotePluginCatalogError> {
|
||||
let mut plugins = Vec::new();
|
||||
let mut page_token = None;
|
||||
loop {
|
||||
let response =
|
||||
get_created_workspace_plugins_page(config, auth, page_token.as_deref()).await?;
|
||||
get_created_workspace_plugins_page(config, auth, originator, page_token.as_deref())
|
||||
.await?;
|
||||
plugins.extend(response.plugins);
|
||||
let Some(next_page_token) = response.pagination.next_page_token else {
|
||||
break;
|
||||
@@ -376,11 +386,12 @@ async fn fetch_created_workspace_plugins(
|
||||
async fn get_created_workspace_plugins_page(
|
||||
config: &RemotePluginServiceConfig,
|
||||
auth: &CodexAuth,
|
||||
originator: &Originator,
|
||||
page_token: Option<&str>,
|
||||
) -> Result<RemotePluginListResponse, RemotePluginCatalogError> {
|
||||
let base_url = config.chatgpt_base_url.trim_end_matches('/');
|
||||
let url = format!("{base_url}/ps/plugins/workspace/created");
|
||||
let client = build_process_reqwest_client();
|
||||
let client = build_reqwest_client(originator);
|
||||
let mut request = authenticated_request(client.get(&url), auth)?;
|
||||
request = request.query(&[("limit", REMOTE_PLUGIN_LIST_PAGE_LIMIT)]);
|
||||
if let Some(page_token) = page_token {
|
||||
@@ -392,13 +403,14 @@ async fn get_created_workspace_plugins_page(
|
||||
async fn create_workspace_plugin_upload(
|
||||
config: &RemotePluginServiceConfig,
|
||||
auth: &CodexAuth,
|
||||
originator: &Originator,
|
||||
filename: &str,
|
||||
size_bytes: usize,
|
||||
remote_plugin_id: Option<&str>,
|
||||
) -> Result<RemoteWorkspacePluginUploadUrlResponse, RemotePluginCatalogError> {
|
||||
let base_url = config.chatgpt_base_url.trim_end_matches('/');
|
||||
let url = format!("{base_url}/public/plugins/workspace/upload-url");
|
||||
let client = build_process_reqwest_client();
|
||||
let client = build_reqwest_client(originator);
|
||||
let request = authenticated_request(client.post(&url), auth)?.json(
|
||||
&RemoteWorkspacePluginUploadUrlRequest {
|
||||
filename,
|
||||
@@ -411,10 +423,11 @@ async fn create_workspace_plugin_upload(
|
||||
}
|
||||
|
||||
async fn put_workspace_plugin_upload(
|
||||
originator: &Originator,
|
||||
upload_url: &str,
|
||||
archive_bytes: Vec<u8>,
|
||||
) -> Result<(), RemotePluginCatalogError> {
|
||||
let client = build_process_reqwest_client();
|
||||
let client = build_reqwest_client(originator);
|
||||
let request = client
|
||||
.put(upload_url)
|
||||
.timeout(REMOTE_PLUGIN_CATALOG_TIMEOUT)
|
||||
@@ -443,6 +456,7 @@ async fn put_workspace_plugin_upload(
|
||||
async fn finalize_workspace_plugin_upload(
|
||||
config: &RemotePluginServiceConfig,
|
||||
auth: &CodexAuth,
|
||||
originator: &Originator,
|
||||
remote_plugin_id: Option<&str>,
|
||||
body: RemoteWorkspacePluginCreateRequest,
|
||||
) -> Result<RemoteWorkspacePluginCreateResponse, RemotePluginCatalogError> {
|
||||
@@ -452,7 +466,7 @@ async fn finalize_workspace_plugin_upload(
|
||||
} else {
|
||||
format!("{base_url}/public/plugins/workspace")
|
||||
};
|
||||
let client = build_process_reqwest_client();
|
||||
let client = build_reqwest_client(originator);
|
||||
let request = authenticated_request(client.post(&url), auth)?.json(&body);
|
||||
send_and_decode(request, &url).await
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ use super::local_paths;
|
||||
use codex_app_server_protocol::PluginAuthPolicy;
|
||||
use codex_app_server_protocol::PluginInstallPolicy;
|
||||
use codex_login::CodexAuth;
|
||||
use codex_login::default_client::Originator;
|
||||
use codex_plugin::PluginId;
|
||||
use codex_plugin::validate_plugin_segment;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
@@ -37,12 +38,14 @@ pub struct RemotePluginShareCheckoutResult {
|
||||
pub async fn checkout_remote_plugin_share(
|
||||
config: &RemotePluginServiceConfig,
|
||||
auth: Option<&CodexAuth>,
|
||||
originator: &Originator,
|
||||
codex_home: &Path,
|
||||
remote_plugin_id: &str,
|
||||
) -> Result<RemotePluginShareCheckoutResult, RemotePluginCatalogError> {
|
||||
let detail = super::super::fetch_remote_plugin_detail_with_download_urls(
|
||||
config,
|
||||
auth,
|
||||
originator,
|
||||
REMOTE_WORKSPACE_SHARED_WITH_ME_PRIVATE_MARKETPLACE_NAME,
|
||||
remote_plugin_id,
|
||||
)
|
||||
|
||||
@@ -229,9 +229,11 @@ async fn save_remote_plugin_share_creates_workspace_plugin() {
|
||||
.mount(&server)
|
||||
.await;
|
||||
|
||||
let originator = Originator::process_default();
|
||||
let result = save_remote_plugin_share(
|
||||
&config,
|
||||
Some(&auth),
|
||||
&originator,
|
||||
codex_home.path(),
|
||||
&plugin_path,
|
||||
/*remote_plugin_id*/ None,
|
||||
@@ -374,9 +376,11 @@ async fn save_remote_plugin_share_updates_existing_workspace_plugin() {
|
||||
.mount(&server)
|
||||
.await;
|
||||
|
||||
let originator = Originator::process_default();
|
||||
let result = save_remote_plugin_share(
|
||||
&config,
|
||||
Some(&auth),
|
||||
&originator,
|
||||
codex_home.path(),
|
||||
&plugin_path,
|
||||
Some("plugins_123"),
|
||||
@@ -445,9 +449,11 @@ async fn update_remote_plugin_share_targets_updates_targets() {
|
||||
.mount(&server)
|
||||
.await;
|
||||
|
||||
let originator = Originator::process_default();
|
||||
let result = update_remote_plugin_share_targets(
|
||||
&config,
|
||||
Some(&auth),
|
||||
&originator,
|
||||
"plugins_123",
|
||||
vec![
|
||||
RemotePluginShareTarget {
|
||||
@@ -577,7 +583,8 @@ async fn list_remote_plugin_shares_fetches_created_workspace_plugins() {
|
||||
.mount(&server)
|
||||
.await;
|
||||
|
||||
let result = list_remote_plugin_shares(&config, Some(&auth), codex_home.path())
|
||||
let originator = Originator::process_default();
|
||||
let result = list_remote_plugin_shares(&config, Some(&auth), &originator, codex_home.path())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -683,9 +690,16 @@ async fn delete_remote_plugin_share_deletes_workspace_plugin() {
|
||||
.mount(&server)
|
||||
.await;
|
||||
|
||||
delete_remote_plugin_share(&config, Some(&auth), codex_home.path(), "plugins_123")
|
||||
.await
|
||||
.unwrap();
|
||||
let originator = Originator::process_default();
|
||||
delete_remote_plugin_share(
|
||||
&config,
|
||||
Some(&auth),
|
||||
&originator,
|
||||
codex_home.path(),
|
||||
"plugins_123",
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
local_paths::load_plugin_share_local_paths(codex_home.path()).unwrap(),
|
||||
BTreeMap::new()
|
||||
|
||||
Reference in New Issue
Block a user