Skip to content

feat(codebuddy): integrate capture-only tools with private prompt staging - #5582

Closed
luvs01 wants to merge 21 commits into
stack/c-sec-adapterfrom
stack/codebuddy-capture-boundaries
Closed

luvs01 wants to merge 21 commits into
stack/c-sec-adapterfrom
stack/codebuddy-capture-boundaries

Conversation

@luvs01

@luvs01 luvs01 commented Sep 22, 2026

Copy link
Copy Markdown
Collaborator

Summary

Integrate #5148's capture-only CodeBuddy tool bridge with the private prompt staging already provided by #5517. Requests with a tool catalog can return typed tool-call intents to the client, which retains approval, sandboxing and execution. This proposal is based on #5517 so it does not duplicate the lower security stack in its review diff.

  • Validate the catalog and advertise only its exact allowed tools through an isolated MCP server. Calls are captured without executing them; reject pre-init, undeclared, excessive or incomplete calls and preserve the required-tool failure contract.
  • Preserve the source's usage snapshots, early-result handling, stdin-EOF cleanup, malformed streamed-argument suppression and closed history-envelope repair. All eleven source contributions, including review follow-ups, are carried with original attribution.
  • Put client system/developer text and the bridge directive in the existing private prompt file. Keep exclusive creation, restricted permissions, sanitized staging errors, failure-before-spawn and owned cleanup. The prompt itself does not enter argv.
  • Keep the scaffold backstop, make its scanning linear and preserve original offsets with ASCII case folding; large-input and Unicode regressions accompany this change.
  • Correct the MCP test's unknown-tool rejection assertion by awaiting the actual SDK rejection before asserting its type/message. The real SDK/stdio exchange, known-tool non-execution, abort and EOF checks remain intact.
  • Return a fixed tool_bridge_setup_failed message when the private bridge files cannot be staged, keeping the failure status and cleanup while preventing raw filesystem errors from reaching callers. Two regressions cover catalog/config write failures, zero child spawn and removal of both temporary directories.

The original #5148 remains open under its author's control. The separate model-roster proposal #5147 is not included. Design context and original author discussion: #5146.

Verification

  • Current head: 3061ef9cbe4764f937a27db7368f3c33782674f3. This follow-up changes only documentation and the specific test consumers listed below; production source is byte-identical to the preceding published head b3aaf0ee0c2b1cc739b582d5f19bc2ba395440f6.
  • Hosted CI exposed structure/runtime.md growing to 602 lines when the branch was combined with newer dev. Two overlapping Remote Workspace descriptions were consolidated without losing their contracts or links. The same patch was verified against both exact failing merge trees (602 to 600) and dev (600 to 598), without raising the 600-line budget. Final combined structure checks passed.
  • Hosted CLI/status and local-management failures were consumers still expecting unbounded health-version strings. The middle-layer fixtures now retain valid semver identity values, project invalid/null/control/overlong inputs to unknown, and verify that raw values are not reflected in JSON or human output. The production security filter is unchanged. Original exact two-file run: 70 passed / 3 failed; corrected run: 76 passed / 0 failed / 385 assertions / 77.72 seconds, pinned Bun 1.4.0. Final fixture bytes match the tested f9ae99bf3579ae24f5bd2c0fa160a54d05cdf2ee commit.
  • Devin discovery now consumes one OAuth snapshot carrying both token and account host; the fixture is aligned to that existing contract. It preserves measured modalities, sidecar rules, tenant-host/account switching, real protobuf/cache parsing and network-zero assertions. Original 2 passed / 6 failed; final 8 passed / 0 failed / 24 assertions / 2.16 seconds, pinned Bun 1.4.0. Final fixture bytes match tested b6cb8a426decf5ff0baa0b65381631d786177dba.
  • Each corrected C2 layer passed typecheck, structure, privacy and file-size checks. These are distinct runs and are not added together. Earlier interrupted whole-auth/four-file runs remain incomplete; current-head hosted results are required before readiness.
  • All 23 CodeBuddy contribution files remain byte-identical to tested b3aaf0ee0c2b1cc739b582d5f19bc2ba395440f6: adapter / tool-bridge-turn / MCP / protocol suites 96 passed / 0 failed / 268 assertions / 5.20 seconds, pinned Bun 1.4.0, with type/structure/privacy/size checks passed. The setup-error negative control failed before its fixed-message correction. The earlier MCP matcher stall and corrected direct-settlement assertion are retained as separate evidence. Live subscription acceptance, built-in prompt replacement semantics and provider AUP/security review are still unresolved.
  • Full-suite/cross-platform completion, exact updated-head hosted CI and independent security review remain incomplete. No test timeout or safety boundary was weakened. This PR stays draft.

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed.
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults.

