Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 65980a9847
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
codex-rs/core/src/plugins/manager.rs
Outdated
| force_reload: bool, | ||
| ) -> PluginLoadOutcome { | ||
| if !plugins_feature_enabled_from_stack(config_layer_stack) { | ||
| if !config.features.enabled(Feature::Plugins) { |
There was a problem hiding this comment.
Restrict plugin feature checks to trusted user config
plugins_for_layer_stack now gates on config.features.enabled(Feature::Plugins), which is computed from merged layers. A project .codex/config.toml can set [features].plugins = true and override a user-disabled flag, re-enabling persisted user plugins for that checkout. This breaks the prior user-opt-in boundary and lets untrusted project config influence plugin activation.
Useful? React with 👍 / 👎.
codex-rs/core/src/skills/manager.rs
Outdated
| let loaded_plugins = | ||
| self.plugins_manager | ||
| .plugins_for_layer_stack(cwd, &config_layer_stack, force_reload); | ||
| let config_toml: ConfigToml = match config_layer_stack.effective_config().try_into() { |
There was a problem hiding this comment.
Deserialize merged config with base path before skill load
skills_for_cwd_with_extra_user_roots uses effective_config().try_into::<ConfigToml>() directly. This skips deserialize_config_toml_with_base, so any relative AbsolutePathBuf field fails deserialization (AbsolutePathBuf deserialized without a base path). The method then returns an error and skips loading skills, even though normal config loading accepts those configs.
Useful? React with 👍 / 👎.
|
@codex review again |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 36c76cbc66
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
codex-rs/core/src/plugins/manager.rs
Outdated
|
|
||
| impl PluginsManager { | ||
| pub fn new(codex_home: PathBuf) -> Self { | ||
| pub fn new(codex_home: PathBuf, plugins_enabled: bool) -> Self { |
There was a problem hiding this comment.
Update all PluginsManager::new call sites
Changing PluginsManager::new to require plugins_enabled breaks callers that still use the old 1-arg API. In this commit, chatgpt/src/connectors.rs:119, cli/src/mcp_cmd.rs:392, and tui_app_server/src/chatwidget.rs:8851 still call PluginsManager::new(config.codex_home.clone()), which causes a compile-time arity error (E0061) for those crates.
Useful? React with 👍 / 👎.
codex-rs/core/src/thread_manager.rs
Outdated
| let plugins_manager = Arc::new(PluginsManager::new( | ||
| codex_home.clone(), | ||
| config.features.enabled(crate::features::Feature::Plugins), | ||
| )); |
There was a problem hiding this comment.
this instance is reused for all threads/sessions over the lifetime of the process. so for app-server, changing config after the process is started wouldn't update the value, and passing thread-level config that changes the value wouldn't be respected.
lmk if im misunderstanding, but this would basically make it static until you restart app-server
There was a problem hiding this comment.
Good call rollback to original approach.
5334dff to
07c90b2
Compare
|
@codex review this |
codex-rs/core/src/plugins/manager.rs
Outdated
| force_reload: bool, | ||
| ) -> PluginLoadOutcome { | ||
| if !plugins_feature_enabled_from_stack(config_layer_stack) { | ||
| if !config.features.enabled(Feature::Plugins) { |
There was a problem hiding this comment.
this reads cloud requirements, yes?
| let Some(plugins_value) = user_layer.config.get("plugins") else { | ||
| return HashMap::new(); | ||
| }; |
There was a problem hiding this comment.
as we discussed offline, this just reads the current enablement state of the plugins directly from config, without considering whether features.plugins is enabled. do we not want to gate this as well?
There was a problem hiding this comment.
looked a bit more, configured_plugins_from_stack seems like the main way existing functionality loads plugins. gating here seems like it would allow us to avoid gating on many of the higher level functions you added the gating to, as long as those work correctly when no plugins are returned (empty HashMap).
it seems that the only logic that needs to keep its own gate is the marketplace-reading logic in list_marketplaces_for_config.
im not sure if code-organization-wise pushing down the gate check is better (less random gate checks in higher-level functions, dont have to remember to add those checks yourself) or worse (less clear that those functions will return empty when features.plugin = false).
LMK what you think.
There was a problem hiding this comment.
I think configured_plugins_from_stack is a low-level help function and it makes sense to parse the config stack directly (no depends on config). But I do cleanup the configured_plugin_states more to get rid of the plugins_for_config call.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ee78106b04
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
codex-rs/core/src/plugins/manager.rs
Outdated
| if let Some(outcome) = self.cached_enabled_outcome() { | ||
| return outcome; |
There was a problem hiding this comment.
Restore force_reload semantics for plugin skill loading
skills_for_cwd*_ still accepts force_reload, but plugin resolution now calls plugins_for_config, which unconditionally returns cached_enabled_outcome when present. After plugin config/state changes, force_reload=true no longer refreshes plugin-provided roots, so stale plugin skills can persist until an unrelated clear_cache() runs.
Useful? React with 👍 / 👎.
| match load_marketplace(&marketplace_path) { | ||
| Ok(marketplace) => marketplaces.push(marketplace), | ||
| Err(err) => { | ||
| warn!( | ||
| path = %marketplace_path, | ||
| error = %err, | ||
| "skipping marketplace that failed to load" | ||
| ); | ||
| } |
There was a problem hiding this comment.
Narrow plugin/list fail-open handling to malformed files only
list_marketplaces_with_home now suppresses every load_marketplace failure and only logs a warning. This causes plugin/list to return partial/empty success responses for IO/permission/other hard failures, masking actionable errors. The intended behavior was fail-open for malformed marketplace data, not all marketplace load errors.
Useful? React with 👍 / 👎.
sayan-oai
left a comment
There was a problem hiding this comment.
approving to unblock as some of these fixes are urgent, but I think we should think about this comment to see which option is cleaner (it was already hard to debug this because of messy code 🙃).
and i know this is tedious/a nit, but it would be great if we could split this pr based on the 4 points in the description. the changes are all small but high impact on functionality, and I'm worried about rolling back 3 good fixes because they were bundled with one bug.
|
Removing plugins_for_layer_stack means a cwd-scoped plugin cache no longer makes sense, so I update it to a global cache. Also to fully respect the feature flag, we also need to add gating at the remaining callsites. The fail-open change for marketplace.json is a bit orthogonal, but it is small, so I’m keeping it in this PR. |
BAD PR
I messed up the commits in this PR and accidentally merged incorrect changes.