Skip to content

security(desktop): bump tauri-plugin-updater to 2.14.1 for zip CVE-2026-115905 - #790

Closed
luvs01 wants to merge 18 commits into
devfrom
devin/security-fix-zip
Closed

luvs01 wants to merge 18 commits into
devfrom
devin/security-fix-zip

Conversation

@luvs01

@luvs01 luvs01 commented Oct 29, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • Update the Windows updater dependency chain to tauri-plugin-updater =2.14.1, tauri =2.12.5, tauri-build =2.7.4, and tauri-utils =2.10.2. The lockfile resolves the original zip advisory with zip 9.1.3.
  • Declare Rust 1.90, matching those pinned crates, and update the desktop structure document. The previous Rust 1.88 declaration could not build the selected dependencies.
  • Integrate upstream dev at c618c77b1e81aa8952422e2d3657439ed6d5f8fe, retaining patched rustls 0.23.46 already landed through upstream build(deps): bump rustls from 0.23.45 to 0.23.46 in /desktop/src-tauri lidge-jun/opencodex#7942. The original dependency update is preserved; no dependency was downgraded to reduce the diff. The delta against the recorded dev snapshot 63de499e is three files.

The source branch is also reviewed in upstream #8039. The source before-release review r4408854656 remains open for signed Windows updater acceptance.

Verification

Current source head: 9ccd9b313b6a5d6650e71ede2336cd1a329f3333.

  • Windows x64, exact isolated Rust 1.90.0: cargo check --manifest-path desktop/src-tauri/Cargo.toml --locked passed with the actual prepared Windows sidecar, keyring and GUI resources.
  • Native unit coverage: updater 16, CLI command construction 8, autostart command construction 3, plus registry recovery 1 and private ACL 5 under Windows BasicUser: 33 distinct passing tests. The elevated-token registry attempt was refused by the existing owner guard because its default owner was Administrators; the same test binary passed as BasicUser. The guard and ACL policy were not weakened.
  • Official unsigned local build, bun desktop/scripts/build-local.ts -- -- --locked, produced both Windows release bundles below with Rust 1.90. The committed updater public key, endpoint and createUpdaterArtifacts: true remain unchanged; the official helper disables updater artifacts for this local invocation only.
  • bun check --no-script --noEmit: 2,253 files; structure, privacy and file-size gates passed. Source and lockfile digests remained unchanged through the native build.
  • Exact-head Cross-platform CI: 41156255102 passed on this exact head (14 successful jobs / 10 policy skips). Policy skips do not establish native Windows/macOS acceptance. Catalog async contracts 41156254959 passed. A full local proxy suite was not repeated for this dependency/MSRV change; focused native validation and current CI cover the changed path.
Local artifact Bytes SHA-256
OpenCodex_2.95.0_x64_en-US.msi 67,125,248 9525687bd086c8a65dbac73d3795b2fe29ac4b50aed22f64a790fcd11fffc9ca
OpenCodex_2.95.0_x64-setup.exe 50,009,619 461dccc77d4288d1710b4757189849a0c039a5311da1aa4389adf5c91508f779

Validation limits: build output passed, but the runner required controlled cleanup and its final receipt is not a clean native-job pass. These are unsigned local bundles, not a signed updater archive. No installed app was replaced or launched. Signed update discovery, extraction, installation and restart still require an approved signed test artifact/feed and an isolated Windows user or VM before release. Maintainer/security acceptance and Dependabot alert closure are separate.

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. Static scope/config review is complete; independent security/maintainer acceptance remains separate.
  • Signed Windows updater installation and restart acceptance before release.
  • Confirm the relevant Dependabot alerts close after the change lands. chore(deps): bump rustls from 0.23.45 to 0.23.46 in /desktop/src-tauri in the cargo group across 1 directory #789 was already closed by Dependabot; this work does not close it again.

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

Summary by CodeRabbit

  • Chores
    • Updated the desktop app’s underlying components. No user-facing features or behavior changes are included in this update.

…26-115905

zip 4.6.1 (critical Zip Cloaking / arbitrary file overwrite) reached the
Windows update-extraction path via tauri-plugin-updater 2.9.0, which
requires zip ^4. The fix needs updater >=2.14.1 (zip ^9) and tauri ^2.12,
so the exact-pin chain moves together: tauri 2.12.5, tauri-build 2.7.4,
tauri-utils 2.10.2. Lockfile regenerated; zip resolves to 9.1.3 and the
refresh also picks up rustls 0.23.46 (dependabot alerts #5-#8).

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Important

Review skipped

We couldn't safely recover the incremental review. No full review was started, and the last reviewed checkpoint was preserved. Retry later, or explicitly request a full review by commenting @coderabbitai full review.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Trigger review
Walkthrough

The Tauri Cargo manifest updates the pinned versions of tauri-build, tauri, tauri-utils, and tauri-plugin-updater. Other listed plugin versions and the tauri feature selection remain unchanged.

Changes: Tauri dependency updates

Layer / File(s) Summary
Update pinned Tauri versions
desktop/src-tauri/Cargo.toml
Updates tauri-build from 2.6.3 to 2.7.4, tauri from 2.11.6 to 2.12.5, tauri-utils from 2.9.3 to 2.10.2, and tauri-plugin-updater from 2.9.0 to 2.14.1.

Estimated code review effort: 1 (Trivial) | ~5 minutes

Change: Other

Suggested reviewers: lidge-jun

Merge Risk: Low · previous review 2ca54

The Tauri dependency upgrade requires Rust 1.90, but the desktop package still advertises 1.88. Builds on the declared minimum toolchain will fail, while CI on stable Rust is unaffected. Bump the declared Rust version to 1.90 before or shortly after merging.

Pre-merge checks: Passed 4
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly identifies the main change: upgrading tauri-plugin-updater to version 2.14.1 to address CVE-2026-115905. It is specific, concise, and consistent with the pull request objectives.
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
Fix failing CI checks
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

CodeRabbit Verify

  • Run CodeRabbit Verify to test the changes in this pull request.

@github-actions github-actions Bot added the intake: hygiene-blocked Deterministic PR hygiene checks failed label Oct 29, 2026
@github-actions

Copy link
Copy Markdown

⚠️ Deterministic hygiene checks failed.

  • missing_coauthor_credit — This pull request says it reimplements, supersedes, carries, or rebases another author's pull request, but no Co-authored-by trailer names that author. Prose in a commit body is not read by anything; the trailer is what GitHub counts. Add it to the description or a commit, or obtain attribution-approved. Paths: #789.

@github-actions

github-actions Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

✅ READY

  • all PR quality gates passed.

Hygiene

✅ Deterministic PR hygiene checks passed.

@github-actions
github-actions Bot marked this pull request as draft October 29, 2026 05:00

@devin-ai-integration devin-ai-integration 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.

Note

Newer findings are available below. Devin Review posted a newer report on this PR, in addition to the findings presented here.

Devin Review found 1 potential issue.

Devin Review

tauri-plugin-shell = "=2.2.1"
tauri-plugin-single-instance = "=2.4.0"
tauri-plugin-updater = "=2.9.0"
tauri-plugin-updater = "=2.14.1"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔍 Windows update path is outside pull-request CI

Pull-request desktop CI runs only on Ubuntu, so it cannot exercise a Windows update with the new updater. Consider a manual Windows run on this head before release.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

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.

Added Windows-native evidence for 9ccd9b3: exact Rust 1.90.0 cargo check --locked with the real prepared sidecar/GUI, 33 distinct native unit tests (including the registry recovery and ACL cases under BasicUser), and the official unsigned local release build for both MSI and NSIS. Both bundle digests and the elevated-owner/controlled-runner-cleanup limitations are now recorded in Verification. The committed updater key, endpoint and release-signing configuration are unchanged.

This narrows the gap but does not replace the requested end-to-end updater check: no installed app was replaced or launched, and no signed updater archive was produced. Signed update discovery/extraction/installation/restart remains an explicit pre-release requirement using an approved signed test artifact/feed and an isolated Windows user or VM. I have left that acceptance unchecked rather than marking it passed from a successful bundle build.

@github-actions github-actions Bot removed the intake: hygiene-blocked Deterministic PR hygiene checks failed label Oct 29, 2026
@github-actions
github-actions Bot marked this pull request as ready for review October 29, 2026 05:01
@luvs01

luvs01 commented Oct 29, 2026 •

Copy link
Copy Markdown
Owner Author

No description provided.

coderabbitai[bot]

This comment was marked as resolved.

luvs01 commented Oct 29, 2026 •

Copy link
Copy Markdown
Owner Author

Existing-writer coordination and exact-head verification (2026-10-29)

Head rechecked: 2ca541e0a28c093cb0c11fad5b97c75f8734762d. Please keep the existing implementation owner on this branch and acknowledge the following remaining scope; this check has not started a competing implementation or a new automated writer/review session.

1. Confirmed MSRV declaration mismatch

The new MSRV finding is supported by independent read-only checks. This head still declares rust-version = "1.88", while the exact pinned/locked tauri-build 2.7.4, tauri 2.12.5, tauri-utils 2.10.2, and tauri-plugin-updater 2.14.1 require Rust 1.90. The official registry entries for tauri-build, tauri-utils, and tauri-plugin-updater, plus the tauri-v2.12.5 workspace manifest inherited by its package manifest, confirm the requirement. This is a real manifest-contract mismatch, not evidence of a failing current Linux CI job. No Rust 1.88 build was run by this verifier.

Please correct the declaration in this existing PR, check any corresponding toolchain documentation, and record the resulting exact head and locked-build result using the declared supported toolchain. Do not change PR CI policy to make the finding disappear.

2. Native Windows full build and updater acceptance

Cross-platform CI 40820871888 is now successful: 8 successful jobs / 13 policy skips. Its Linux desktop job actually ran fmt/clippy/tests, bundled-sidecar/dashboard build, AppImage/deb builds and Linux packaged-shell E2E. Service lifecycle 40820872178 also succeeded. These results do not cover the remaining Windows updater path.

The existing owner should validate the new final head in an isolated Windows environment and attach:

  1. Exact commit, Windows/Rust versions, existing build commands and artifact hashes; build the Windows sidecar ocx-x86_64-pc-windows-msvc.exe and the complete desktop package. The previously reported dependency-only cargo check, which stopped at the missing sidecar, is not a full build.
  2. Exercise the application's actual updater download/verification/extraction/installation path in disposable test directories, then start the updated app and bundled sidecar and verify their versions. Record the observed extraction destination, installation result and startup result, with sanitized logs. A direct unzip test alone does not establish updater acceptance.
  3. Verify the advisory's relevant archive handling on that same Windows path using the project's accepted isolated test setup, preserving signature checks, ownership/ACL behavior and existing security policy. Do not replace the user's live installation or relax signing, permissions or PR CI policy for the test. If that setup or permission is unavailable, report the specific blocker before proceeding.

Existing verification entry points: prepare-sidecar.ts maps --target x86_64-pc-windows-msvc to the Windows standalone build and stages both ocx-x86_64-pc-windows-msvc.exe and the keyring resource. The existing build:local wrapper can produce MSI/NSIS installable bundles, but explicitly sets createUpdaterArtifacts: false; its success alone cannot validate an updater archive. The exact application install path downloads/verifies first, awaits prepare_restart, and calls update.install(package) through the spawn coordinator. Windows hands off to the installer and may exit before that function returns. Observe the installer handoff and the newly launched app/sidecar, not just a returned success or a fresh manual installation. Confirm availability of an already authorized signed test artifact/feed; if it is unavailable, record that as a test-setup blocker instead of changing the committed updater key, endpoint or verification policy.

3. One rustls upstream route, without premature closure

Because this broader 151-package update still needs the above work, the existing upstream #7942 is now the narrow rustls-first delivery track, retargeted to dev and still Draft. lidge-jun#7942, fork #789 and this head have identical rustls 0.23.46 version/checksum/dependency entries. lidge-jun#7942's dev-history refresh and readiness/security evidence remain explicitly pending.

Keep #789/lidge-jun#7942 open until upstream acceptance establishes the replacement relationship. After the narrow fix reaches the upstream baseline, compare this PR against that baseline to remove duplicate patch scope; do not downgrade rustls to manufacture a smaller diff. This PR remains the broader updater/zip work item. Ready status is separate from the outstanding native/security/maintainer acceptance; no merge approval or closure is implied.

@github-actions github-actions Bot added the bug Something isn't working label Oct 31, 2026
luvs01 and others added 13 commits November 3, 2026 18:04
* fix(cli): attest Codex listener before token injection

* fix(cli): bind listener proof to the Codex destination

Carry the actual challenged origin through credential admission and compare it
with the final standalone or direct-client destination before loading a token.
Preserve existing launch guards and cover port, address-family and proof
snapshot behavior with the real attestation verifier and synthetic responses.

* fix(cli): keep direct-client launches on their own listener proof

A direct client's ownership proof comes from its machine listener, while
Codex dials the hub URL, so comparing the two always withheld the client
credential. Bind the proof origin to the destination only for standalone
installations; direct clients still require a proven local runtime and keep
their connection-state and loopback checks.

* fix(cli): require the client listener role for direct-client proofs

A direct client's credential could be authorized by any listener of the
same home that answered the ownership challenge. Carry the proven
listener's client role into the proof and refuse direct-client injection
without it.

* Revert the client-role requirement for direct-client proofs

The role a listener reports is not covered by the ownership proof, so
requiring it added no authenticated guarantee. Binding the role would
need a change to the attestation format shared with the desktop app.
Direct clients keep the home-ownership proof, which dev does not
require at all.

* docs(cli): state what the direct-client listener proof covers

* fix(cli): prove a localhost listener at the address it binds

A configured localhost binds 127.0.0.1, which is also what the
standalone Codex target dials; probing the raw name produced a different
origin and withheld the automatic token.

---------

Co-authored-by: JUN <jun@lidgeai.com>
* fix(kimi): report monthly Coding Plan quota

* fix(kimi): validate monthly ratios and continue envelope fallback

* fix(kimi): keep nested legacy quota windows and validate counter ranges

* fix(kimi): treat a quota counter overage as exhausted

A used count above the limit, or a negative remaining count, means the
window is used up; dropping the row would let an over-quota account look
available. Impossible counters still fall back to the ratio.

* fix(kimi): let either counter overage exhaust the quota window

A negative remaining next to a lower used count still means the window
is used up; check both overages before choosing a counter.

* fix(kimi): check quota exhaustion before rejecting counters

An exhaustion signal now wins even beside an impossible companion
counter, and a positive remainder can no longer round up to an
exhausted window.

---------

Co-authored-by: JUN <jun@lidgeai.com>
* fix(codex): keep profile keys OpenCodex does not manage

Reinjection rebuilt ~/.codex/opencodex.config.toml from the template, so an
operator's own Codex root keys (stream_idle_timeout_ms, stream_max_retries, ...)
vanished on the next start without a message.

Carry root keys this build does not own into the rebuilt profile, ahead of the
first table. Values that span several lines are copied whole, keys owned by
either profile shape (model_provider, model_catalog_json, openai_base_url) are
always rewritten, and a profile with nothing to carry keeps the generated bytes
byte for byte.

* fix(codex): carry unmanaged profile keys as source text and keep generated tables authoritative

Carried root assignments keep their original bytes, so an integer outside the JavaScript safe range in an array or inline table is no longer dropped. A carried key named like a table the generated profile writes (features, model_providers) is dropped instead of redefining that table. The injector re-reads opencodex.config.toml under the write lock and refuses retryably when it changed after the plan read it.

* docs(codex): describe which profile keys survive regeneration

* fix(codex): keep a carried assignment's trailing spaces

* test(codex): keep profile preservation tests inside their own Codex home

Install an isolated CODEX_HOME before loading the path-dependent modules
and refuse to run when the profile path is outside a test home, so a run
without the repository preload cannot remove a real profile.

* fix(codex): close multiline strings that end with extra quotes

TOML lets a multiline string close with up to two content quotes before
its delimiter. The structural scanner treated those as a new string and
swallowed the following root keys, so profile regeneration dropped them.

* fix(codex): roll back the profile only when this injection published it

A refusal before the profile publish, including the stale-profile check, restored the captured pre-image over an edit that landed after the capture. Rollback now reverts the profile only when this operation published it and the file still holds those bytes; config and journal rollback are unchanged.

* fix(codex): treat a profile removed before the plan reads it as absent

The plan checked existsSync and then read the profile, so a removal in between aborted the run with a raw ENOENT. It now reads directly, treats ENOENT as absent and rethrows other errors; the lock-time comparison still refuses retryably if the profile reappears.

* fix(codex): read the profile at lock time without an existence check

The lock-time comparison now shares the plan's reader, so a profile
removed during the read is treated as absent and the change is refused
retryably instead of escaping as ENOENT.

---------

Co-authored-by: T <t@x.io>
Co-authored-by: JUN <jun@lidgeai.com>
…ge-jun#8072)

* fix(kiro): report content-filter stops as non-retryable refusals

A tool-less turn that Kiro's safety filter refuses (CONTENT_FILTERED, e.g. the Claude BIO classifier) arrives with no content. Explicit stop reasons were only mapped in required completion mode, so a disabled-mode refusal fell through to the retryable empty-stream error and clients received a 502 overloaded_error for a verdict that repeats deterministically.

CONTENT_FILTERED and GUARDRAIL_INTERVENED now map to the non-retryable content_filter incomplete in every mode, which Messages renders as stop_reason refusal and Responses as a terminal failure. Kiro's refusal category and explanation are carried in the message.

* fix(kiro): anchor content-filter checks ahead of the completion branches

Same behavior: a validated final answer and a real tool call keep their precedence over a content-filter stop, now through an explicit guard. Placing both checks before the completion-answer branches keeps them first in order for every outcome that follows, and stops them sharing an insertion point with other changes to the same terminal sequence.

* fix(kiro): keep first-attempt progress when the retry is filtered

Review follow-up. A bounded retry that streamed text before CONTENT_FILTERED made the prior-attempt drain treat that text as superseding the first attempt's held progress, so the client lost it although neither attempt produced an accepted answer. The refusal check now runs before that drain and releases the first attempt's progress, then the retry's partial text, then the refusal. Server tests now cover partial text before a refusal on tool-less Messages (buffered and streaming) and Responses turns.

* test(kiro): cover the buffered Responses refusal and document it

Review follow-up. The tool-less refusal cases now include non-streaming /v1/responses, asserting the shared buffered contract (incomplete body, content_filter, no error) with and without partial text; both variants fail against dev's Kiro code. The providers guide describes the non-retryable refusal and what a filtered bounded retry shows.

* docs(kiro): document the functions the content-filter change touches

CodeRabbit's docstring-coverage pre-merge check (80% of touched functions with branches) reported 60%. Adds doc comments to the touched stream and event-parsing functions and to the test helpers; no behavior change.

---------

Co-authored-by: JUN <jun@lidgeai.com>
…un#8047)

* fix(command-code): reserve only live buffer growth

* test(command-code): cover shared buffer ownership and drain

---------

Co-authored-by: JUN <jun@lidgeai.com>
…e-jun#8036)

* fix(link): restore local routing when child stops

* fix(client): restore owned Link routing before listener release

* test(cli): align stop contracts with owned routing cleanup

* test(client): preserve failure exit in signal cleanup contract

* docs(link): document pending disconnect stop refusal

Add an incomplete disconnect receipt (client_disconnect_pending) to the
existing stop restoration refusal conditions in all eight lifecycle guides.
Keep the recovery-evidence guidance and the runtime behavior unchanged.

* fix(link): preserve handled-signal exit wiring

* fix(link): allow catalog sync before signal restoration

* fix(link): fence sync commits during signal shutdown

* fix(link): keep runtime publication through its record builder

* fix(link): retry transient stop-fence contention explicitly

* docs(link): define the configuration mutation lock on first use

* docs(link): keep operator recovery steps in the CLI lifecycle guide

The structure note now states only the runtime behavior; starting and
resyncing a Link Child after a signal stop is documented with the other
stop steps in the public lifecycle reference.

* test(link): use the canonical Codex home in sync-stop fixtures

Sync records the canonical catalog path while the fixture created its
native backup under the /var alias on macOS, so restoration fell back to
an empty catalog; clean up held children with SIGKILL so a failed
assertion is reported instead of hanging. Also correct the offline-sync
wording: an offline sync does reapply routing.

---------

Co-authored-by: JUN <jun@lidgeai.com>
* perf(devin): batch consumed stream chunk removal

* perf(devin): compact stream chunks without a discarded array

---------

Co-authored-by: JUN <jun@lidgeai.com>
lidge-jun#8009)

* fix(codex): hold selection ownership through dashboard feature toggles

* test(codex): cover feature invocation without injected toggle

---------

Co-authored-by: JUN <jun@lidgeai.com>
…l turn (lidge-jun#8064)

ZCode sends assistant text as the Responses message shorthand
({role, content} with no type). isAssistantTurnItem only recognized a typed
message, so the shorthand closed the assistant turn and
backfillBareToolCallTurnReasoning inserted its placeholder after the text
instead of at the head of the turn. DeepSeek's thinking mode rejects that
ordering with "The reasoning_text in the thinking mode must be passed back to
the API", and every continuation of the session fails the same way.

Normalize the item type the way the Responses parser already does, so a
shorthand with role=assistant belongs to the surrounding assistant turn. The
placeholder then precedes the whole turn, matching the typed-message shape
that already passes.

Co-authored-by: fec333 <7840187+fec123@users.noreply.github.com>
Co-authored-by: JUN <jun@lidgeai.com>
…dge-jun#8048)

* fix(responses): unwrap one extra executable freeform body wrapper

* fix(responses): stream object-leading executable bodies once they cannot be a nested wrapper

* perf(responses): resume progressive freeform decoding across deltas

Each delta decoded the whole accumulated canonical value and walked the whole decoded body again for a nested executable wrapper, so one-character deltas did quadratic work. A per-call ProgressiveFreeformInputReader now resumes where the previous delta stopped, and the nested-wrapper check is an incremental state machine that also releases a non-string nested input once no later string duplicate can follow.

---------

Co-authored-by: JUN <jun@lidgeai.com>
…jun#8070)

* fix(kiro): resubmit a finished answer on the completion retry

On a trivial request claude-sonnet-5 answers in plain text with END_TURN instead of calling the private completion tool, so the bounded retry fires. Its instruction began "Continue the existing task", which the model read as the user's next message: it called the completion tool with "there is no active task to continue", and that replaced the correct answer.

The retry instruction now states that ordinary text has not reached the user and asks for an already complete reply to be resubmitted unchanged. The empty-completion classification is unchanged.

* test(kiro): register the retry-wording test on an uncontended layout line

Other open Kiro changes register their tests on the kiro-single-final line; moving this entry to the kiro-images line keeps the two registrations from conflicting when both land.

* fix(kiro): keep a direct completion route in the retry instruction

Review follow-up. The reworded retry instruction offered only a resubmitted reply, a blocking question, or another tool call. On a reasoning-only retry there is no previous reply, so a request the model can answer directly had no completion route in the message itself. It now says: if the task is complete, call the completion tool with the final answer, submitting the previous reply unchanged when that already was the answer. Documented in the adapter reference.

* test(kiro): document the retry-wording test helpers

CodeRabbit's docstring-coverage pre-merge check counts functions this PR touches; the new test file's helpers had no doc comments.

---------

Co-authored-by: JUN <jun@lidgeai.com>
* Fix non-ASCII Codex turn metadata headers

* docs: document ASCII-safe JSON contract for rewritten turn metadata

* fix(codex): escape DEL in turn metadata header

* docs(structure): record turn metadata header escaping

* fix(codex): bound turn metadata by canonical size so re-isolation is idempotent

* fix(codex): canonicalize matching turn metadata

---------

Co-authored-by: JUN <jun@lidgeai.com>
…#8135)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

@devin-ai-integration devin-ai-integration 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.

Devin Review found 1 new potential issue.

Devin Review

Comment thread src/client/runtime.ts
Comment on lines +496 to +497
const restored = linkMode ? restoreLinkClientRouting(state.value, { syncFenced }) : null;
if (restored && !restored.success) console.error(`[client] ${restored.message}`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔍 Description understates the runtime changes

The description says this update changes no user-facing behavior, but signal shutdown now restores a Link Child's Codex routing. Reconcile the stated scope and validation with this lifecycle change.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

@luvs01

luvs01 commented Nov 3, 2026

Copy link
Copy Markdown
Owner Author

No description provided.

@luvs01 luvs01 closed this Nov 4, 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.

9 participants