Co-authored-by: mdwsk88 924038395@qq.com

mdwsk88 and others added 20 commits September 23, 2026 00:54
…nly MCP bridge

Port the tool-bridge design from the pre-coding-agent implementation onto the
shared runTurn framework. When a request declares tools, the adapter builds a
validated catalog (bounded count, names, descriptions, schemas), the turn
writes it plus an MCP config into a private temp dir, and the CLI is launched
with --mcp-config and exact --allowedTools alongside the existing --tools
""/--strict-mcp-config posture. The capture-only server advertises schemas
over ListTools and never answers CallTool; the turn ends at message_stop,
terminates the process tree, and emits the captured tool_use blocks as
tool_call events with request wire names. The client keeps approval,
sandboxing, and execution; tool results continue the conversation through the
existing stream-json history projection.

Fail-closed boundaries: tool-bridge init validation (the CLI must report the
capture server connected), undeclared tool names, a 16-call turn limit, and
bridge setup failures. Requests without tools keep the exact v1 text-only
arg shape.

(cherry picked from commit 6691dce)
A capture-only tool-bridge leg is terminated at message_stop while the CLI parks on the never-answering MCP server, so no result frame ever arrives and the completed response reported zero tokens. Fold message_delta and assistant usage snapshots into per-turn parse state (per-field maxima, result frames stay authoritative) and attach the folded snapshot to the synthesized done(tool_use) event.

(cherry picked from commit 01f30c8)
Port the three-turn synthetic acceptance scenario (function_call capture, continuation after tool results, exact final text) onto the current tree: the provider is seeded from the registry entry with a CODEBUDDY_LIVE_API_KEY, the region is selectable via CODEBUDDY_LIVE_REGION, the CLI installation is pinned by front-loading CODEBUDDY_LIVE_CLI_PATH on PATH and failing closed on a resolution mismatch, and each tool leg must report positive usage so the partial-usage path cannot regress silently. The harness stays opt-in (CODEBUDDY_LIVE_TEST=1), runs outside the bun test preload, keeps real HOME for the CLI, and prints only fixed-code results.

(cherry picked from commit 9e7fd58)
Describe the armed path in the provider guide: catalog and MCP config in a private temp dir, exact --allowedTools, init-handshake validation, captured function_call items with wire-name mapping, the 16-call turn cap, message_stop termination, and client-owned approval and execution. Update the registry notes that still described the provider as text-only until a bridge lands.

(cherry picked from commit 6057e3f)
Address CodeRabbit review findings on the tool bridge:

- Require every started tool call to complete before message_stop (turn.ts);
  mismatched start/stop counts fail closed with a 502 protocol_error.
- Require the [DONE] SSE terminator in the live acceptance stream validator
  before accepting a completed response (scripts/codebuddy-live-acceptance.ts).
- Document 502 tool_call_required failure behavior under tool_choice: required
  in the provider guide (docs-site).
- Add regression test cases for incomplete tool calls and truncated streams.

(cherry picked from commit 2ddf3e6)
… frame

