Skip to content

Commit 073ada2

Browse files
committed
fix(updater): require confirmation before installing downloaded updates
1 parent 53f2f9a commit 073ada2

35 files changed

Lines changed: 980 additions & 155 deletions

‎Cargo.lock‎

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Cargo.toml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ unic-langid = "0.9"
248248
x25519-dalek = { version = "2.0", features = ["static_secrets"] }
249249
aes-gcm = "0.10"
250250
sha2 = "0.10"
251+
minisign-verify = "0.2"
251252
sha1 = "0.10"
252253
argon2 = "0.5"
253254
rand = "0.8"

‎docs/interactive-capabilities/README.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ OpenBitFun Playbook currently contains **22 features**, **21 settings pages**, a
2727
- Generated per-item interaction audit: `docs/interactive-capabilities/technical/product-control-open-audit.json`
2828
- Generated low-level audit map: `docs/interactive-capabilities/technical/tauri-command-map.json`
2929

30-
说明书、网站、搜索和 Agent 只看“功能 + 设置 + 子能力”。每项子能力都必须引用已注册 Tauri Command 或可解析的源码标记;这些证据不会进入公开目录。当前 **661** 个 Tauri 命令只用于实现覆盖审计。产品 UI 交互源码会在生成和检查时扫描并校验,但不会保存成随普通 UI 改动频繁变化的版本化快照。
30+
说明书、网站、搜索和 Agent 只看“功能 + 设置 + 子能力”。每项子能力都必须引用已注册 Tauri Command 或可解析的源码标记;这些证据不会进入公开目录。当前 **664** 个 Tauri 命令只用于实现覆盖审计。产品 UI 交互源码会在生成和检查时扫描并校验,但不会保存成随普通 UI 改动频繁变化的版本化快照。
3131

32-
Docs, website, search, and agents see only features, settings, and documented sub-capabilities. Every sub-capability must reference a registered Tauri command or a resolvable source marker; evidence is stripped from public projections. The **661** Tauri commands remain implementation-audit evidence only. Product UI interaction sources are scanned and validated during generation and checks, but are not stored as a versioned snapshot that churns with ordinary UI changes.
32+
Docs, website, search, and agents see only features, settings, and documented sub-capabilities. Every sub-capability must reference a registered Tauri command or a resolvable source marker; evidence is stripped from public projections. The **664** Tauri commands remain implementation-audit evidence only. Product UI interaction sources are scanned and validated during generation and checks, but are not stored as a versioned snapshot that churns with ordinary UI changes.
3333

3434
## 控制边界 / Control boundary
3535

