Skip to content

fix(cli-auth): 保活刷新不再误报「认证脱节」,孤儿 Token 可自愈 - #124

Merged
changexbc merged 4 commits into
mainfrom
fix/cli-auth-minimal
Sep 30, 2026
Merged

changexbc merged 4 commits into
mainfrom
fix/cli-auth-minimal

Conversation

@changexbc

Copy link
Copy Markdown
Owner

背景

Windows 上 CodeBuddy CLI 认证横幅有两个独立成因,之前都表现为「认证脱节」告警,且无法自愈。

1. 误报

保活刷新先批量改写账号库(~/.wb-switch/accounts.json)里的 access_token,再异步同步回 ~/.codebuddy/settings.json。这个中间态被原判定当成「认证脱节」,于是每次启动都可能弹一次横幅。

2. 不可自愈

settings.json 里的 token 若匹配不上账号库中任何账号(孤儿值,多因历史某次刷新未同步成功),原判断 !previous_matches && !already_synced 会永远 return Ok(false)——状态卡死,只能靠用户手动点「更新 CLI 认证」,点了也未必收敛。

改动

核心(crates/wb-switch-core/src/modules/codebuddy_cli.rs)

  • 按账号库 mtime 划出 30 秒宽限窗口:窗口内报 syncInProgress(正在同步,无需操作),窗口外才报 syncPending(真脱节)。判定抽成纯函数 classify_sync_state,边界(尤其窗口临界点)可被单测固定。
  • 增加孤儿例外:settings 的 token 匹配不上任何账号时,允许被活跃账号的最新 token 覆盖;若命中的是其它账号(用户手动切换),仍不覆盖,保留原保护。

前端

  • 刷新前后、切换账号、接入 helper 后广播 codebuddy-cli-updated;AccountsPage 监听该事件并加 30 秒兜底轮询,横幅不再滞留。
  • syncInProgress 期间只给状态说明、不显示按钮,避免用户在刷新未完成时重复触发写入。

测试

  • 新增 crates/wb-switch-core/tests/cli_auth_sync_e2e.rs(5 个用例):误报、真脱节、一致、孤儿自愈、不得覆盖其它账号。
  • 新增 config::HOME_ENV_VAR(WB_SWITCH_HOME)覆盖钩子,把家目录沙箱化,测试全程不触碰真实账号与 CLI 配置;沙箱期间清除 CODEBUDDY_AUTH_TOKEN / CODEBUDDY_INTERNET_ENVIRONMENT,因此在 CodeBuddy CLI 自身进程里跑也是绿的,不会出现「测的是当前 shell 而不是被测逻辑」的假红。
  • 测试文件整体加 #![cfg(windows)]:被测分支本就是 Windows 专属,避免非 Windows 下 clippy --all-targets -- -D warnings 因未使用导入 / 死代码失败。

验证

门禁 结果
cargo test -p wb-switch-core 700 passed + 新增 e2e 5 passed
cargo test -p wb-switch-server 9 passed
cargo fmt --check -p wb-switch-core -p wb-switch-server -p wb-switch-rust 通过
cargo clippy --all-targets --no-deps -- -D warnings 改动代码无告警
npm run build(tsc + vite) 通过

反向验证:临时移除孤儿例外后,orphaned_settings_token_is_healed_by_sync 精确失败于 Ok(false)(期望 Ok(true)),确认测试确实咬住了原 bug,而不是恒真。

附带的构建层提交(与业务无关)

本 PR 另含一个独立提交 e629264:schemars 0.8(tauri-build / tauri-plugin 的传递依赖,且开启 preserve_order)按 IndexMap<K, V> 两参数形式引用 indexmap 1.x,而 indexmap 1.9.3 的默认哈希参数 S 只在 has_std 下存在;该 cfg 由 crate 内 build.rs 的 autocfg 探测 sysroot 得出,在新版 Rust(本机 1.98.1 实测)上该探测失败,导致 E0107: struct takes 3 generic arguments but 2 were supplied。现 patch 到 vendor-patched/indexmap:其 build.rs 无条件声明 has_std,只改 build script 探测逻辑、不触碰任何库代码(已核对:该 crate 的 src/ 只用到 has_std 这一个自定义 cfg)。如不需要,可单独回退该提交并删除 vendor-patched/。

已知的既有问题(非本 PR 引入)

  • src-tauri/src/tray.rs:1031 在 Windows 上跑 cargo clippy -p wb-switch-rust --all-targets 会报 E0425: cannot find function taskbar_uses_light_theme(#[cfg(windows)] 的测试函数缺 use)。该文件最后改动在 77d3a39(v0.1.50);CI 的 clippy 跑在 macOS,该分支被 cfg 掉,所以 CI 不报。
  • 同理,Windows 本地 clippy 还会在 vscode_cn_inject.rs、codebuddy_cli.rs:378 报 needless_return 等,均为既有 Windows-only 代码。

changexbc and others added 4 commits September 30, 2026 02:02
`schemars 0.8`(tauri-build / tauri-plugin 的传递依赖,且开启了 `preserve_order`)
按 `IndexMap<K, V>` 两参数形式引用 `indexmap 1.x`,而 `indexmap 1.9.3` 的默认哈希参数
`S` 只在 `has_std` 下存在。该 cfg 由 crate 内 build.rs 里的 `autocfg` 探测 sysroot 得出,
在新版 Rust(本机 1.98.1 实测)上该探测会失败,于是编译报:

    E0107: struct takes 3 generic arguments but 2 were supplied

这里把 `indexmap` patch 到 `vendor-patched/indexmap`:其 build.rs 无条件声明 `has_std`,
从根上消除 E0107。只改 build script 的探测逻辑,不触碰任何库代码——该 crate 的 `src/`
只用到 `has_std` 这一个自定义 cfg(已核对),因此不改变任何运行时行为。

纯构建层兼容修复,与业务逻辑无关。若你的工具链较老(autocfg 探测正常),
可整段回退本提交并删除 `vendor-patched/`。
Windows 上 CodeBuddy CLI 认证横幅有两个独立成因:

1. 误报:保活刷新先改写账号库里的 token、再同步回 settings.json。
   这个中间态被原判定当成「认证脱节」,于是每次启动都可能弹一次。
   现按账号库 mtime 划出 30 秒宽限窗口,窗口内报 syncInProgress
   (「正在同步,无需操作」),窗口外才报 syncPending(真脱节)。

2. 不可自愈:settings 里的 token 若匹配不上账号库中任何账号(孤儿值,
   多因历史刷新未同步成功),原判断 `!previous_matches && !already_synced`
   会永远 return Ok(false),状态卡死只能手动点按钮。
   现增加孤儿例外:孤儿值允许被活跃账号的最新 token 覆盖;
   若命中的是其它账号(用户手动切换)仍不覆盖。

配套:刷新前后与切换账号/接入 helper 后广播 codebuddy-cli-updated,
前端监听该事件并加 30 秒兜底轮询,横幅不再滞留。

测试隔离:新增 e2e 用 WB_SWITCH_HOME 把家目录沙箱化(新增
config::HOME_ENV_VAR 覆盖钩子),并在沙箱期间清除 CODEBUDDY_AUTH_TOKEN /
CODEBUDDY_INTERNET_ENVIRONMENT,使用例在 CodeBuddy CLI 自身进程里也能跑绿;
整个测试文件加 `#![cfg(windows)]`,避免非 Windows 下
`clippy --all-targets -D warnings` 因未使用导入 / 死代码失败。

验证:wb-switch-core 700 单测 + 5 个新增 e2e 全通过;反向验证(移除孤儿例外)
确认 e2e 中 orphaned_settings_token_is_healed_by_sync 会精确失败于 Ok(false)。
…ted_cfgs

CI 的 lint job 跑 `cargo clippy -p wb-switch-core -p wb-switch-server -p wb-switch-rust
--all-targets --no-deps -- -D warnings`,会把 vendor-patched/indexmap 里
`#[cfg(has_std)]` 触发的 rustc `unexpected_cfgs` 告警直接判成错误,
`indexmap` 编译失败(13 errors),PR 的 lint job 因此红。

根因:autocfg 的自由函数 `emit()` 不会自动调用 `emit_possibility()`
(其文档明确写了这点),所以 `has_std` 这个 cfg 名从未被声明。
补一行 `autocfg::emit_possibility("has_std")` 即可。

本地验证:同一条 CI 命令下 has_std 相关输出从 13 条降为 0;
fmt / core 700+5 单测 / server 9 单测 均通过。
@changexbc
changexbc merged commit f357c58 into main Sep 30, 2026
10 checks passed
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.

1 participant