The incomplete-call check only ran after message_stop, so a stream that delivered the terminal result frame first (or without message_stop) emitted done before the check could run: under tool_choice auto an unfinished call still succeeded, and under required only the zero-completed case was rejected. Intercept the done event from a result frame the same way the tool_call_required check does: when started calls do not equal completed calls, fail closed with the 502 protocol_error shape and add the reordered-stream regression test.

(cherry picked from commit afef809)
…esis

When every captured tool call has completed and the CLI settles with a
successful result frame before message_stop (instead of parking on the
never-answering capture server), the adapter emitted the result-derived
done(stop) immediately: terminalEmitted was set, the loop exited, and the
synthesized done(tool_use, endTurn: false) the client contract expects never
surfaced.

Defer that terminal event instead: message_stop synthesis emits the
tool_use completion with the deferred result frame's usage (authoritative
vendor accounting) folded in, and a stream that ends without message_stop
fails closed with a 502 protocol_error. Regression coverage added for both
paths. Also rebased onto current dev, resolving the tool-bridge turn.ts
conflicts by combining dev's Windows taskkill tree termination with the
stdin-EOF reap path.

(cherry picked from commit 907b6cd)
The tool_call_start handler counted and forwarded tool lifecycle events
before initValidated was set. A stream could emit a complete tool call,
then a valid system/init, then message_stop: the late init flipped the
flag, the delayed message_stop check passed, and the adapter accepted a
turn whose tool events surfaced from an unvalidated bridge.

Require initValidated before the first tool call: a tool_call_start on an
unvalidated bridge fails closed immediately with the established
tool_bridge_init_missing error, and no tool lifecycle event reaches the
client. Regression coverage added for the tool-call-before-init ordering.

(cherry picked from commit 9671f00)
…calls

Keep cache-creation-only usage snapshots instead of collapsing them to undefined (a capture-only tool leg ends at message_stop with no result frame, so that snapshot is the only accounting the turn sees), and refuse a tool call that arrives before the bridge init handshake at arrival time so a later init frame cannot retroactively legitimize it.

(cherry picked from commit 8028b60)
… history envelopes

A coding-agent stream that loses the leading brace-quote of a tool-call arguments JSON can never assemble into parseable JSON. Hold those fragments instead of streaming them, so the failed item never publishes bytes the client would retain and replay as poisoned history; at completion the existing fail-closed still turns the turn into a clean 502. For history already carrying the corruption (observed live 260921 as arguments 'code":"...'), parseRequest now repairs the closed object envelope when the restored text parses, so the model sees the real call instead of a tolerated {} forever.

(cherry picked from commit 4701f6e)
Unicode lowercasing can expand a code point (e.g. İ -> i+combining dot), which shifted loweredText positions away from text offsets and let a calls+invoke scaffold slip through unflagged. Compare markers with ASCII-only folding so indices stay aligned, and replace the wall-clock perf assertion with a scaled-input check plus an expansion regression test.

Co-Authored-By: Epinephrine <luvs01@hanmail.net>
(cherry picked from commit 425764f)
Carries the mcp-server.ts EOF exit and its regression test from upstream
review commit a1fd16a that the earlier conflicted pick dropped: the
pinned MCP SDK (1.30.0) does not detect stdin EOF, so without the
explicit end/close handlers the capture server could outlive the
terminated CLI as an orphaned bun process.

Co-authored-by: mdwsk88 <924038395@qq.com>
…est import

Two hunks the conflicted pick dropped: assertReportedUsage now requires
both token directions (a single-field check passed when the synthesized
tool leg reported zero input tokens), and the tool-bridge test imports
types from the correct ../../src path.

Co-authored-by: mdwsk88 <924038395@qq.com>
Carries the remaining assertion from upstream review commit a1fd16a:
message_start.message.usage feeds partialUsage so a capture-only tool
leg terminated at message_stop still reports input tokens.

