fix: Tauri runtime guard + market-script sha256 verification (+ architecture notes)#603
Open
keevingfu wants to merge 6 commits into
Open
fix: Tauri runtime guard + market-script sha256 verification (+ architecture notes)#603keevingfu wants to merge 6 commits into
keevingfu wants to merge 6 commits into
Conversation
Backend commands are reached through a single `call`/`invoke` path. When the UI runs outside the Tauri webview (browser, `tauri dev` opened directly, or a devtools/automation context), `window.__TAURI_INTERNALS__` is undefined and `@tauri-apps/api` throws "Cannot read properties of undefined (reading 'invoke')". This surfaced as "Restart Codex++" failing, but affects every command. Guard `call`/`logDiagnostic` with a runtime check that rejects with a clear, actionable message instead of the opaque TypeError. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Source-read notes covering the core mechanisms: CDP injection, the Runtime-Binding bridge, React hooking in the injected script, the Responses<->Chat protocol proxy (incl. apply_patch codec), the macOS launcher, GitHub-release auto-update, Zed Remote open, and upstream worktree creation. Each section carries file:line references. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Source-read notes for the relay-config writer (relay_config.rs + settings.rs): the mode × protocol axes, how Official/MixedApi/PureApi map onto auth.json vs config.toml, the four-step profile-switch pipeline (filter common -> complete provider -> merge+limits -> mode-specific auth), shared common-config, atomic write+backup+validate, backfill/clear, ChatGPT JWT account label, and the Tauri-command (not bridge) entry point. Verified by running the relay_config suite: 67 passed. Also marks ch.9 done in the dev log; remaining modules deferred to ch.10+. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Source-read notes for the two background-consistency mechanisms: provider_sync (codex-plus-data) migrates session-history visibility across a provider switch by rewriting the model_provider tag in three sources (rollout JSONL first line, state_5.sqlite threads index, global-state workspace roots), preserving mtime, dir-locking against concurrent runs, backing up before changes, rolling back on failure, skipping OS-locked files, and warning that synced-but-encrypted history may not resume; and watcher (codex-plus-core) keeps the launcher/injection alive via CDP liveness probe, on-demand stale-launcher recovery with ancestor-chain self-protection, and Windows auto-start install. Honestly notes the three pacing constants have no in-tree polling loop and recovery is on-demand (main.rs:64), not a 3s daemon. Verified by running both suites: provider_sync 7 passed, watcher 9 passed. Also marks ch.10 done in the dev log; user_scripts/script_market -> ch.11+. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Source-read notes for user-authored / market-installed enhancement JS: user_scripts (builtin+user two-source scan, global + per-script toggles behind a Mutex+atomic_write, build_enabled_bundle wrapping each script in an isolated try/catch IIFE, injected both via addScriptToNewDocument at launch and via live Runtime.evaluate on /user-scripts/reload), and script_market (GitHub-raw index.json manifest with strict per-entry filtering, download + atomic install + recorded metadata). Records an honest finding: the sha256 field is parsed and stored but never verified on install (no Sha256/sha2 anywhere; the behavior is pinned by install_market_script_ignores_checksum_mismatch...). Flagged as a future hardening point. Verified by running the bridge_routes suite: 20 passed. Also marks ch.11 done in the dev log; architecture notes now cover all major modules. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Market scripts are JS injected into the Codex page, so their integrity is security-relevant. The manifest already carried a per-script sha256, but install_market_script_content wrote the downloaded bytes without checking it (the old behavior was even pinned by a test that ignored mismatches). Add verify_script_checksum: before writing, hash the downloaded content and compare (case-insensitive hex) against the manifest sha256. On mismatch, abort the install with a clear error — no file written, no install recorded, any existing version left intact. An empty sha256 skips the check so hash-less legacy manifests still install. Pull in sha2 + hex (both already resolved in Cargo.lock). Rewrite the ignore-mismatch test into reject-mismatch-and-keep-existing, and add accept-matching + skip-when-empty. bridge_routes 20 -> 22 passed. Sync architecture-notes ch.11.6 to describe the now-verified behavior. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
keevingfu
pushed a commit
to keevingfu/CodexPlusPlus
that referenced
this pull request
Jun 4, 2026
Running development worklog distinct from the release-facing CHANGELOG: records the 2026-06-03 source walkthrough, the manager invoke runtime-guard fix, branch/PR status (BigPizzaV3#603, pending maintainer CI approval), and the next-step plan. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
c6d88bd to
c097924
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
This PR bundles three related pieces of work from a source walkthrough of the codebase. They are split into self-contained commits, so it reads cleanly commit-by-commit:
invokein the manager.sha256before installing it.docs/architecture-notes.md, 11 chapters withfile:linereferences).If a maintainer would prefer the docs and/or the hardening split into separate PRs, happy to do that — just say the word.
1. Fix: guard Tauri runtime before invoke (
923188b)Backend commands in the manager are all reached through one
call/invokepath. When the UI runs outside the Tauri webview (a browser,tauri devopened directly, or a devtools/automation context),window.__TAURI_INTERNALS__isundefined, so@tauri-apps/api'sinvokethrows:This was reported as "Restart Codex++" failing, but it affects every command — restart just happened to be the one clicked. The backend command (
restart_codex_plus) is correctly registered and is not at fault.Change: add a
tauriRuntimeAvailable()runtime check; guardcallandlogDiagnosticso a missing runtime rejects with a clear, actionable message instead of the opaque TypeError (andlogDiagnosticbecomes a no-op so it can't re-trigger the same error). The popup now reads "Tauri 运行时不可用:请在已安装的「Codex++ 管理工具」窗口中操作…".2. Hardening: verify market-script sha256 before install (
c097924)Market scripts are JS that get injected into the Codex page, so their integrity is security-relevant. The market manifest already carried a per-script
sha256, butinstall_market_script_contentwrote the downloaded bytes without checking it (the prior behavior was even pinned by a test that ignored mismatches).Change: add
verify_script_checksum— before writing, hash the downloaded content and compare (case-insensitive hex) against the manifestsha256. On mismatch the install aborts with a clear error: no file written, no install recorded, any existing version left intact. An emptysha256skips the check, so hash-less legacy manifests still install. Pulls insha2+hex(both already resolved inCargo.lock).3. Docs: architecture walkthrough notes (
74de9ca,1681ffc,baffc04,db1f5c3)docs/architecture-notes.md— a new-contributor map of the core mechanisms, each section carryingfile:linereferences:1–8. CDP injection · the Runtime-Binding bridge · React hooking in the injected script · the Responses⇄Chat protocol proxy (incl.
apply_patchcodec) · the macOS launcher · GitHub-release auto-update · Zed Remote open · upstream worktree creation.9. Relay config & profile switching (mode × protocol, the three auth/config layouts).
10. Background consistency —
provider_sync(history visibility across a provider switch) +watcher(keep-alive / stale recovery).11. User scripts & the script market (which is where the §2 hardening was found).
Testing
npm run check(tsc --noEmit) passes.cargo check -p codex-plus-core -p codex-plus-launcher -p codex-plus-datapasses; no new warnings.bridge_routes22 passed (incl. the new sha256 reject/accept/skip-when-empty cases)protocol_proxy35 ·relay_config67 ·provider_sync7 ·watcher9🤖 Generated with Claude Code