Commit Graph

15 Commits

Author SHA1 Message Date
jacobzhou-oai
56b82e676c Enforce Agent Plugin runtime boundaries (#37027)
## What changed

- Track Agent Plugin manifests through plugin, skill, and MCP loading so their capabilities use format-specific behavior without changing legacy plugins.
- Discover only direct-child skills, exclude app and hook capabilities, isolate MCP data, and reject MCP configuration files that are non-regular or resolve outside the plugin root.
- Bound model-visible skill instructions, plugin instructions, MCP descriptions, schemas, individual tools, and the aggregate Agent Plugin MCP tool set.
- Stop MCP and OAuth redirects when Agent Plugins send configured or authorization headers, while retaining existing redirect behavior for legacy MCP servers.

## Testing

- Add coverage for capability filtering, skill discovery, isolated MCP data and reserved-path expansion, unsafe MCP configuration files, context limits, and redirect handling.

GitOrigin-RevId: c9af66b051269f3226628ca280a58d32c808c38f
2026-08-05 04:54:33 +00:00
jacobzhou-oai
720c9d68e1 Skip symlinks when installing plugins (#36967)
## What changed

- Ignore symbolic links and other non-file, non-directory entries while copying a plugin into the store instead of rejecting the installation.
- Cover symlinked skill files and executables, verifying that the plugin installs without copying either link.

GitOrigin-RevId: da0cbbd95d12313afcaecdcb52824fc1922d0b74
2026-08-04 20:16:27 +00:00
jacobzhou-oai
2b5bdcf675 Support portable Agent Plugins throughout installation (#36544)
## Why

Agent Plugins use a schema-declared root `plugin.json` and can have dotted names or versions that do not fit Codex's directory-safe version format. The packaging and installation paths still assumed the legacy manifest layout and identifier rules.

## What changed

- Recognize valid root Agent Plugin manifests when discovering, packing, and installing plugins, while leaving unrelated root manifests on the legacy path.
- Accept safe dotted plugin names, default missing Agent Plugin versions to `1.0.0`, and derive stable directory-safe versions when necessary without rewriting the portable manifest.
- Skip legacy command migration for Agent Plugins and reject symlinks or other unsupported file types while copying plugin sources.

## Testing

Add coverage for portable bundle round trips, manifest discovery, dotted names, version handling, command preservation, and symlink rejection.

GitOrigin-RevId: 61476c4c4100495842253d8b429c0b896490962d
2026-08-02 02:29:45 +00:00
jameswt-oai
07fd04abb1 Propagate remote plugin IDs to skill metadata (#35261)
## What changed

- Carry a plugin's local and remote identities together from plugin loading into
  `SkillMetadata`.
- Resolve remote IDs from the installed-plugin snapshot when available, falling
  back to persisted install metadata only when no snapshot exists.
- Include plugin identity in skill cache keys so identity changes refresh cached
  skill metadata.

## Testing

- Cover snapshot and persisted identity resolution, local marketplace isolation,
  cached skill refreshes, and propagation through plugin skill snapshots.

GitOrigin-RevId: aabeeb631a43361fe817358ace7f1ea8ba5db708
2026-07-24 23:36:11 +00:00
charlesgong-openai
2cd6ed7509 Migrate plugin commands into skills on install (#33411)
## What changed

- Convert supported plugin command Markdown into generated skills when a plugin is installed.
- Read command sources from the manifest's `commands` field, falling back to the plugin's `commands/` directory.
- Load generated command skills alongside native plugin skills while preferring native skills with the same name.
- Skip commands with unsupported templates, missing descriptions, name collisions, or generated skills larger than 4 KB, and keep migration failures from blocking plugin installation.

## Testing

- Cover default and manifest-configured command paths, stale generated skill cleanup, size limits, native-skill precedence, invalid manifest fields, and non-fatal migration errors.

GitOrigin-RevId: 67d910048544b160b191066569bca69b2b951ebc
2026-07-15 19:51:37 +00:00
charlesgong-openai
1ee0e9a949 Log plugin install failure subtypes (#31518)
## Summary

- classify plugin store and remote bundle I/O failures by privacy-safe
operation context
- include the normalized `sub_error_type` in structured plugin-install
failure warnings
- leave analytics events and schemas unchanged

## Why

Top-level error types such as `store_io` collapse multiple filesystem
operations, making logs harder to diagnose. The subtype identifies the
failed operation without logging paths or new exception details.

## Impact

Plugin-install warning logs gain an optional normalized subtype.
Analytics payloads, app-server APIs, and stored data are unchanged.

## Validation

- `just fmt`
- `just test -p codex-core-plugins -p codex-app-server` (1,235 passed;
14 failed and 6 timed out because local `sandbox-exec` was denied,
`test_stdio_server` was unavailable, or user-level skill fixtures were
loaded)
2026-07-08 11:06:45 -04:00
xl-openai
9dbdb4e2c0 [plugins] Enforce marketplace source policy at runtime (#29691)
## Summary

- project effective marketplace/plugin config through the enterprise
source policy so blocked installed plugins become inactive
- filter plugin list/read/discovery and CLI marketplace source/snapshot
reporting using the same policy
- enforce source admission for background marketplace cache refreshes
- continue refreshing/upgrading independent marketplaces and plugins
when one entry fails, returning per-entry errors
- include policy-projected plugin state in cache and refresh keys so
requirement changes invalidate stale results

## Stack

This is PR 2 of 2 and is based on #29690. Review the admission model and
source matcher in #29690 first; this PR contains only runtime
enforcement.

## Test plan

- `just test -p codex-core-plugins` (287 tests)
- `just test -p codex-cli
plugin_list_ignores_implicit_system_marketplace_roots_without_manifests`
- `cargo check -p codex-cli -p codex-app-server --tests`
2026-06-27 15:22:05 -07:00
jameswt-oai
a72433d560 [codex-core-plugins] Remote Plugin ID Persisted to File (#27669)
## This PR

Remote plugin analytics cannot rely only on the in-memory
installed-plugin snapshot because that snapshot is refreshed
asynchronously after startup. This PR persists the authoritative backend
identity alongside each cached remote plugin bundle so later consumers
can resolve it without a network request.

### Behavior

- Store Codex-owned remote installation metadata in an atomic
`.codex-remote-plugin-install.json` sidecar under the plugin cache root.
- Use a versioned, snake_case schema:

  ```json
  {
    "schema_version": 1,
    "remote_plugin_id": "plugins~Plugin_..."
  }
  ```

- Write the metadata during remote bundle installation.
- Backfill it when bundle sync finds an already-current cached bundle.
- Clear it when a generic/local install replaces the cache.
- Let existing uninstall and stale-cache removal delete it with the
plugin cache root.
- Reject unsupported schema versions rather than silently misreading
future formats.

This PR does not change analytics serialization or event behavior.

### Review surface

The implementation is limited to four `codex-core-plugins` files:

- `store.rs`: owns the versioned sidecar read/write/remove lifecycle.
- `remote_bundle.rs`: persists the backend ID after a remote bundle
install.
- `remote/remote_installed_plugin_sync.rs`: backfills metadata for an
already-current cached bundle.
- Tests cover the storage lifecycle and both remote write paths.

## Testing / Validation

### Automated

- `just test -p codex-core-plugins` (268 tests passed)
- `just fix -p codex-core-plugins` passes with one pre-existing
`large_enum_variant` warning in `manifest.rs`.
- Coverage verifies the exact filename and JSON schema, identity
replacement, local reinstall clearing, uninstall cleanup, remote bundle
installation, unsupported schema rejection, and installed-plugin sync
backfill.

### Live manual validation

Validated the production app-server RPC path with an isolated temporary
`CODEX_HOME` and the PR-built Codex binary. The app-server communicated
over stdio and did not bind a port.

Test plugin: `plugins~Plugin_b80dd84519148191a409cde181c9b3d6`
(`build-macos-apps@openai-curated-remote`).

1. Confirmed `plugin/read` initially reported the plugin uninstalled.
2. Installed it through `plugin/install` and confirmed version `0.1.4`
was cached.
3. Verified
`$CODEX_HOME/plugins/cache/openai-curated-remote/build-macos-apps/.codex-remote-plugin-install.json`
was created beside the `0.1.4/` bundle directory with mode `0600` and
the expected contents:

   ```json
   {
     "schema_version": 1,
"remote_plugin_id": "plugins~Plugin_b80dd84519148191a409cde181c9b3d6"
   }
   ```

4. Deleted only the sidecar, restarted the app-server, and confirmed
installed-plugin startup sync recreated it with the same contents.
5. Uninstalled through `plugin/uninstall`, confirmed `plugin/read`
returned `installed: false`, and verified the local plugin cache root
was removed.
6. Restored the account's original uninstalled state and removed the
isolated home and copied credentials.

## Split Overview

```text
main
├── #27093  Debug analytics capture                     merged
│   └── #27099  Non-mutating plugin smoke               merged
│       └── #27100  Remote install/uninstall smoke      merged
└── #27102  Plugin telemetry metadata refactor          merged
    └── #27669  Persist remote plugin identity           ← this PR

Next:
└── Final PR: add explicit local and remote IDs to plugin analytics
```

This PR is based directly on `main`; prerequisite
[#27102](https://github.com/openai/codex/pull/27102) has merged. The
original combined [#26281](https://github.com/openai/codex/pull/26281)
remains the aggregate reference until the final replacement PR is
published.
2026-06-22 14:28:39 -07:00
charlesgong-openai
772c5c5195 [codex] Support marketplace plugin manifest fallback (#28789)
## Summary

Support marketplace plugins whose source directory does not include a
discoverable plugin manifest. Metadata-rich `marketplace.json` entries
now act as fallback plugin manifests for listing, local detail reads,
install, and non-curated cache refresh.

The fallback preserves marketplace-entry plugin fields wholesale, then
adds the small Codex-facing compatibility bridge for presentation
metadata. A real source `plugin.json` always wins when present.

## Details

- Capture flattened marketplace-entry fields into
`MarketplacePluginManifestFallback`, preserving fields such as
`version`, `description`, `skills`, `mcpServers`, `apps`, `hooks`,
`agents`, `commands`, `strict`, `author`, and future manifest fields
without a per-field translation list.
- Bridge Claude-style top-level `displayName`, `author.name`,
`homepage`, and marketplace `category` into Codex's nested `interface`
fields only when the nested values are absent.
- Treat fallback metadata as installable only when the marketplace entry
contributes metadata beyond bare `name` and `source`; existing
missing-manifest behavior remains for metadata-free entries.
- Read local plugin details from the already parsed fallback manifest,
including fallback-declared app and MCP paths, instead of rereading only
an on-disk manifest.
- Pass fallback contents into `PluginStore`, which validates them and
injects `.codex-plugin/plugin.json` into Store's existing atomic copy.
Local marketplace source directories are never mutated, and the fallback
path no longer needs an additional staging directory.
- Keep Git source materialization unchanged; Git clones still use the
existing marketplace source staging area before Store installation.
2026-06-18 15:49:27 -07:00
iceweasel-oai
d3d38159ed fix(plugins): keep version upgrades additive (#23356)
## Why

Windows can reject plugin cache upgrades when a running MCP server still
has its working directory inside the currently active plugin version.
The existing cache refresh path replaces
`plugins/cache/<marketplace>/<plugin>` as a whole, so a live handle
under the old version can make an otherwise ordinary version bump fail.

This PR keeps the existing plugin-selection model intact while making
version bumps less disruptive.

## What changed

- When installing a new version beside an existing plugin cache root,
move only the staged version directory into place instead of replacing
the whole plugin root.
- Best-effort prune older sibling version directories after the new
version is activated.
- Preserve the existing whole-root replacement path for first installs
and same-version refreshes.
- Add regression coverage for upgrading from `1.0.0` to `2.0.0` without
replacing the plugin root.

## Verification

- `cargo test -p codex-core-plugins install_with_new_version`
- `cargo fmt --package codex-core-plugins --check`
2026-05-19 04:02:30 +00:00
Abhinav
c6e7d564c3 Discover hooks bundled with plugins (#19705)
## Why

Plugins can bundle lifecycle hooks, but Codex previously only discovered
hooks from user, project, and managed config layers. This adds the
plugin discovery and runtime plumbing needed for plugin-bundled hooks
while keeping execution behind the `plugin_hooks` feature flag.

## What

- Discovers plugin hook sources from each plugin's default
`hooks/hooks.json`.
- Supports `plugin.json` manifest `hooks` entries as either relative
paths or inline hook objects.
- Plumbs discovered plugin hook sources through plugin loading into the
hook runtime when `plugin_hooks` is enabled.
- Marks plugin-originated hook runs as `HookSource::Plugin`.
- Injects `PLUGIN_ROOT` and `CLAUDE_PLUGIN_ROOT` into plugin hook
command environments.
- Updates generated schemas and hook source metadata for the plugin hook
source.

## Stack

1. This PR - openai/codex#19705
2. openai/codex#19778
3. openai/codex#19840
4. openai/codex#19882

## Reviewer Notes

- Core logic is in `codex-rs/core-plugins/src/loader.rs` and
`codex-rs/hooks/src/engine/discovery.rs`
- Moved existing / adding new tests to
`codex-rs/core-plugins/src/loader_tests.rs` hence the large diff there
- Otherwise mostly plumbing and minor schema updates

### Core Changes

The `codex-rs/core` changes are limited to wiring plugin hook support
into existing core flows:

- `core/src/session/session.rs` conditionally pulls effective plugin
hook sources and plugin hook load warnings from `PluginsManager` when
`plugin_hooks` is enabled, then passes them into `HooksConfig`.
- `core/src/hook_runtime.rs` adds the `plugin` metric tag for
`HookSource::Plugin`.
- `core/config.schema.json` picks up the new `plugin_hooks` feature
flag, and `core/src/plugins/manager_tests.rs` updates fixtures for the
added plugin hook fields.

---------

Co-authored-by: Codex <noreply@openai.com>
2026-04-28 14:17:18 -07:00
xl-openai
7d72fc8f53 feat: Cache remote plugin bundles on install (#19914)
Remote installs now fetch, validate, download, and cache the plugin
bundle locally
2026-04-28 00:53:27 -07:00
Eric Traut
e3f44ca3b3 Fix plugin cache panic when cwd is unavailable (#18499)
## Summary

Fixes #16637. (I hit this bug after 11h of work on a long-running task.)

Plugin cache initialization could panic when an already-absolute cache
path was normalized through `AbsolutePathBuf::from_absolute_path`,
because that path still consulted `current_dir()`.

This changes absolute-path normalization so already-absolute paths do
not depend on cwd, and makes plugin cache root construction available as
a fallible path through `PluginStore::try_new()`. Plugin cache subpaths
now use `AbsolutePathBuf::join()` instead of re-absolutizing derived
absolute paths.
2026-04-18 19:04:53 -07:00
xl-openai
37161bc76e feat: Handle alternate plugin manifest paths (#18182)
Load plugin manifests through a shared discoverable-path helper so
manifest reads, installs, and skill names all see the same alternate
manifest location.
2026-04-16 19:43:19 -07:00
xl-openai
48cf3ed7b0 Extract plugin loading and marketplace logic into codex-core-plugins (#18070)
Split plugin loading, marketplace, and related infrastructure out of
core into codex-core-plugins, while keeping the core-facing
configuration and orchestration flow in codex-core.

---------

Co-authored-by: Codex <noreply@openai.com>
2026-04-15 23:13:17 -07:00