Co-authored-by: mdwsk88 <924038395@qq.com>
Restore the adapter contract comment from source review commit a1fd16a after the C2 prompt-file adaptation. The runtime already advertises the request catalog through the capture-only bridge; it does not execute those tools.

Co-authored-by: mdwsk88 <924038395@qq.com>
Keep the failure code and cleanup contract while excluding filesystem error text from client events. A scoped write seam exercises catalog and MCP config failures after real prompt staging, proving no CLI spawn and removal of both owned directories.
@coderabbitai

coderabbitai Bot commented Sep 22, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@luvs01
luvs01 added this pull request to stack #5518 September 22, 2026 18:59
@github-actions

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

@github-actions github-actions Bot added the enhancement New feature or request label Sep 22, 2026
@lidge-jun

Copy link
Copy Markdown
Owner

리뷰 · 우선순위 64 / 80

이 PR은 CodeBuddy가 도구를 직접 실행하지 않게 하면서, 클라이언트가 보낸 도구 목록만 “호출하고 싶다”는 뜻으로 받아 적게 만듭니다. 원래 #5148에 있던 캡처 전용 MCP 다리를, #5517이 이미 넣은 개인 프롬프트 임시 파일 방식 위에 얹은 통합안입니다. 요청에 도구가 있으면 카탈로그를 검사하고, 임시 폴더에 목록과 MCP 설정을 쓰며, 실행하지 않는 MCP 서버만 붙입니다. 서버는 목록만 알려 주고 CallTool에는 답을 하지 않습니다. 부모는 message_stop을 보면 프로세스를 끊고, 잡아 둔 호출을 원래 요청 이름으로 바꿔 클라이언트에 넘깁니다. 승인·샌드박스·실행은 계속 클라이언트 몫입니다. 도구가 없는 요청은 예전처럼 글만 오갑니다. 프롬프트와 다리 지시문은 argv에 넣지 않고 0600 임시 파일로만 넘깁니다. 스테이징이 깨지면 고정 문구 tool_bridge_setup_failed / system_prompt_staging_failed만 내고, 파일 시스템 에러 문구는 밖으로 안 보냅니다. 초기화 전 호출, 목록 밖 이름, 한 턴 16개 초과, 필수 도구를 안 부른 경우, 인자 JSON이 깨진 스트림·히스토리도 막거나 고칩니다. 스캐폴드 검사는 ASCII만 접어 오프셋이 안 밀리게 했습니다. 베이스는 dev가 아니라 stack/c-sec-adapter이고 드래프트입니다. 원본 #5148은 아직 dev에 열려 있습니다. 작성자가 핀 Bun으로 돌린 CodeBuddy 관련 테스트는 통과했다고 적었지만, 이 헤드의 호스트 CI test 2/4·test 3/4는 빨간 상태입니다(실패는 status version skew, Devin 카탈로그 쪽이라 이 diff의 CodeBuddy 파일과는 멀어 보입니다). 인증 CLI 라이브 수락은 이 통합 작업에서 안 돌렸다고 본문에 적혀 있습니다.

라인 - src/adapters/coding-agent/turn.ts의 카탈로그·mcp.json writeFilemode: 0o600만 있고 flag: "wx"가 없습니다. 같은 PR 스택의 src/adapters/codebuddy/adapter.ts 프롬프트 스테이징은 flag: "wx"를 씁니다. 임시 디렉터리는 mkdtemp라 실사용에서는 거의 겹치지 않지만, “전용 생성” 경계가 프롬프트와 다리 파일에서 다릅니다.

라인 - src/adapters/coding-agent/turn.tsrequireToolCall 실패 메시지 — 공유 runCodingAgentTurn 안에 "CodeBuddy finished without calling the required tool."가 박혀 있습니다. 지금은 CodeBuddy만 다리를 쓰지만, 다른 coding-agent 가족이 같은 입력을 쓰면 라벨이 틀립니다.