‎docs/interactive-capabilities/capabilities.json‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"title": "OpenBitFun Playbook",
55
"origin": "https://playbook.openbitfun.com",
66
"source": "src/shared/interactive-capabilities/catalog.json",
7-
"digest": "54dbaf7f84805e6cd683cd103d1a2bbaeb556953e1f5ef9c3309221e36e472e2",
7+
"digest": "63d430e2cdadd590e819c09c40e6ca693c33cd31bf4734dbf2803d1ba405128c",
88
"ownerDigest": "8c1887b051aab537946c1e80afd24a5eb3936a083e01bbbce4227e6c7d8b0e48",
99
"searchAcceptance": [
1010
{
@@ -24149,13 +24149,13 @@
2414924149
},
2415024150
{
2415124151
"id": "manual-update",
24152-
"titleZh": "手动检查、下载并安装可用更新,然后按需重启",
24153-
"titleEn": "Check for, download, and install an available update manually, then restart when needed",
24152+
"titleZh": "手动检查并后台下载更新,确认后安装并重启,或稍后从关于页面安装",
24153+
"titleEn": "Check and download updates in the background, then confirm installation and restart or install later from About",
2415424154
"control": {
2415524155
"kind": "open",
2415624156
"reasonCode": "unstructuredInteraction",
24157-
"reasonZh": "“手动检查、下载并安装可用更新,然后按需重启”由多个实时状态相关步骤组成,目前没有一个能确定完成整个流程的单一结构化 Command;Agent 会打开精确入口,并把后续交互保留在用户可见界面。",
24158-
"reasonEn": "“Check for, download, and install an available update manually, then restart when needed” spans multiple live-state-dependent steps and currently has no single structured Command that can deterministically complete the whole workflow; the Agent opens the exact entry and keeps the remaining interaction visible to the user."
24157+
"reasonZh": "“手动检查并后台下载更新,确认后安装并重启,或稍后从关于页面安装”需要下载后由用户确认安装与重启;Agent 会打开精确入口,并把后续交互保留在用户可见界面。",
24158+
"reasonEn": "“Check and download updates in the background, then confirm installation and restart or install later from About” requires user confirmation after downloading, before installation and restart; the Agent opens the exact entry and keeps the remaining interaction visible to the user."
2415924159
}
2416024160
},
2416124161
{
@@ -24359,8 +24359,8 @@
2435924359
"Completion, permission, and startup-tip notifications",
2436024360
"启用或停用自动检查更新",
2436124361
"Enable or disable automatic update checks",
24362-
"手动检查、下载并安装可用更新,然后按需重启",
24363-
"Check for, download, and install an available update manually, then restart when needed",
24362+
"手动检查并后台下载更新,确认后安装并重启,或稍后从关于页面安装",
24363+
"Check and download updates in the background, then confirm installation and restart or install later from About",
2436424364
"控制 OpenBitFun 是否在登录系统后自动启动",
2436524365
"Choose whether OpenBitFun launches automatically after system sign-in",
2436624366
"控制 OpenBitFun 运行期间是否阻止电脑自动睡眠",

‎docs/interactive-capabilities/capabilities/setting.application.general.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ Manage app-level preferences for startup, updates, close behavior, notifications
1919

2020
- **Agent 可直接控制 / Direct Agent control** · 启用或停用自动检查更新
2121
- Enable or disable automatic update checks
22-
- **Agent 可定位入口,需交互完成 / Agent opens; interaction required** · 手动检查、下载并安装可用更新,然后按需重启
23-
- Check for, download, and install an available update manually, then restart when needed
22+
- **Agent 可定位入口,需交互完成 / Agent opens; interaction required** · 手动检查并后台下载更新,确认后安装并重启,或稍后从关于页面安装
23+
- Check and download updates in the background, then confirm installation and restart or install later from About
2424
- **Agent 可直接控制 / Direct Agent control** · 控制 OpenBitFun 是否在登录系统后自动启动
2525
- Choose whether OpenBitFun launches automatically after system sign-in
2626
- **Agent 可直接控制 / Direct Agent control** · 控制 OpenBitFun 运行期间是否阻止电脑自动睡眠

‎docs/interactive-capabilities/technical/product-control-open-audit.json‎

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"schemaVersion": 1,
33
"generatedFrom": "src/shared/interactive-capabilities/catalog.json",
4-
"catalogDigest": "54dbaf7f84805e6cd683cd103d1a2bbaeb556953e1f5ef9c3309221e36e472e2",
4+
"catalogDigest": "63d430e2cdadd590e819c09c40e6ca693c33cd31bf4734dbf2803d1ba405128c",
55
"count": 212,
66
"reasonCounts": {
77
"externalAuth": 4,
@@ -2492,19 +2492,20 @@
24922492
{
24932493
"capabilityId": "setting.application.general",
24942494
"itemId": "manual-update",
2495-
"titleZh": "手动检查、下载并安装可用更新,然后按需重启",
2496-
"titleEn": "Check for, download, and install an available update manually, then restart when needed",
2495+
"titleZh": "手动检查并后台下载更新,确认后安装并重启,或稍后从关于页面安装",
2496+
"titleEn": "Check and download updates in the background, then confirm installation and restart or install later from About",
24972497
"reasonCode": "unstructuredInteraction",
2498-
"reasonZh": "“手动检查、下载并安装可用更新,然后按需重启”由多个实时状态相关步骤组成,目前没有一个能确定完成整个流程的单一结构化 Command;Agent 会打开精确入口,并把后续交互保留在用户可见界面。",
2499-
"reasonEn": "“Check for, download, and install an available update manually, then restart when needed” spans multiple live-state-dependent steps and currently has no single structured Command that can deterministically complete the whole workflow; the Agent opens the exact entry and keeps the remaining interaction visible to the user.",
2498+
"reasonZh": "“手动检查并后台下载更新,确认后安装并重启,或稍后从关于页面安装”需要下载后由用户确认安装与重启;Agent 会打开精确入口,并把后续交互保留在用户可见界面。",
2499+
"reasonEn": "“Check and download updates in the background, then confirm installation and restart or install later from About” requires user confirmation after downloading, before installation and restart; the Agent opens the exact entry and keeps the remaining interaction visible to the user.",
25002500
"presentationTarget": {
25012501
"kind": "settings",
25022502
"pageId": "application.general"
25032503
},
25042504
"evidence": [
25052505
"command:check_for_updates",
2506-
"command:install_update",
2507-
"command:restart_app",
2506+
"command:download_update",
2507+
"command:get_pending_update",
2508+
"command:install_pending_update",
25082509
"command:get_app_version"
25092510
]
25102511
},

‎docs/interactive-capabilities/technical/tauri-command-map.json‎

Lines changed: 56 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
{
22
"schemaVersion": 2,
33
"generatedFrom": "src/shared/interactive-capabilities/catalog.json",
4-
"catalogDigest": "54dbaf7f84805e6cd683cd103d1a2bbaeb556953e1f5ef9c3309221e36e472e2",
5-
"commandCount": 661,
4+
"catalogDigest": "63d430e2cdadd590e819c09c40e6ca693c33cd31bf4734dbf2803d1ba405128c",
5+
"commandCount": 664,
66
"coverage": {
7-
"commandCount": 661,
8-
"documentedCommandCount": 630,
9-
"implementationCommandCount": 31,
10-
"implementationDigest": "859a3a3cb1e4e27ca38cd9003cef14e8758483ce85417a2c22c6ab92df9dd2c3"
7+
"commandCount": 664,
8+
"documentedCommandCount": 631,
9+
"implementationCommandCount": 33,
10+
"implementationDigest": "35539d9c1510287cb47f4a68fe35859b78f93bb06cd66b86e58d878a48d8c509"
1111
},
1212
"commands": [
1313
{
@@ -2290,6 +2290,22 @@
22902290
"signature": "fn download_skill_market( _state: State<'_, AppState>, request: SkillMarketDownloadRequest, ) -> Result<SkillMarketDownloadResponse, String>",
22912291
"remoteWorkspacePolicy": "LegacyUnaudited"
22922292
},
2293+
{
2294+
"id": "download_update",
2295+
"moduleId": "update",
2296+
"capabilityId": "setting.application.general",
2297+
"capabilityIds": [
2298+
"setting.application.general"
2299+
],
2300+
"documentedItemIds": [
2301+
"setting.application.general:manual-update"
2302+
],
2303+
"visibility": "documented",
2304+
"rustPath": "api::update_api::download_update",
2305+
"sourceFile": "src/apps/desktop/src/api/update_api.rs",
2306+
"signature": "fn download_update( app: AppHandle, request: PendingUpdateRequest, ) -> Result<PendingUpdateResponse, String>",
2307+
"remoteWorkspacePolicy": "WorkspaceAgnostic"
2308+
},
22932309
{
22942310
"id": "editor_ai_cancel",
22952311
"moduleId": "editor_ai",
@@ -3493,6 +3509,22 @@
34933509
"signature": "fn get_pending_announcements( state: State<'_, AppState>, ) -> Result<Vec<AnnouncementCard>, String>",
34943510
"remoteWorkspacePolicy": "WorkspaceAgnostic"
34953511
},
3512+
{
3513+
"id": "get_pending_update",
3514+
"moduleId": "update",
3515+
"capabilityId": "setting.application.general",
3516+
"capabilityIds": [
3517+
"setting.application.general"
3518+
],
3519+
"documentedItemIds": [
3520+
"setting.application.general:manual-update"
3521+
],
3522+
"visibility": "documented",
3523+
"rustPath": "api::update_api::get_pending_update",
3524+
"sourceFile": "src/apps/desktop/src/api/update_api.rs",
3525+
"signature": "fn get_pending_update( app: AppHandle, request: PendingUpdateRequest, ) -> Result<Option<PendingUpdateResponse>, String>",
3526+
"remoteWorkspacePolicy": "WorkspaceAgnostic"
3527+
},
34963528
{
34973529
"id": "get_prevent_sleep_enabled",
34983530
"moduleId": "sleep_prevention",
@@ -4764,8 +4796,8 @@
47644796
"remoteWorkspacePolicy": "LegacyUnaudited"
47654797
},
47664798
{
4767-
"id": "install_update",
4768-
"moduleId": "system",
4799+
"id": "install_pending_update",
4800+
"moduleId": "update",
47694801
"capabilityId": "setting.application.general",
47704802
"capabilityIds": [
47714803
"setting.application.general"
@@ -4774,6 +4806,20 @@
47744806
"setting.application.general:manual-update"
47754807
],
47764808
"visibility": "documented",
4809+
"rustPath": "api::update_api::install_pending_update",
4810+
"sourceFile": "src/apps/desktop/src/api/update_api.rs",
4811+
"signature": "fn install_pending_update( app: AppHandle, request: InstallPendingUpdateRequest, ) -> Result<(), String>",
4812+
"remoteWorkspacePolicy": "WorkspaceAgnostic"
4813+
},
4814+
{
4815+
"id": "install_update",
4816+
"moduleId": "system",
4817+
"capabilityId": "setting.application.general",
4818+
"capabilityIds": [
4819+
"setting.application.general"
4820+
],
4821+
"documentedItemIds": [],
4822+
"visibility": "implementation",
47774823
"rustPath": "install_update",
47784824
"sourceFile": "src/apps/desktop/src/api/system_api.rs",
47794825
"signature": "fn install_update(app: AppHandle, request: InstallUpdateRequest) -> Result<(), String>",
@@ -7774,10 +7820,8 @@
77747820
"capabilityIds": [
77757821
"setting.application.general"
77767822
],
7777-
"documentedItemIds": [
7778-
"setting.application.general:manual-update"
7779-
],
7780-
"visibility": "documented",
7823+
"documentedItemIds": [],
7824+
"visibility": "implementation",
77817825
"rustPath": "restart_app",
77827826
"sourceFile": "src/apps/desktop/src/api/system_api.rs",
77837827
"signature": "fn restart_app(app: AppHandle, request: RestartAppRequest) -> Result<(), String>",

‎src/apps/desktop/AGENTS.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,11 @@ The `devtools` Cargo feature exists for debugging UI/UX in the desktop app. When
9393
cargo check -p openbitfun-desktop && cargo test -p openbitfun-desktop
9494
```
9595

96+
For staged application-update cache and signature behavior, use
97+
`cargo test -p openbitfun-desktop --lib api::update_api::tests`.
98+
After changing updater command registration, also run
99+
`cargo test -p openbitfun-desktop --lib remote_workspace_policy`.
100+
96101
If the change affects startup, WebDriver, browser/computer-use, or packaged behavior, also run:
97102

98103
```bash

‎src/apps/desktop/Cargo.toml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ axum = { workspace = true }
8181
tower-http = { workspace = true, features = ["fs"] }
8282
sha1 = { workspace = true }
8383
sha2 = { workspace = true }
84+
minisign-verify = { workspace = true }
8485
screenshots = { workspace = true }
8586
enigo = { workspace = true }
8687
image = { workspace = true, features = ["jpeg", "png"] }

‎src/apps/desktop/README.md‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# OpenBitFun Desktop
2+
3+
For development commands, see [AGENTS.md](AGENTS.md) and the repository
4+
[contribution guide](../../../CONTRIBUTING.md).
5+
6+
## Application updates
7+
8+
Choose **Background download** in the new-version dialog to download and verify
9+
an update while continuing to use OpenBitFun. Downloading does not install the
10+
update or restart the application.
11+
12+
When the download finishes, OpenBitFun offers **Install and restart** or
13+
**Later**. Installation restarts OpenBitFun on this device and interrupts its
14+
active sessions. Choosing Later, or closing the dialog, keeps the downloaded
15+
update. Open **About → Install and restart** whenever you are ready; the same
16+
confirmation appears before installation.
17+
18+
Downloaded updates remain available after closing and reopening OpenBitFun.
19+
After reopening, the current updater requires access to the update server to
20+
restore installer metadata, but does not download the package again. If this
21+
step or installation fails, the pending update remains available to retry.
22+
Use **Download again** in the error dialog if the cached package is damaged.
23+
24+
Application updates always belong to the local desktop, including while viewing
25+
a peer device or a remote workspace. They do not install software on the peer or
26+
cancel independently running detached jobs on another host. Connections through
27+
the restarting desktop are interrupted.

0 commit comments

Comments
 (0)