mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
[codex] Pass auth mode to plugin manager (#27517)
## Summary - Add auth mode state to `PluginsManager`. - Sync the plugin manager auth mode when `ThreadManager` is created and when account auth changes. - Route plugin load outcomes through an auth-aware projection hook so follow-up plugin filtering can stay inside `core-plugins`. ## Motivation This prepares plugin capability loading to be configured by auth mode, such as hiding or exposing app/MCP-backed plugin surfaces based on whether the user is using ChatGPT auth or API-key auth, without leaking those details outside the plugin manager. ## Tests - `just fmt` - `just test -p codex-core-plugins` - `env -u CODEX_SANDBOX_NETWORK_DISABLED -u CODEX_SANDBOX just test -p codex-core thread_manager::tests` - `env -u CODEX_SANDBOX_NETWORK_DISABLED -u CODEX_SANDBOX just test -p codex-app-server`
This commit is contained in:
committed by
GitHub
Unverified
parent
4435ff2810
commit
856855914f
@@ -158,6 +158,9 @@ impl AccountRequestProcessor {
|
||||
|
||||
pub(crate) fn clear_external_auth(&self) {
|
||||
self.auth_manager.clear_external_auth();
|
||||
self.thread_manager
|
||||
.plugins_manager()
|
||||
.set_auth_mode(self.auth_manager.get_api_auth_mode());
|
||||
}
|
||||
|
||||
fn current_account_updated_notification(&self) -> AccountUpdatedNotification {
|
||||
@@ -173,6 +176,10 @@ impl AccountRequestProcessor {
|
||||
thread_manager: &Arc<ThreadManager>,
|
||||
auth: Option<CodexAuth>,
|
||||
) {
|
||||
thread_manager
|
||||
.plugins_manager()
|
||||
.set_auth_mode(auth.as_ref().map(CodexAuth::api_auth_mode));
|
||||
|
||||
match config_manager
|
||||
.load_latest_config(/*fallback_cwd*/ None)
|
||||
.await
|
||||
|
||||
@@ -48,6 +48,7 @@ use crate::store::PluginInstallResult as StorePluginInstallResult;
|
||||
use crate::store::PluginStore;
|
||||
use crate::store::PluginStoreError;
|
||||
use codex_analytics::AnalyticsEventsClient;
|
||||
use codex_app_server_protocol::AuthMode;
|
||||
use codex_config::ConfigLayerStack;
|
||||
use codex_config::clear_user_plugin;
|
||||
use codex_config::set_user_plugin_enabled;
|
||||
@@ -203,6 +204,13 @@ fn featured_plugin_ids_cache_key(
|
||||
}
|
||||
}
|
||||
|
||||
fn project_plugin_load_outcome_for_auth(
|
||||
outcome: PluginLoadOutcome,
|
||||
_auth_mode: Option<AuthMode>,
|
||||
) -> PluginLoadOutcome {
|
||||
outcome
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct PluginInstallRequest {
|
||||
pub plugin_name: String,
|
||||
@@ -319,6 +327,7 @@ pub struct PluginsManager {
|
||||
remote_installed_plugins_cache_refresh_state: RwLock<RemoteInstalledPluginsCacheRefreshState>,
|
||||
global_remote_catalog_cache_refresh_state: RwLock<GlobalRemoteCatalogCacheRefreshState>,
|
||||
restriction_product: Option<Product>,
|
||||
auth_mode: RwLock<Option<AuthMode>>,
|
||||
analytics_events_client: RwLock<Option<AnalyticsEventsClient>>,
|
||||
}
|
||||
|
||||
@@ -375,10 +384,30 @@ impl PluginsManager {
|
||||
GlobalRemoteCatalogCacheRefreshState::default(),
|
||||
),
|
||||
restriction_product,
|
||||
auth_mode: RwLock::new(None),
|
||||
analytics_events_client: RwLock::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_auth_mode(&self, auth_mode: Option<AuthMode>) -> bool {
|
||||
let mut stored_auth_mode = match self.auth_mode.write() {
|
||||
Ok(auth_mode_guard) => auth_mode_guard,
|
||||
Err(err) => err.into_inner(),
|
||||
};
|
||||
if *stored_auth_mode == auth_mode {
|
||||
return false;
|
||||
}
|
||||
*stored_auth_mode = auth_mode;
|
||||
true
|
||||
}
|
||||
|
||||
pub fn auth_mode(&self) -> Option<AuthMode> {
|
||||
match self.auth_mode.read() {
|
||||
Ok(auth_mode_guard) => *auth_mode_guard,
|
||||
Err(err) => *err.into_inner(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_analytics_events_client(&self, analytics_events_client: AnalyticsEventsClient) {
|
||||
let mut stored_client = match self.analytics_events_client.write() {
|
||||
Ok(client_guard) => client_guard,
|
||||
@@ -417,7 +446,7 @@ impl PluginsManager {
|
||||
remote_plugin_enabled: config.remote_plugin_enabled,
|
||||
};
|
||||
if !force_reload && let Some(outcome) = self.cached_enabled_outcome(&cache_key) {
|
||||
return outcome;
|
||||
return self.project_plugins_for_auth(outcome);
|
||||
}
|
||||
|
||||
let Ok(_load_permit) = self.enabled_outcome_load_semaphore.acquire().await else {
|
||||
@@ -425,7 +454,7 @@ impl PluginsManager {
|
||||
return PluginLoadOutcome::default();
|
||||
};
|
||||
if !force_reload && let Some(outcome) = self.cached_enabled_outcome(&cache_key) {
|
||||
return outcome;
|
||||
return self.project_plugins_for_auth(outcome);
|
||||
}
|
||||
let cache_generation = self.enabled_outcome_cache_generation();
|
||||
let outcome = load_plugins_from_layer_stack(
|
||||
@@ -438,7 +467,11 @@ impl PluginsManager {
|
||||
.await;
|
||||
log_plugin_load_errors(&outcome);
|
||||
self.cache_enabled_outcome_if_current(cache_generation, cache_key, outcome.clone());
|
||||
outcome
|
||||
self.project_plugins_for_auth(outcome)
|
||||
}
|
||||
|
||||
fn project_plugins_for_auth(&self, outcome: PluginLoadOutcome) -> PluginLoadOutcome {
|
||||
project_plugin_load_outcome_for_auth(outcome, self.auth_mode())
|
||||
}
|
||||
|
||||
pub fn clear_cache(&self) {
|
||||
@@ -468,14 +501,15 @@ impl PluginsManager {
|
||||
if !config.plugins_enabled {
|
||||
return PluginLoadOutcome::default();
|
||||
}
|
||||
load_plugins_from_layer_stack(
|
||||
let outcome = load_plugins_from_layer_stack(
|
||||
config_layer_stack,
|
||||
self.remote_installed_plugin_configs(),
|
||||
&self.store,
|
||||
self.restriction_product,
|
||||
config.remote_plugin_enabled,
|
||||
)
|
||||
.await
|
||||
.await;
|
||||
self.project_plugins_for_auth(outcome)
|
||||
}
|
||||
|
||||
/// Resolve plugin hooks for a config layer stack without loading other plugin capabilities.
|
||||
|
||||
@@ -17,6 +17,7 @@ use crate::test_support::load_plugins_config as load_plugins_config_input;
|
||||
use crate::test_support::write_curated_plugin_sha_with as write_curated_plugin_sha;
|
||||
use crate::test_support::write_file;
|
||||
use crate::test_support::write_openai_curated_marketplace;
|
||||
use codex_app_server_protocol::AuthMode;
|
||||
use codex_app_server_protocol::ConfigLayerSource;
|
||||
use codex_config::AppToolApproval;
|
||||
use codex_config::CONFIG_TOML_FILE;
|
||||
@@ -47,6 +48,21 @@ use wiremock::matchers::query_param;
|
||||
|
||||
const MAX_CAPABILITY_SUMMARY_DESCRIPTION_LEN: usize = 1024;
|
||||
|
||||
#[test]
|
||||
fn plugins_manager_tracks_auth_mode() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let manager = PluginsManager::new(tmp.path().to_path_buf());
|
||||
|
||||
assert_eq!(manager.auth_mode(), None);
|
||||
assert!(manager.set_auth_mode(Some(AuthMode::ApiKey)));
|
||||
assert_eq!(manager.auth_mode(), Some(AuthMode::ApiKey));
|
||||
assert!(!manager.set_auth_mode(Some(AuthMode::ApiKey)));
|
||||
assert!(manager.set_auth_mode(Some(AuthMode::ChatgptAuthTokens)));
|
||||
assert_eq!(manager.auth_mode(), Some(AuthMode::ChatgptAuthTokens));
|
||||
assert!(manager.set_auth_mode(/*auth_mode*/ None));
|
||||
assert_eq!(manager.auth_mode(), None);
|
||||
}
|
||||
|
||||
fn write_plugin_with_version(
|
||||
root: &Path,
|
||||
dir_name: &str,
|
||||
|
||||
@@ -272,6 +272,7 @@ impl ThreadManager {
|
||||
codex_home.to_path_buf(),
|
||||
restriction_product,
|
||||
));
|
||||
plugins_manager.set_auth_mode(auth_manager.get_api_auth_mode());
|
||||
let mcp_manager = Arc::new(McpManager::new_with_extensions(
|
||||
Arc::clone(&plugins_manager),
|
||||
Arc::clone(&extensions),
|
||||
@@ -365,6 +366,7 @@ impl ThreadManager {
|
||||
codex_home.clone(),
|
||||
restriction_product,
|
||||
));
|
||||
plugins_manager.set_auth_mode(auth_manager.get_api_auth_mode());
|
||||
let mcp_manager = Arc::new(McpManager::new(Arc::clone(&plugins_manager)));
|
||||
let skills_manager = Arc::new(SkillsManager::new_with_restriction_product(
|
||||
skills_codex_home,
|
||||
|
||||
Reference in New Issue
Block a user