라인 - PR 관계 — #5148(원본, dev, 비드래프트)과 이 #5582(스택 위 통합, 드래프트)가 같은 캡처 다리 주제로 같이 열려 있습니다. #5147 로스터 PR은 본문대로 빠져 있어 범위는 겹치지 않습니다.

라인 - 호스트 CI — test 2/4status version skew projection(proxyVersion이 null), test 3/4devin advertised catalog input modalities가 실패합니다. 이 PR이 고친 CodeBuddy·bridge 파일과 직접 연결되진 않아 보이지만, 스택 헤드 기준으로는 CI가 초록이 아닙니다. 작성자 로컬 핀 테스트와 호스트 결과가 어긋납니다.

라인 - adapter.ts--system-prompt-file — #5517에서 이어진 교체(기본 프롬프트를 통째로 바꿈) 의미는 그대로입니다. 벤더 기본 안전·도구 문구가 빠질 수 있다는 점은 이 통합 PR에도 남아 있습니다.

메인테이너의 판단이 필요한 지점

--system-prompt-file로 기본 시스템 프롬프트를 교체해도 되는지(지원 CLI에서 플래그가 있는지, 교체로 빠지는 기본 지침이 없는지). 부모 #5517 스택과 #5148 원본 중 무엇을 닫고 어떤 순서로 dev에 올릴지. 캡처 전제(CLI가 CallTool 답 전에 message_stop을 보낸다)와 AUP·프록시 라우팅을 도구 광고 시작과 함께 허용할지. 호스트 CI 빨간 테스트가 부모 스택 잔여인지, 이 헤드에서 같이 막을지.

너의 추천

보안 방향(실행은 클라이언트, 캡처만, 임시 파일·권한·실패 문구 고정, stdin EOF로 MCP 고아 방지, 초기화 전·미선언·한도·필수 도구 fail-closed)은 유지하는 편이 좋습니다. 머지 후보로 쓰려면 (1) #5148과 역할이 겹치니 원본은 이 통합이 이긴 뒤 닫거나, 반대로 원본을 살릴 거면 이 드래프트를 닫고 (2) 카탈로그/mcp.json에도 프롬프트와 같이 flag: "wx"를 맞추고 (3) require 실패 메시지는 프로필 label을 쓰게 고치고 (4) --system-prompt-file과 라이브 CLI 한 턴은 메인테이너가 지원 바이너리로 확인한 뒤 Ready로 올리는 순서를 권합니다. types.ts/config.ts 쪼개기나 프리뷰 배포 이야기는 이 PR과 무관합니다.

이 댓글은 grok-bot이 작성했습니다

@lidge-jun

Copy link
Copy Markdown
Owner

Carried into #5610 as 699a596, a squash of this PR's own diff at head 3061ef9 on top of the #5517 carry. Authorship is kept, and the commit also credits @mdwsk88 for the #5148 bridge. Review follow-ups in #5610 (00c3dd1) make the bridge fail closed: a turn without a verified init handshake, a tool call seen only in the complete assistant message, or a pre-existing staging file now fails the turn. The follow-ups also document the history-argument repair as a provider-agnostic contract. #5148 stays open under its author. Closing as superseded by #5610. Thanks @luvs01.

@lidge-jun lidge-jun closed this Sep 22, 2026
lidge-jun added a commit that referenced this pull request Sep 23, 2026
)

* fix(service): combine startup ownership, token binding, and slot retention

Carries #5512 by @luvs01 (head a12b2ad), which
consolidates #5477, #5306 and #5357:

