Skip to content

fix(v2): harden unreadable routed agent tasks - #336

Merged
lidge-jun merged 2 commits into
lidge-jun:devfrom
MathiasHeinke:codex/v2-fernet-guard-hardening
Jul 24, 2026
Merged

fix(v2): harden unreadable routed agent tasks#336
lidge-jun merged 2 commits into
lidge-jun:devfrom
MathiasHeinke:codex/v2-fernet-guard-hardening

Conversation

@MathiasHeinke

@MathiasHeinke MathiasHeinke commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Summary

This is the clean follow-up rebuild for #283 on current dev (d9e06c8d). It closes the mixed-slot and failover bypasses documented after the original merge/revert, while leaving the responses facade unchanged.

Current PR head: 87af85fb9df8bf8a4fbe0e1ae5fbb122bfe84fa9.

What changed

  • Classify the current raw routed agent_message before history expansion, compatibility mutation, sanitization, parsing, collaboration injection, adapter construction, or fetch.
  • Recognize only canonical padded Fernet structure using base64url round-trip, version byte, minimum size, CBC block shape, and safe token boundaries.
  • Inspect only the newly delivered task item, skipping allowed trailing metadata, so encrypted history cannot poison later plaintext work.
  • Strip bounded current and future CXC compatibility preambles before deciding whether meaningful plaintext remains.
  • Return a static machine-readable HTTP 400 with code unreadable_encrypted_agent_task and never echo ciphertext.
  • For mixed combos, constrain both initial selection and every failover to resolved canonical ChatGPT-forward provider shape. If no eligible native target exists, fail before any provider call.
  • Update the English and Chinese sub-agent guides with the typed error, native combo behavior, and recovery options.

Verification

  • GitHub checks on 87af85fb: 10 passed, 0 failed, 0 pending (Linux, macOS, Windows, npm-global on all three, React Doctor, target enforcement, label, CodeRabbit).
  • Full PR diff SHA-256: d0cf7b89abed89de44abb1584030f925d74bfb2fe4c952aeafc020364db118ab.
  • Tree: c6defa10a4d6e6d43aff2c115369cce16e011a82.
  • Six-file runtime/security diff SHA-256: 207ba99280383f4f706347869c7b092e480171f601dd41a24aaa4f459d775bee (unchanged from the independently reviewed 733cec4d code commit).
  • Canonical full suite on the unchanged runtime diff: 3,803 passed, 0 failed across 309 files.
  • Post-documentation local gates: focused guard/combo/compatibility suite 85 passed, 0 failed; typecheck PASS; privacy scan PASS; diff check PASS.
  • Docs site: frozen-lockfile install and Astro production build PASS, 121 pages generated.
  • GitNexus: runtime change surface reviewed; documentation follow-up LOW risk, 0 affected execution flows.
  • Route-receipt validator PASS; validator suite 32 passed, 0 failed.

Independent security review

  • Kimi K3 through the approved CLI adapter: PASS, no P0/P1/P2.
  • Claude Code Opus 4.8 xhigh through Claude Max: PASS, no P0/P1/P2.
  • Separate read-only Codex GPT-5.5 CAO: PASS, no P0/P1/P2.
  • CodeRabbit on the current head: no actionable findings.

All independent security reviews covered the unchanged six-file runtime diff. The only review finding on the PR requested documentation sync; it was addressed in 87af85fb and the thread is resolved.

No secrets, decryption keys, captured real task payloads, or ciphertext reflection are included.

Closes the follow-up identified in #283.

Summary by CodeRabbit

  • New Features

    • Improved handling of encrypted agent tasks by identifying unreadable payloads and routing them only to compatible backends.
    • Added clear unreadable_encrypted_agent_task errors when no compatible destination is available.
    • Preserved encrypted payload handling during combo failover.
  • Bug Fixes

    • Improved detection of valid encrypted content and reduced false positives.
  • Documentation

    • Clarified encrypted task routing, failover behavior, model inheritance, and recovery options.

@github-actions github-actions Bot added the bug Something isn't working label Jul 23, 2026

@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: c454af188f

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

Comment thread src/server/responses.ts Outdated
@MathiasHeinke
MathiasHeinke force-pushed the codex/v2-fernet-guard-hardening branch from c454af1 to 733cec4 Compare July 23, 2026 14:37
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The change structurally validates embedded Fernet payloads, refines unreadable agent-task detection, and restricts combo routing and retries to decrypt-capable native OpenAI targets with a shared error response. English and Chinese documentation describe the resulting delivery and recovery rules.

Changes

Encrypted agent-task routing

Layer / File(s) Summary
Structural payload classification
src/server/responses/encrypted-payload.ts, tests/multi-agent-compat.test.ts, tests/v2-agent-message-failfast.test.ts
Fernet detection now validates token structure and boundaries. Unreadable-task classification considers current agent messages, readable text records, routing envelopes, and broader CXC control paragraphs; tests cover valid, invalid, mixed, historical, and plaintext cases.
Decryptability-aware combo selection
src/combos/resolve.ts, src/server/responses/core.ts, tests/combos.test.ts, tests/v2-agent-message-failfast.test.ts
Combo target selection and retry advancement apply payload decryptability alongside cooldown checks, reject requests with no eligible native target using a shared 400 error response, and test forwarding and failover ordering.
Encrypted task delivery documentation
docs-site/src/content/docs/guides/sub-agent-surface.md, docs-site/src/content/docs/zh-cn/guides/sub-agent-surface.md
English and Chinese guides document encrypted v2 task routing, explicit unreadable-task errors, native-target requirements, failover behavior, and recovery options.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant handleResponses
  participant handleComboResponses
  participant pickComboTarget
  participant NativeOpenAI as canonical OpenAI forward provider
  Client->>handleResponses: submit parsed agent task
  handleResponses->>handleComboResponses: pass unreadable-task status
  handleComboResponses->>pickComboTarget: select decryptable target
  pickComboTarget->>NativeOpenAI: forward encrypted task
  NativeOpenAI-->>handleComboResponses: response or failure
  handleComboResponses->>pickComboTarget: retry with payload eligibility
Loading

Suggested reviewers: ingwannu, lidge-j

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: hardening unreadable routed agent task handling in v2.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@lidge-jun
lidge-jun force-pushed the codex/v2-fernet-guard-hardening branch from 87af85f to 9f75de0 Compare July 23, 2026 19:01
@lidge-jun

Copy link
Copy Markdown
Owner

Maintainer takeover update for PR #336:

This is a fail-fast mitigation for issue #92; it does not solve or close #92. Thank you, @MathiasHeinke, for the contribution.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs-site/src/content/docs/guides/sub-agent-surface.md`:
- Line 9: Synchronize the translated sub-agent surface documentation in the
Japanese, Korean, and Russian guides with the current English/zh-cn behavior.
Replace the outdated “task text can be lost” description with the
`unreadable_encrypted_agent_task` failure for direct native-to-non-native
routes, and document that combos prefer a decrypt-capable native ChatGPT target.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 20a5eaf5-367c-4a25-8411-6dd4baa1a1ef

📥 Commits

Reviewing files that changed from the base of the PR and between 87af85f and 9f75de0.

📒 Files selected for processing (8)
  • docs-site/src/content/docs/guides/sub-agent-surface.md
  • docs-site/src/content/docs/zh-cn/guides/sub-agent-surface.md
  • src/combos/resolve.ts
  • src/server/responses/core.ts
  • src/server/responses/encrypted-payload.ts
  • tests/combos.test.ts
  • tests/multi-agent-compat.test.ts
  • tests/v2-agent-message-failfast.test.ts


:::note
On the v2 surface (`multi_agent_v2`), a spawned sub-agent inherits the parent model **by default**: `fork_turns` defaults to `all`, and full-history forks reject overrides. Since v2.7.2 opencodex injects guidance that teaches the model how to break inheritance — a `spawn_agent` call that sets `fork_turns` to `"none"` (or a partial fork such as `"3"`) can pass `model` / `reasoning_effort` arguments, which the Codex runtime parses and applies even though the published tool schema hides them. Known limitation: when a **native** parent spawns a child routed to a **non-native** provider, the Codex client may send the `NEW_TASK` payload only as backend-encrypted `encrypted_content`, so the routed child receives an empty task body ([#92](https://github.com/lidge-jun/opencodex/issues/92)). The model override still applies, but the task text can be lost — the v1 surface remains the reliable choice for heterogeneous-provider delegation.
On the v2 surface (`multi_agent_v2`), a spawned sub-agent inherits the parent model **by default**: `fork_turns` defaults to `all`, and full-history forks reject overrides. Since v2.7.2 opencodex injects guidance that teaches the model how to break inheritance — a `spawn_agent` call that sets `fork_turns` to `"none"` (or a partial fork such as `"3"`) can pass `model` / `reasoning_effort` arguments, which the Codex runtime parses and applies even though the published tool schema hides them. Known transport limitation: when a **native** parent spawns a child routed to a **non-native** provider, the Codex client may send the `NEW_TASK` payload only as backend-encrypted `encrypted_content` ([#92](https://github.com/lidge-jun/opencodex/issues/92)). opencodex does not forward that unreadable task to an external provider: a direct route fails with HTTP 400 and code `unreadable_encrypted_agent_task`, while a combo skips non-decrypting targets and selects a canonical native ChatGPT target when one is available. Use v1 for heterogeneous-provider delegation, select a native ChatGPT child, or resend the task as plaintext v2 `agent_message` content.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check for other locale copies of this guide and whether they still contain the old wording.
fd 'sub-agent-surface.md' docs-site/src/content/docs
echo "---"
for f in $(fd 'sub-agent-surface.md' docs-site/src/content/docs); do
  echo "== $f =="
  rg -n 'unreadable_encrypted_agent_task|encrypted_content|task text can be lost' "$f" || echo "(no match — likely stale)"
done

Repository: lidge-jun/opencodex

Length of output: 6642


Sync the sub-agent-surface.md translations
docs-site/src/content/docs/ja/guides/sub-agent-surface.md:9, docs-site/src/content/docs/ko/guides/sub-agent-surface.md:9, and docs-site/src/content/docs/ru/guides/sub-agent-surface.md:9 still describe the old “task text can be lost” behavior. Update them to match the English/zh-cn text: direct non-native routes now fail with unreadable_encrypted_agent_task, and combos prefer a decrypt-capable native ChatGPT target.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs-site/src/content/docs/guides/sub-agent-surface.md` at line 9,
Synchronize the translated sub-agent surface documentation in the Japanese,
Korean, and Russian guides with the current English/zh-cn behavior. Replace the
outdated “task text can be lost” description with the
`unreadable_encrypted_agent_task` failure for direct native-to-non-native
routes, and document that combos prefer a decrypt-capable native ChatGPT target.

Source: Path instructions

@lidge-jun
lidge-jun merged commit fd7e97e into lidge-jun:dev Jul 24, 2026
16 of 17 checks passed
lidge-jun added a commit that referenced this pull request Jul 24, 2026
lidge-jun added a commit that referenced this pull request Jul 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants