8 Commits

  • [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`
  • [plugins] Expose marketplace source in marketplace list JSON (#27009)
    ## Summary
    - Follow-up to #26417 and #26631
    - Add `marketplaceSource` to `codex plugin marketplace list --json`
    entries for configured marketplaces
    - Reuse the existing `marketplaceSource` shape from `codex plugin list
    --json`
    - Keep human-readable marketplace list output unchanged
    - Add CLI coverage for configured local and git marketplace sources
    
    Example:
    
    ```json
    {
      "marketplaces": [
        {
          "name": "debug",
          "root": "/path/to/.codex/.tmp/marketplaces/debug",
          "marketplaceSource": {
            "sourceType": "git",
            "source": "https://example.com/acme/agent-skills.git"
          }
        }
      ]
    }
    ```
    
    ## Validation
    - `just fmt`
    - `just fix -p codex-cli`
    - `just test -p codex-cli marketplace_list`
    - `just test -p codex-cli`
  • Add JSON output for plugin subcommands (#26631)
    ## Summary
    - Follow-up to #25330 and #26417
    - Add `--json` output for `codex plugin add` and `codex plugin remove`
    - Add `--json` output for `codex plugin marketplace
    add/list/upgrade/remove`
    - Keep existing human-readable output unchanged
    - Keep existing error handling/stderr behavior unchanged; `--json`
    changes successful stdout output only
    - Align marketplace add/remove JSON field names with the existing
    app-server protocol shape
    - Add CLI coverage for plugin and marketplace JSON outputs
    
    ## Validation
    - `just fmt`
    - `just fix -p codex-cli`
    - `just test -p codex-cli`
  • Expose configured marketplace source in plugin list JSON (#26417)
    ## Summary
    - Follow-up to #25330
    - Add `marketplaceSource` to `codex plugin list --json` entries for
    configured marketplaces
    - Keep the existing per-plugin `source` field unchanged; this still
    reports the local plugin source path
    - Include only the configured marketplace `sourceType` and `source` from
    `config.toml`
    - Keep human-readable output unchanged
    - Add CLI coverage for configured local and git marketplace sources
    
    Example:
    
    ```json
    {
      "source": {
        "source": "local",
        "path": "/path/to/.codex/.tmp/marketplaces/debug/plugins/sample"
      },
      "marketplaceSource": {
        "sourceType": "git",
        "source": "https://example.com/acme/agent-skills.git"
      }
    }
    ```
    
    ## Validation
    - `just fmt`
    - `just fix -p codex-cli`
    - `just test -p codex-cli plugin_list`
  • [codex] Add plugin list JSON output (#25330)
    ## Summary
    - add `--json` output to `codex plugin list` with `installed` and
    `available` arrays
    - add `--available` for JSON output only; using it without `--json` is
    rejected
    - keep the existing non-JSON table output unchanged
    - add CLI coverage for JSON installed/available output and the
    `--available`/`--json` requirement
    
    ## Validation
    - `just test -p codex-cli plugin_list`
    - `just fix -p codex-cli`
    - `git diff --check`
    
    Note: `just fmt` ran Rust formatting first, then failed in the Python
    ruff step because `openai-codex-cli-bin==0.132.0` has no wheel for this
    Linux platform.
  • feat(plugins): tabulate plugin list output (#23727)
    ## Summary
    - render `codex plugin list` as one table per marketplace with the
    marketplace manifest path shown above each table
    - surface the installed plugin version in the CLI output by threading
    `installed_version` through marketplace listing state
    - narrow the system-root exemption so only known bundled/runtime
    marketplaces skip missing-manifest failures, and keep `VERSION` empty
    for cached-but-unconfigured plugins
    
    ## Rationale
    The plugin list UX was hard to scan as a flat list and did not show
    which installed version was active. This change makes the CLI output
    easier to read in the real multi-marketplace case, keeps the plugin path
    visible, fixes the Sapphire regression where bundled/runtime marketplace
    roots were blocking `plugin list`, and addresses the two review findings
    that came out of the follow-up deep review.
    
    ## Key Decisions
    - kept the CLI output grouped per marketplace instead of one global
    table so the marketplace path can live with the rows it owns
    - kept `VERSION` as the installed version, which means it is empty until
    a plugin is actually installed
    - handled the bundled/runtime regression in the CLI snapshot validation
    path rather than widening app-server protocol or changing marketplace
    loading behavior
    - narrowed the exemption to known system marketplace names plus expected
    system paths, so user-configured marketplaces under those directories
    still fail loudly
    - gated `installed_version` on actual installed state so `VERSION`
    cannot show stale cache state for `not installed` rows
    
    ## Validation
    - `just fmt`
    - Sapphire: `cargo test -p codex-cli --test plugin_cli` (`14 passed; 0
    failed`)
    - Sapphire smoke test: bundled/runtime roots still work
      - `cargo run -q -p codex-cli -- plugin add sample@debug`
      - `cargo run -q -p codex-cli -- plugin list`
    - verified the bundled/runtime-root scenario no longer errors and shows
    the expected marketplace table output
    - Sapphire smoke test: custom marketplace under bundled path still
    errors
    - verified `failed to load configured marketplace snapshot(s)` for
    `custom-marketplace`
    - Sapphire smoke test: cached-but-unconfigured plugin hides version
    - verified `sample@debug not installed` renders with an empty `VERSION`
    column
    
    ## Sample Output
    ```text
    /tmp/custom-marketplace/plugin.json
    NAME          VERSION  STATUS         DESCRIPTION
    sample@debug  1.0.0    enabled        Debug sample plugin
    other@local            not installed  Local development plugin
    ```
  • [codex] add plugin marketplace CLI commands (#21396)
    ## Why
    
    Plugin CLI installs should behave more like `apt-get install`:
    configured marketplaces are the only install sources, the local
    marketplace snapshot is the package index used at install time, and
    `plugins/cache` is only a cache of already-downloaded plugin bytes.
    
    That distinction matters once marketplaces and plugins have auth or
    availability state. A repo-local marketplace manifest or leftover cached
    plugin artifact should not silently become an install source unless the
    marketplace was explicitly configured and its readable snapshot still
    authorizes the plugin.
    
    ## What Changed
    
    - add CLI commands to list configured marketplaces and add, list, or
    remove marketplace plugins
    - accept stable `plugin@marketplace` ids for add/remove while preserving
    the explicit `--marketplace` form
    - restrict `codex plugin add` and `codex plugin list` to configured
    marketplaces instead of also discovering current-working-directory
    marketplace roots
    - fail `codex plugin add` and `codex plugin list` when a configured
    marketplace snapshot is missing or malformed instead of treating it as
    an empty source or a generic plugin miss
    - preserve marketplace snapshot semantics: a configured local/Git
    marketplace snapshot can authorize installs without consulting the
    original upstream source
    - allow `plugins/cache` reuse only after configured marketplace
    resolution succeeds
    - keep removal resilient after marketplace deletion or drift and ignore
    malformed marketplace config entries in listing
    
    ## Commands Added
    
    - `codex plugin add <plugin>@<marketplace>`
    - `codex plugin add <plugin> --marketplace <marketplace>`
    - `codex plugin list`
    - `codex plugin list --marketplace <marketplace>`
    - `codex plugin remove <plugin>@<marketplace>`
    - `codex plugin remove <plugin> --marketplace <marketplace>`
    - `codex plugin marketplace add <source>`
    - `codex plugin marketplace add <source> --ref <ref>`
    - `codex plugin marketplace add <source> --sparse <path>`
    - `codex plugin marketplace list`
    - `codex plugin marketplace upgrade`
    - `codex plugin marketplace upgrade <marketplace>`
    - `codex plugin marketplace remove <marketplace>`
    
    ## CLI Help Output
    
    <details>
    <summary><code>codex plugin --help</code></summary>
    
    ```text
    Manage Codex plugins
    
    Usage: codex plugin [OPTIONS] <COMMAND>
    
    Commands:
      add          Install a plugin from a configured marketplace snapshot
      list         List plugins available from configured marketplace snapshots
      marketplace  Add, list, upgrade, or remove configured plugin marketplaces
      remove       Remove an installed plugin from local config and cache
      help         Print this message or the help of the given subcommand(s)
    ```
    
    </details>
    
    <details>
    <summary><code>codex plugin add --help</code></summary>
    
    ```text
    Install a plugin from a configured marketplace snapshot.
    
    Pass either `PLUGIN@MARKETPLACE` or pass `PLUGIN` with `--marketplace MARKETPLACE`.
    
    Usage: codex plugin add [OPTIONS] <PLUGIN[@MARKETPLACE]>
    
    Arguments:
      <PLUGIN[@MARKETPLACE]>
              Plugin selector to install: either PLUGIN@MARKETPLACE or PLUGIN with --marketplace
    
    Options:
      -m, --marketplace <MARKETPLACE>
              Configured marketplace name to use when PLUGIN does not include @MARKETPLACE
    
    Examples:
      codex plugin add sample@debug
      codex plugin add sample --marketplace debug
    ```
    
    </details>
    
    <details>
    <summary><code>codex plugin list --help</code></summary>
    
    ```text
    List plugins available from configured marketplace snapshots
    
    Usage: codex plugin list [OPTIONS]
    
    Options:
      -m, --marketplace <MARKETPLACE>
              Only list plugins from this configured marketplace name
    
    Examples:
      codex plugin list
      codex plugin list --marketplace debug
    ```
    
    </details>
    
    <details>
    <summary><code>codex plugin remove --help</code></summary>
    
    ```text
    Remove an installed plugin from local config and cache.
    
    Pass either `PLUGIN@MARKETPLACE` or pass `PLUGIN` with `--marketplace MARKETPLACE`.
    
    Usage: codex plugin remove [OPTIONS] <PLUGIN[@MARKETPLACE]>
    
    Arguments:
      <PLUGIN[@MARKETPLACE]>
              Plugin selector to remove: either PLUGIN@MARKETPLACE or PLUGIN with --marketplace
    
    Options:
      -m, --marketplace <MARKETPLACE>
              Marketplace name to use when PLUGIN does not include @MARKETPLACE
    
    Examples:
      codex plugin remove sample@debug
      codex plugin remove sample --marketplace debug
    ```
    
    </details>
    
    <details>
    <summary><code>codex plugin marketplace --help</code></summary>
    
    ```text
    Add, list, upgrade, or remove configured plugin marketplaces
    
    Usage: codex plugin marketplace [OPTIONS] <COMMAND>
    
    Commands:
      add      Add a local or Git marketplace to the configured marketplace sources
      list     List configured marketplace names and their local snapshot roots
      upgrade  Refresh configured Git marketplace snapshots
      remove   Remove a configured marketplace source by name
    ```
    
    </details>
    
    <details>
    <summary><code>codex plugin marketplace add --help</code></summary>
    
    ```text
    Add a local or Git marketplace to the configured marketplace sources
    
    Usage: codex plugin marketplace add [OPTIONS] <SOURCE>
    
    Arguments:
      <SOURCE>
              Marketplace source: a local path, owner/repo[@ref], HTTPS Git URL, or SSH Git URL
    
    Options:
          --ref <REF>
              Git ref to fetch for Git marketplace sources
    
          --sparse <PATH>
              Sparse checkout path for Git marketplace sources. Can be repeated
    
    Examples:
      codex plugin marketplace add ./path/to/marketplace
      codex plugin marketplace add owner/repo --ref main
      codex plugin marketplace add https://github.com/owner/repo --sparse plugins/foo
    ```
    
    </details>
    
    <details>
    <summary><code>codex plugin marketplace list --help</code></summary>
    
    ```text
    List configured marketplace names and their local snapshot roots
    
    Usage: codex plugin marketplace list [OPTIONS]
    ```
    
    </details>
    
    <details>
    <summary><code>codex plugin marketplace upgrade --help</code></summary>
    
    ```text
    Refresh configured Git marketplace snapshots.
    
    Omit MARKETPLACE_NAME to upgrade all configured Git marketplaces.
    
    Usage: codex plugin marketplace upgrade [OPTIONS] [MARKETPLACE_NAME]
    
    Arguments:
      [MARKETPLACE_NAME]
              Optional configured marketplace name to upgrade. Omit to upgrade all Git marketplaces
    
    Examples:
      codex plugin marketplace upgrade
      codex plugin marketplace upgrade debug
    ```
    
    </details>
    
    <details>
    <summary><code>codex plugin marketplace remove --help</code></summary>
    
    ```text
    Remove a configured marketplace source by name
    
    Usage: codex plugin marketplace remove [OPTIONS] <MARKETPLACE_NAME>
    
    Arguments:
      <MARKETPLACE_NAME>
              Configured marketplace name to remove
    
    Example:
      codex plugin marketplace remove debug
    ```
    
    </details>
    
    ## Public Semantics
    
    - `codex plugin add <plugin>@<marketplace>` succeeds only when
    `<marketplace>` is configured and its local marketplace snapshot
    contains `<plugin>`
    - repo-local marketplaces are not install sources until the user runs
    `codex plugin marketplace add ...`
    - configured marketplace snapshots must be readable; missing or
    malformed snapshots fail the CLI operation rather than silently falling
    through to cache or empty results
    - cached plugin artifacts can satisfy reinstall only when the configured
    marketplace snapshot still authorizes that plugin
    - cached plugin artifacts alone never make a plugin installable
    
    ## Tests
    
    - `cargo test -p codex-cli --test plugin_cli`
    - `cargo clippy -p codex-cli --tests -- -D warnings`
    - `cargo test -p codex-cli`
    - `git diff --check`
    - `just bazel-lock-update`
    - `just bazel-lock-check`