Skip to content

fix(vault): 保存凭据跳过未变化的 keychain 条目,修复切换供应商弹窗风暴 (#602) - #634

Merged
H-Chris233 merged 1 commit into
betafrom
fix/issue-602-keychain-prompt-storm
Jun 10, 2026
Merged

fix(vault): 保存凭据跳过未变化的 keychain 条目,修复切换供应商弹窗风暴 (#602)#634
H-Chris233 merged 1 commit into
betafrom
fix/issue-602-keychain-prompt-storm

Conversation

@appergb

@appergbappergb commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator

User description

问题 (#602)

macOS 设置中切换供应商会连续弹出多次「OpenLess 想访问钥匙串」密码弹窗(v1.3.6-2 复现)。

根因:切换供应商只改 root.active 一个字段,但 save_credentials 每次都执行读旧 manifest → 重写所有 chunks → 重写 manifest。macOS Keychain 每个条目各自 ACL,签名变化/未点「始终允许」时每次条目访问各弹一窗 → 一次切换 3+ 个弹窗。读路径早有进程缓存(PR #394),写路径没有。

修复

基于已有的进程级凭据缓存做三处收口:

  1. manifest 进程缓存:load/save 成功后回填 CREDENTIALS_MANIFEST_CACHE,后续 save 不再回 keychain 读旧 manifest。冷缓存仍读真实 manifest——UUID 代际旧 chunks 的清理信息不丢。
  2. chunk_skip_mask(纯函数,带单测):用缓存中上次落盘的 root 反推旧 chunk 内容,逐字节一致的 chunk 跳过重写。仅旧 manifest 已是稳定名(generation=None)时启用;任何不确定(冷缓存/序列化顺序差异/UUID 代际)都退回「全部重写」旧行为,只会多写不会漏写。
  3. manifest 跳写:manifest 内容只由 chunks 数决定,数量不变且已是稳定名 → 内容逐字节一致,跳过。

效果:典型单 chunk 凭据库,切换供应商 keychain 访问 3 次 → 1 次;no-op 保存 0 次。保存时新增一行 info 日志(written/total + manifest 状态),方便用户日志回报验证。

安全性

  • partial-write 防护保持:仍是「先 chunks 后 manifest」顺序
  • 跳写只在「目标内容 == 缓存内容」时发生;save 失败不更新缓存,重试会全量重写差异项
  • 不改变存储 schema,无迁移,可直接回滚

验证

  • 新增单测 chunk_skip_mask_skips_unchanged_and_rewrites_changed(4 个场景)
  • cargo test --lib:479 passed, 0 failed

Closes#602


PR Type

Bug fix


Description

  • 添加进程级 manifest 缓存,避免保存前读取钥匙串

  • 实现 chunk_skip_mask 跳过未变化的 chunk

  • 在 chunk 数量和 manifest 稳定时跳过 manifest 写入

  • 添加相应的单元测试


Diagram Walkthrough

flowchart LR
A["save_credentials"] --> B{"manifest cache hit & stable name?"}
B -- "yes" --> C["chunk_skip_mask from cached root"]
C --> D["write only changed chunks"]
D --> E{"chunks count unchanged?"}
E -- "yes" --> F["skip manifest write"]
E -- "no" --> G["write new manifest"]
B -- "no" --> H["read manifest from keychain"]
H --> I["write all chunks"]
I --> G
F --> J["update caches"]
G --> J
Loading

File Walkthrough

Relevant files
Bug fix
persistence.rs
添加 manifest 缓存和 chunk 跳过优化

openless-all/app/src-tauri/src/persistence.rs

  • 新增 CREDENTIALS_MANIFEST_CACHE 静态缓存
  • 新增 chunk_skip_mask 函数计算可跳过的 chunk
  • 修改 save_credentials 使用缓存和跳过逻辑
  • 新增 chunk_skip_mask 单元测试
+113/-11

切换供应商只改 root.active 一个字段,但 save_credentials 会先读旧 manifest、
再重写所有 chunks、再重写 manifest —— macOS 上每个 keychain 条目各自 ACL,
ad-hoc 签名/未永久授权时每次访问各弹一次「访问密码」弹窗,一次切换弹 3+ 次。
三处收口(都基于已有的进程级凭据缓存,行为冷路径不变):
1. manifest 进程缓存(CREDENTIALS_MANIFEST_CACHE):load/save 成功后回填,
后续 save 不再回 keychain 读旧 manifest(省 1 次 ACL 访问);冷缓存仍读
真实 manifest,UUID 代际旧 chunks 的清理信息不丢。
2. chunk_skip_mask:用缓存里上次落盘的 root 反推旧 chunk 内容,逐字节一致的
chunk 跳过重写。仅旧 manifest 已是稳定名(generation=None)时启用;缓存
序列化顺序差异只会多写(回退旧行为),不会漏写。
3. manifest 内容只由 chunks 数决定:数量不变且已是稳定名 → 跳过重写。
典型单 chunk 凭据库:切换供应商 3 次 keychain 访问 → 1 次。
@github-actions

Copy link
Copy Markdown
Contributor

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

🎫 Ticket compliance analysis 🔶

602 - Partially compliant

Compliant requirements:

  • 新增 manifest 进程缓存,避免 save_credentials 时重复读取 keychain manifest
  • 使用 chunk_skip_mask 跳过内容未变化的 chunk 写入
  • manifest 内容不变时跳过 manifest 写入
  • 冷启动/不确定时退回全量写入,不丢失清理信息

Non-compliant requirements:

(无)

Requires further human verification:

(无)

394 - Partially compliant

Compliant requirements:

  • 保留了已有的 CREDENTIALS_CACHE 并在 store_credentials_cache 中正确更新
  • 新增的 manifest 缓存(CREDENTIALS_MANIFEST_CACHE)与现有缓存协同工作
  • 错误路径不缓存 manifest,确保下次读取仍从 keychain 重试

Non-compliant requirements:

(无)

Requires further human verification:

(无)

⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
🧪 PR contains tests
🔒 No security concerns identified
⚡ No major issues detected

@H-Chris233
H-Chris233 merged commit f6c0b32 into betaJun 10, 2026
5 checks passed
@H-Chris233
H-Chris233 deleted the fix/issue-602-keychain-prompt-storm branch August 3, 2026 08:46
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[macos]设置中切换供应商会多次弹出访问密码的弹窗

2 participants

@appergb@H-Chris233