- bind the service API token to its owning state, canonicalize qualified-localhost
  binds, and carry WSL ownership state honestly (#5477);
- take a fresh task listing for the second startup ownership decision (#5306);
- retain workflow slots for streaming turns (#5357);
- own server-auth fixture lifetime and project a current-schema config for it.

Squashed from the PR's own diff (origin/dev...a12b2ad) onto current dev.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(server): self-heal a replaced package tree via drain-and-restart

Carries #5513 by @luvs01 (head 4d168f1), which
consolidates #5393 and its scheduler follow-up: detect a replaced installed package
tree, degrade health honestly, and drive a timer-driven, retryable drain-and-restart
whose verify step is deferred past scheduler re-entry. The guard factory lives in
src/server/index/package-tree-guard.ts.

Squashed from the PR's own diff (a12b2ad...4d168f1) onto the #5512 carry.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(security): combine install discovery, credential, and transport hardening

Carries #5515 by @luvs01 (head 843f299), which
consolidates #5359, #5285 and #5322:

- keep selected Codex installation discovery off network filesystems, probe
  oversized wrappers through a held-handle prefix read, and stop a PATH scan at a
  refused probe (#5359);
- exclude npm candidates inside the launch directory subtree (#5285);
- refuse plaintext remote hub origins, fail closed on POSIX chmod for credential
  files, and skip the frame-log write when descriptor hardening fails (#5322).

Squashed from the PR's own diff (origin/dev...843f299) onto the chain carry.
Integration: structure/runtime.md wording reflowed by two lines so the combined
service and security stacks stay within the 600-line structure budget.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(security): combine management-auth and boundary hardening

Carries #5516 by @luvs01 (head 245d542), which
consolidates #5326, #5312, #5363 and #5317:

- harden pairing redemption, agent roster intake, and SOCKS5 decoding (#5326);
- guard gh resolution, anchor the grok managed-region fences to whole lines, and
  bound provider-controlled text (#5312);
- harden management-auth admission and provenance (#5363);
- bound the /healthz version before it reaches diagnostics (#5317).

Squashed from the PR's own diff (843f299...245d542) onto the #5515 carry.
Integration: both stacks rewrote the shared server-auth test fixtures. The carry
keeps the #5512 current-schema fixture projection and config helper (including
its 4 KiB boundary case) and adds this PR's Aside sync capability assertions.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(security): combine adapter argv and upstream-body hardening

Carries #5517 by @luvs01 (head 260a87b), which
consolidates #5315 and #5336:

- stage Qoder and CodeBuddy system prompts in private files instead of
  child-process argv, with exclusive creation and owned cleanup (#5315);
- bound upstream error bodies and resolve account-scoped transports (Copilot,
  Devin) from the same OAuth snapshot as the bearer (#5336).

Squashed from the PR's own diff (245d542...260a87b) onto the #5516 carry.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* feat(codebuddy): integrate capture-only tools with private prompt staging

Carries #5582 by @luvs01 (head 3061ef9), which
integrates the capture-only CodeBuddy tool bridge from #5148 by @mdwsk88 with the
private prompt staging from #5517. Requests with a tool catalog advertise only the
allowed tools through an isolated MCP server that captures calls without executing
them; the client keeps approval, sandboxing and execution. Pre-init, undeclared,
excessive or incomplete calls are rejected, streamed malformed tool arguments are
suppressed, bridge staging failures return a fixed message, and an opt-in live
acceptance harness is included. Design context: #5146.

Squashed from the PR's own diff (260a87b...3061ef9) onto the #5517 carry.

Co-authored-by: mdwsk88 <924038395@qq.com>

* fix(client): bound total hub catalog response lifetime

Carries #5252 by @luvs01 (head 779ef91): give the
hub catalog body read an overall deadline (24x the inactivity window, capped at
120 s) on top of the inactivity window, and release refused, HTTP-error and 304
bodies without awaiting their cancellation.

Squashed from the PR's own diff (origin/dev...779ef91).

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(grok): reserve model aliases only when the written config stays valid

Reimplements #5281 by @luvs01. A user sub-table such as [model.ocx-mine.extra]
only creates an implicit parent, so it no longer forces the generated table to a
suffixed alias. The alias choice is now checked against the bytes actually
written: the unsuffixed alias is used only when the final config (after
model-reference rewriting) parses; otherwise the conservative choice that also
reserves deeper headers is used, and a valid user file for which neither choice
parses is refused without writing. Malformed user TOML keeps the previous
conservative reservation.

The original change reserved only exact two-segment headers, which could emit a
duplicate [model.x] table when the user defines model.x through dotted keys.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(codex-auth): scope Codex OAuth cancellation to the originating flow

Reimplements #4923 by @luvs01 on the current login-state layout (in-flight
controllers moved to src/oauth/login-flow-state.ts in #5220). Cancelling a Codex
login was keyed only by provider, so a stale modal posting an old flowId could
abort a newer attempt, and a cancel without a flowId expired every pending flow.

- Each in-flight controller records the flowId that started it; a cancel whose
  flowId does not match the active attempt is refused before anything aborts.
- POST /api/codex-auth/login/cancel requires a non-empty flowId, rejects unknown
  or non-pending flows with 400 without touching any row, and expires only that
  flow. Provider-wide cancellation through /api/oauth/login/cancel is unchanged.
- ocx account cancel requires --flow for Codex providers and sends no request
  without it.

The dashboard's 409 recovery keeps its code; its ownerless cancel is now refused,
so it ends in the existing "already in progress" message instead of superseding a
flow it does not own.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(socks5): bound compressed event streams by expansion, not total size

Review follow-up to the #5516 carry. The 32 MiB decoded-body cap applied to every
gzip/deflate response, so a long, normally compressed SSE stream through the
SOCKS5 tunnel was cut once its cumulative output crossed the cap. Buffered
responses keep the absolute cap; event streams may continue while decoded bytes
stay within the greater of 32 MiB or 128x the coded bytes consumed, which still
stops high-ratio bombs.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(codex): keep scanning PATH past a missing Windows candidate

Review follow-up to the #5515 carry. The held-handle reader reported a missing
file or directory as open-refused, so the default existence probe stopped the
PATH scan at the first absent PATHEXT candidate (for example codex.com) before it
reached an installed codex.cmd. NtCreateFile's object-name-not-found and
object-path-not-found statuses now map to a distinct not-found result that lets
the scan continue; every other failure still refuses.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(server): require Windows ACL hardening before a frame-log append

Review follow-up to the #5515 carry. On Windows the frame log ignored a failed
permission change and appended anyway. Each append now hardens the target with
the required Windows ACL helper and checks that the path still names the opened
file before writing; any failure writes nothing.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(devin): bind catalog authority to the tenant destination

Review follow-up to the #5517 carry.

- The observe-only OAuth snapshot applied the Copilot-validated apiBaseUrl to
  every provider, so a crafted Devin credential could carry a Copilot host that
  the snapshot claimed as its own. The overlay now applies only to github-copilot.
- Devin's live roster, stale fallback and cooldown were keyed by the token alone
  while discovery also depends on the validated tenant URL. The catalog authority
  and the matching routing-cache resolver now fingerprint the token together with
  the validated destination URL.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(codebuddy): fail closed on unverified bridge turns and staging collisions

Review follow-up to the #5582 carry.

- With the capture-only tool bridge armed, a successful terminal event is no
  longer accepted unless the CLI's system/init frame confirmed the bridge server;
  a turn that ends without it fails with tool_bridge_init_missing.
- A tool_use block that arrives only in the complete assistant message, without
  the partial tool events the bridge captures, now fails the turn instead of
  being dropped silently; partial captures are deduplicated by id.
- The catalog and MCP config staging files are created exclusively (wx, 0600),
  like the prompt file, so a pre-existing file fails before spawn.
- The history-argument repair for a missing JSON object prefix is documented and
  tested as a provider-agnostic contract; other malformed strings keep {}.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
Co-authored-by: mdwsk88 <924038395@qq.com>

* fix(service): keep service-command ownership bound to the recorded home

Review follow-up to the #5512 carry. On WSL with CODEX_HOME unset, the carried
allowance treated a legacy Linux ~/.codex install record as owned when discovery
now selects the Windows profile, so service stop could stop the Linux-home
service and then restore native Codex in the Windows home, and repair could
rewrite the recorded home. Service commands again require the exact recorded
home and name it in the refusal; the unattended startup inspector reaches the
same foreign verdict.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(server): veto a package-tree restart when its server stops or loses ownership

Review follow-up to the #5513 carry.

- A package-tree restart accepted by the guard stayed scheduled after an explicit
  server.stop(), so the drain-and-respawn could reopen a server the caller had
  stopped. The caller that accepted a pending restart now receives a veto, and
  the guard uses it on dispose.
- When running as a supervised service child, the automatic path checks service
  home ownership when accepting and again before the handoff; a mismatch keeps
  the 503 fence and skips the restart.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(security): resolve gh from fixed paths and look up pairing grants by digest

Review follow-ups to the #5516 carry.

- On Windows the automatically polled star-status route derived gh.exe roots from
  ProgramFiles and LOCALAPPDATA, so a process environment could select any
  absolute directory. Windows candidates are now the fixed system install paths,
  and the child PATH is only the resolved executable's directory. Other installs
  report gh as unavailable, which only hides the sidebar star state.
- Pairing redemption looked each guess up by scanning every live grant; the map
  is keyed by the grant digest, so the lookup is now a direct get. A valid grant
  still redeems behind a throttled source.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* test(server): cover the one-shot Aside sync capability end to end

Review follow-up to the #5516 carry, which added a one-shot, HMAC-bound
capability for the default ocx sync path without exercising it. A real listener
now proves single use, refusal on replay, wrong path, query, method, pid or port,
expiry and a bad MAC, and that the CLI default path performs the attestation and
a bodyless POST (through a narrow transport seam).

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* test: register the review follow-up test files in the layout maps

Adds the three new test files from the L4 review follow-ups to both
scripts/test-layout/layout.json and tests/fixtures/test-layout-expected.json.

* test(grok): pin re-injection and strip for a nested user model table

Review follow-up to the #5281 reimplementation: two injections are byte
identical, every intermediate file parses, and strip restores the exact user
content.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(server): harden a Windows frame log once per file identity

Re-review follow-up: requiring Windows ACL hardening on every append spawned
icacls for every relayed frame and could stall the realtime relay. The hardened
file identity (device and inode) is now remembered for the log path; an
unchanged file skips the respawn, and a replaced file at the same path is
hardened again before any write.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* docs(structure): describe the package-tree restart veto and ownership recheck

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(server): stop an automatic restart from handing off after an explicit shutdown

Security review follow-up to the #5513 carry. Once an automatic package-tree
restart entered its drain, an operator shutdown (signal or management stop)
could still be followed by the restart handoff, because the drain cannot tell
its own listener stop from an independent one. Explicit shutdown paths now mark
the process, and an admission-bound restart checks that mark before every
handoff step. Manually requested restarts keep their behavior.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(server): mark a management stop before its asynchronous teardown

Security re-review follow-up: the management stop route marked the explicit
shutdown only after awaiting the shared teardown, so an automatic restart
draining concurrently could reach its handoff in that window. The mark now
precedes the first await after the stop is accepted.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* test(server): allow post-lookup pruning in the pairing digest regression

The digest-lookup regression trapped every iteration of the grant map, so a
valid redemption failed once session minting pruned expired grants after the
lookup (hosted CI test 4/4). The trap now fails only on a scan that precedes the
digest lookup, which is the regression it guards.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix: repair standalone bridge and restart ownership

Use the compiled CLI as the capture-only MCP entrypoint, release automatic restart fences on veto, align Devin discovery, and tighten Windows and local transport handling. Apply the documented Qoder prompt environment for both regions and update focused regressions and operator docs.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

Co-authored-by: mdwsk88 <924038395@qq.com>

---------

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
Co-authored-by: mdwsk88 <924038395@qq.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants