Skip to content

fix(runtime): keep packaged Core and WebUI coherent across updates - #176

Open
JosephTian876 wants to merge 9 commits into
AstrBotDevs:mainfrom
JosephTian876:fix/select-coherent-packaged-resources
Open

fix(runtime): keep packaged Core and WebUI coherent across updates#176
JosephTian876 wants to merge 9 commits into
AstrBotDevs:mainfrom
JosephTian876:fix/select-coherent-packaged-resources

Conversation

@JosephTian876

Copy link
Copy Markdown

A merge-style Desktop update can leave old Dashboard files beside the new payload. An official Windows update from v4.27.0 to v4.27.5 reproduced this condition: all 244 expected new WebUI files were present with matching SHA-256 values, but 134 stale files and the old assets/version marker survived. Desktop/Core/code were 4.27.5 while the public versions API still reported WebUI v4.27.0.

This PR implements the Desktop side of a complete packaged-resource identity boundary. The companion Core change is AstrBotDevs/AstrBot#9898; complete cache-transition protection in a release requires compatible changes from both repositories.

Summary / 改动概述

  • Prepare backend and WebUI from one AstrBot checkout and validate the final bundle before packaging.
  • Write the WebUI version marker and extend runtime-manifest.json with Desktop/Core/source identity plus SHA-256 attestations for index.html and its local JavaScript/CSS entries.
  • Compile the exact final manifest SHA-256 into the executable. Release builds fail if the manifest is unavailable.
  • Treat direct resources and _up_/resources as complete candidates rather than mixing backend and WebUI leaves across roots.
  • Accept only the candidate whose manifest matches the running executable, then validate its versions, paths, marker, index, and entry digests before starting Core.
  • Verify the live /api/v1/stats/versions, /index.html, and every attested entry response before navigating to an already-running or newly started packaged backend.
  • Bound backend identity HTTP reads by header/body size and an overall socket-read deadline.
  • Navigate with a full astrbot_bundle=v1-<manifest-sha256> identity so Core #9898 can bypass and clear the previous WebView cache without clearing cookies or local storage.
  • Show fail-closed resource errors in the startup window and re-resolve resources before recovering from a failed updater installation.
  • Extend the packaged-backend smoke test to verify the versions endpoint and the exact served index/entry bytes.
  • Document the build/runtime identity contract and compatibility boundaries.

Compatibility notes:

  • Packaged resource preparation now requires Core 4.26.0 or newer because startup identity verification depends on /api/v1/stats/versions.
  • Stable Desktop builds require exact Desktop/Core/WebUI version equality. Nightly/custom prereleases may embed a different Core version, but Core and WebUI must still match.
  • Packaged mode intentionally ignores ASTRBOT_WEBUI_DIR; dev/custom launch plans and explicitly external backends remain unchanged.
  • User data is not moved, deleted, or included in the bundle identity.
  • No workflow, public API, response-schema, or IPC-schema change is included.

Verification / 验证方式

Local source gates:

Node syntax checks:                         41/41 passed
Changed/related Node tests:                 84 passed, 0 failed, 1 skipped
Backend smoke unit tests:                   35/35 passed
Prepared Core/WebUI backend smoke:          passed
cargo fmt --all -- --check:                 passed
strict Clippy with documented Windows
function-cast allowances:                   passed
cargo test --locked:                        185 passed, 1 known upstream Windows assertion failure
git diff --check:                           passed

The skipped Node case requires symlink creation on Windows.

The one Rust failure is the unchanged
backend::restart::tests::restart_strategy_delegates_to_strategy_module
assertion: it expects the non-Windows strategy even though the correct Windows
strategy is ManagedSkipGraceful. The same assertion exists on origin/main,
and the dedicated Windows strategy test passes.

A repository-wide Node run reported 141 passed, 26 failed, and 1 skipped. All
26 failures are in unchanged Windows-incompatible fixtures that assume POSIX
executables, command lookup, or path formatting. Every changed or directly
related Node suite passes.

Windows x64 NSIS/WebView2 upgrade test:

  • Installed an isolated v4.27.0 baseline and launched its packaged backend and WebView2 profile.
  • Confirmed that the old entry asset was present in both HTTP cache and code cache.
  • Invoked the v4.27.5 candidate installer against the same installation using the updater's passive arguments (/P /UPDATE /NS).
  • The merged installation contained 396 WebUI files for a 258-file current payload, leaving 138 stale extras, including the old JavaScript entry.
  • All 258 current files were present and hash-correct; the installed runtime manifest exactly matched the candidate manifest.
  • With the old WebView2 profile preserved, runtime reported Core/code/WebUI 4.27.5 and served index, JavaScript, and CSS bytes matching the manifest.
  • Navigation used the full manifest identity, and the Dashboard entry response from Core #9898 included Cache-Control: no-store and Clear-Site-Data: "cache".
  • With stale direct resources and exact current _up_/resources, runtime rejected direct and successfully selected the staged bundle.
  • With both candidates stale, runtime showed a startup error, spawned no packaged Python backend, and did not navigate to the old Dashboard.
  • A user-data sentinel remained byte-identical through the upgrade, staged fallback, and fail-closed cases.

E2E limitations:

  • The candidate was an unsigned isolated Windows x64 build, not a release-signing test.
  • It executed the real NSIS installer with the updater's passive arguments, but did not exercise the signed network manifest/download or the in-app confirmation button.
  • The candidate used the unmerged Core changes from fix(dashboard): reject stale WebUI assets in desktop-managed mode AstrBot#9898 with a test-only version sync to 4.27.5 so the stable version invariant could be exercised. That version-only test change is not part of either PR.
  • Linux, macOS, and Windows ARM installers were not exercised end to end locally; their shared build/runtime logic is covered by the source tests and repository CI.
  • These results establish no known blocker in the exercised paths; they do not claim that every possible regression is impossible.

Checklist / 检查清单

  • This change is not a breaking public API or user-data change. / 此改动不会破坏公共 API 或用户数据。
  • I have verified the change locally (and provided logs/results above). / 我已在本地验证并在上方提供结果。
  • No workflow files are changed. / 未修改工作流文件。
  • The added sha2 dependency is recorded in src-tauri/Cargo.lock. / 新增依赖已同步到锁文件。
  • This PR does not include malicious code. / 此 PR 不包含恶意代码。

@sourcery-ai sourcery-ai 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.

Sorry @JosephTian876, your pull request is larger than the review limit of 150,000 diff characters

@zouyonghe zouyonghe left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Review findings

P1: Chunked response can panic Desktop

src-tauri/src/backend/http_response.rs:99 uses chunk_size + 2 where chunk_size comes from the HTTP response. A chunk size near usize::MAX overflows in debug builds and can panic during slicing in release builds. This parser handles backend HTTP responses, so a malformed or hostile backend response can terminate the Desktop process.

Please use checked arithmetic for both the bounds check and the input[chunk_size..chunk_size + 2] slice, for example by computing let required_length = chunk_size.checked_add(2)?; and reusing it.

P2: debug/dev mode can fail with leftover packaged resources

src-tauri/build.rs:82 sets ASTRBOT_RUNTIME_MANIFEST_SHA256 to development-unbound for debug builds. However, src-tauri/src/launch_plan.rs:469-475 still validates packaged resources whenever a leftover resources/backend/runtime-manifest.json exists. After a packaged build, running pnpm dev can therefore fail with an invalid manifest identity instead of falling back to the dev launch plan.

This contradicts the documented behavior that debug/dev launch paths do not use the packaged identity gate. Please make debug builds skip packaged launch, or provide a real manifest hash in debug builds.

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.

2 participants