Skip to content

fix(adapters): third-wave review findings (#346/#350/#352/#354/#357/#358) - #364

Merged
ScriptedAlchemy merged 1 commit into
mainfrom
fix/findings-wave3-adapters
Sep 3, 2026
Merged

fix(adapters): third-wave review findings (#346/#350/#352/#354/#357/#358)#364
ScriptedAlchemy merged 1 commit into
mainfrom
fix/findings-wave3-adapters

Conversation

@ScriptedAlchemy

Copy link
Copy Markdown
Owner

Summary

Test plan

  • adapter metadata/capability/host/claude-validation/codex/event-project suites 359 passed (only failure = known pre-existing worktree-env workspace/open starter)
  • route-unit pool, typecheck, lint

… path segments, tool_input contract, revision bumps
@changeset-bot

changeset-bot Bot commented Sep 3, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: e04b428

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
agent-bundle Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@ScriptedAlchemy
ScriptedAlchemy merged commit 305161a into main Sep 3, 2026
4 checks passed
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 3, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-03T04:38:04.599567Z e04b428 PR opened
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e04b4284cf

ℹ️ 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".

"$defs": {
"componentPath": {
"pattern": "^\\./(?!(?:.*\\/)?\\.\\.(?:\\/|$)).+",
"pattern": "^\\./(?!(?:.*[\\/\\\\])?\\.\\.(?:[\\/\\\\]|$))[^\\\\]+$",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Reject line terminators in hardened path patterns

The replacement final class matches line terminators, while the negative lookahead's .* does not. Consequently, a component path containing a newline followed by /../../outside passes this schema even though POSIX normalization escapes the plugin root; the same expression is copied into the three interface-asset patterns. Since this schema is the local guard for Codex manifests, exclude line terminators or make the traversal check span every character.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in #397 (merged as d25a9c6). plugin.schema.json now excludes line terminators (\n, \r, U+2028, U+2029), other control characters, and backslash-form parent segments in componentPath, composerIcon, logo, logoDark, and screenshots[] so a newline followed by /../ can no longer slip past the traversal guard; PROVENANCE.json sha/bytes re-pinned, Codex adapter revision 1.9.0 / composite plugin adapter 1.24.0, and tests/codex-plugin-validation.test.ts gained negative fixtures with embedded newlines and traversal for every path field.

Comment on lines +224 to +227
// The pinned permission-request input schema declares `"tool_input": true`
// (any JSON value), so presence is required but shape is tool-defined.
if (!Object.hasOwn(native, 'tool_input') || native.tool_input === undefined) {
return nativeEventError('native tool_input is required');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep Claude tool_input validation object-shaped

This relaxed check applies to Claude as well as Codex, although only the pinned Codex schema declares tool_input: true; Claude's PermissionRequest envelope remains object-shaped, like its other tool events. A malformed Claude replay or playground request with null, an array, or a scalar now reaches handlers as if it were a valid host envelope. Gate the any-JSON behavior on target === 'codex' and preserve the object check for Claude.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in #397 (merged as d25a9c6). The any-JSON tool_input relaxation in events/projection.ts is now Codex-only (whose pinned schema declares "tool_input": true); Claude permission/request envelopes keep the object-shaped requirement. Covered for both targets in tests/event-project.test.ts and tests/route-unit/event-project.test.ts.

ScriptedAlchemy added a commit that referenced this pull request Sep 3, 2026
…ds (#313) (#366)

Plain `.ts` routed CLI commands ran `runAgentRequest` with no providers, so
`(await agent()).providers` was empty on that surface while MCP, event,
rendered CLI, and rendered script scopes mounted the conventional registry.
The generated executable now runs the same ordered, fail-closed provider loop
before every plain request, with the framework-owned `processLifetime` value.

The rendered-session bridge also never posted `invocation` to its worker, so
providers behind rendered CLI commands and rendered scripts observed
`invocation: undefined`; the bridge forwards it now, and the routed-CLI
executable proof covers provider values on plain CLI, rendered CLI, and
rendered script surfaces.

Also aligns the binary-gated Codex install proof with the `interface.logo`
field the Codex adapter emits since #364.
@ScriptedAlchemy
ScriptedAlchemy deleted the fix/findings-wave3-adapters branch September 3, 2026 05:26
ScriptedAlchemy added a commit that referenced this pull request Sep 3, 2026
…st-install proof

#364 made the Codex adapter honor plugin.logo (interface.logo + shipped image). The
host-install fixture declares plugin.logo, so the binary-gated Codex host-install proofs
started failing on the interfaceFields key list. #368 fixed the built-bundle proof;
this brings the packed-tarball proof (packed-host-install-proof.test.ts) in line.
Test-expectation-only; product behavior is unchanged.

Found by the #181/#242 closed-issue re-verification.
ScriptedAlchemy added a commit that referenced this pull request Sep 3, 2026
…st-install proof (#367)

#364 made the Codex adapter honor plugin.logo (interface.logo + shipped image). The
host-install fixture declares plugin.logo, so the binary-gated Codex host-install proofs
started failing on the interfaceFields key list. #368 fixed the built-bundle proof;
this brings the packed-tarball proof (packed-host-install-proof.test.ts) in line.
Test-expectation-only; product behavior is unchanged.

Found by the #181/#242 closed-issue re-verification.
ScriptedAlchemy added a commit that referenced this pull request Sep 3, 2026
…staging link is still present

Hard-link publication leaves the sidecar doubly linked between the winner's
link() and the unlink of its .stage- file. A loser (or any reader) arriving in
that window hit the nlink !== 1 guard in #readSidecar and failed with
"Native Playground catalog snapshot is invalid." — the main CI flake on the
#364 merge run (Node 24). Account for the extra link by identity: a same-epoch
staging sibling sharing dev/ino, or the open handle reporting nlink 1 once the
staging file is gone. Other extra hard links stay rejected. Adds a
deterministic gate-ordered reproduction and an aliasing regression test.
ScriptedAlchemy added a commit that referenced this pull request Sep 3, 2026
…staging link is still present (#377)

Hard-link publication leaves the sidecar doubly linked between the winner's
link() and the unlink of its .stage- file. A loser (or any reader) arriving in
that window hit the nlink !== 1 guard in #readSidecar and failed with
"Native Playground catalog snapshot is invalid." — the main CI flake on the
#364 merge run (Node 24). Account for the extra link by identity: a same-epoch
staging sibling sharing dev/ino, or the open handle reporting nlink 1 once the
staging file is gone. Other extra hard links stay rejected. Adds a
deterministic gate-ordered reproduction and an aliasing regression test.
ScriptedAlchemy added a commit that referenced this pull request Sep 3, 2026
…ry PR with pinned CLIs

The host-install, packed host-install, and packed Claude plugin-validation
proofs skip their Claude/Codex legs when the CLIs are absent, which let #364
break both proofs on main unnoticed (#367/#368 repaired them from local runs).

- Pin @anthropic-ai/claude-code@2.1.250 and @openai/codex@0.147.0 as `hostCli`
  in each adapter's schema PROVENANCE.json; scripts/host-cli-pins.mjs reads
  the pins, refuses a pin that differs from observedCliVersion, installs them
  (re-running Claude's postinstall when npm blocks it), and fails closed with
  one diagnostic line when the CLI on PATH is not the pin.
- Add the host-install-proofs CI job (cached CLI prefix, version gate, build,
  test:host-install, test:host-install:packed, test:packed:native) honoring
  the docs-only skip. No secrets or login are needed.
- Harden the Codex interface proof: one shared pinned snapshot for both proof
  suites, installed manifest must equal the built artifact, validate against
  the pinned plugin schema, and reject fields outside the adapter's exported
  codexInterfaceFields.
- Document the job and the local commands in docs/local-ci.md and README.
ScriptedAlchemy added a commit that referenced this pull request Sep 3, 2026
…ry PR with pinned CLIs (#395)

* ci(host-proofs): run the binary-gated real-host install proofs on every PR with pinned CLIs

The host-install, packed host-install, and packed Claude plugin-validation
proofs skip their Claude/Codex legs when the CLIs are absent, which let #364
break both proofs on main unnoticed (#367/#368 repaired them from local runs).

- Pin @anthropic-ai/claude-code@2.1.250 and @openai/codex@0.147.0 as `hostCli`
  in each adapter's schema PROVENANCE.json; scripts/host-cli-pins.mjs reads
  the pins, refuses a pin that differs from observedCliVersion, installs them
  (re-running Claude's postinstall when npm blocks it), and fails closed with
  one diagnostic line when the CLI on PATH is not the pin.
- Add the host-install-proofs CI job (cached CLI prefix, version gate, build,
  test:host-install, test:host-install:packed, test:packed:native) honoring
  the docs-only skip. No secrets or login are needed.
- Harden the Codex interface proof: one shared pinned snapshot for both proof
  suites, installed manifest must equal the built artifact, validate against
  the pinned plugin schema, and reject fields outside the adapter's exported
  codexInterfaceFields.
- Document the job and the local commands in docs/local-ci.md and README.

* docs(local-ci): list dev-live-host among the CI-run host proofs

* fix(ci): key host CLI cache on package names and resolve npm global bin via prefix

Address the automated review on #395: the actions/cache key now includes each
pinned hostCli.package as well as its version, so a re-pin to a different
package with the same version misses the cache instead of reusing stale
binaries; and the installer derives npm's global bin directory from
`npm prefix -g` (<prefix>/bin on POSIX, the prefix itself on Windows)
instead of walking up from `npm root -g`.

* fix(ci): hash exact host CLI pins into the cache key

Sanitising package names for the actions/cache key can map distinct
packages (`@foo/bar`, `foo-bar`) to the same text; append a 16-hex SHA-256
of the exact `package@version` pairs so any re-pin misses the cache.

* fix(ci): probe installed host CLIs from the prefix only and reject bare --prefix

The post-install probe now runs with PATH limited to the prefix bin
directory plus the running Node, so a pre-existing claude/codex elsewhere
on the inherited PATH cannot mask an incomplete prefix. `install --prefix`
without a directory operand is rejected instead of silently installing
into the default global npm prefix.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant