Skip to content

feat(auth): auth.json 跨进程写锁 + runtime 真身损坏回滚 - #96

Merged
wangzhizhou merged 1 commit into
mainfrom
feat/auth-lock-and-rollback
Oct 20, 2026
Merged

wangzhizhou merged 1 commit into
mainfrom
feat/auth-lock-and-rollback

Conversation

@wangzhizhou

Copy link
Copy Markdown
Contributor

两件共享契约加固,规范先行(父仓库 docs/spec/frontends.md F4.1、docs/spec/install-update.md §10.1)。

1. auth.json 跨进程写锁(F4.1)

问题:刷新令牌是「读 → 联网换新 → 写」的读改写。两个前端(CLI + GUI)同时刷,后写者覆盖先写者,
而微软的 refresh token 是轮换的 → 被覆盖的那份立刻失效,用户被登出。

做法:orzmc/infra/filelock.py —— <stateDir>/auth.lock 目录锁

项 值
获取 os.mkdir(POSIX/Windows 都原子)
陈旧 目录 mtime > 30s → 视为持锁进程已崩,删除后重试
超时 最多等 10s,拿不到 → E_AUTH_LOCKED(绝不在没锁时刷新)
临界区 持锁 → 重读 → 需要才刷新 → 写

为什么不用 flock:flock 与 fcntl 锁在 Linux/macOS 属于不同命名空间,跨语言极易"看起来加了锁、
其实互不可见";Windows 又没有 flock。mkdir 三平台语义一致,算法与 Swift 侧逐字相同
(Swift 侧另开 PR,同一套规则)。

Authenticator.ensure() 现在:持锁 → 重读 → 若另一个前端刚写好有效会话就直接复用(不再刷第二次)。

2. runtime 真身损坏回滚(§10.1)

  • 安装:旧真身改名 <payload>.bak → 原子替换;替换失败还原 .bak;
  • 运行前:对自己的副本做魔数预检,坏且 .bak 完好 → 回滚并 warn;
  • 执行失败(EACCES/ENOEXEC 之类"文件本身不可执行")→ 回滚后重试一次,仍失败报 E_RUNTIME + 提示重装;
  • 绝不静默删文件、绝不自动联网重下。

顺手修一个真 bug:runtime install 之前把 channel=wrapper(自己的副本)也当成"可复用"→ 永远无法升级;
现在只对别人装的原生 Swift 安装 no-op。

验证

  • 新增 orzmc/tests/test_auth_lock.py(7 例)与 TestPayloadRollback(3 例);
  • ruff / ruff format --check / mypy / pytest(全量)全绿;共享验收 25/25。

两件共享契约加固(规范见父仓库 `frontends.md` F4.1 与 `install-update.md` §10.1)。

**1. `auth.json` 跨进程写锁(F4.1)**
刷新令牌是「读 → 联网换新 → 写」的读改写,两个前端同时刷会让后者的 refresh token 立刻失效
(用户被登出)。新增 `orzmc/infra/filelock.py`:`<stateDir>/auth.lock` **目录锁**
(`mkdir` 在 POSIX/Windows 都原子;陈旧 30s 自动破除;等 10s 拿不到 → `E_AUTH_LOCKED`)。
算法与 Swift 侧**逐字一致**(用 flock 不行:`flock` 与 `fcntl` 锁跨语言互不可见,Windows 又没有 flock)。

`Authenticator.ensure()` 改为:**持锁 → 锁内重读 → 需要才刷新**。锁内重读到另一个前端刚写好的有效会话时
直接复用,不再刷一次(否则把它的 refresh token 轮换掉)。

**2. `runtime` 真身损坏回滚(§10.1)**
- 安装时把旧真身改名为 `<payload>.bak` 再原子替换,替换失败还原;
- 运行前对**自己的副本**做魔数预检,坏了且 `.bak` 完好 → 回滚并继续(记 warn);
- `exec` 报不可执行(EACCES/ENOEXEC/…)→ 用 `.bak` 回滚后**重试一次**,仍失败报 `E_RUNTIME` 并提示重装;
- 顺手修:`runtime install` 之前对 `channel=wrapper` 自己的副本也误判为"可复用"→ 永远无法升级;
  现在只对**别人装的**原生 Swift 安装 no-op。

测试:新增 `orzmc/tests/test_auth_lock.py`(7 例:获取/owner/争用超时/陈旧破除/新鲜不抢/锁路径/
锁内重读复用/超时映射 E_AUTH_LOCKED)与 `TestPayloadRollback`(3 例:备份生成/坏文件回滚/无备份不静默删)。
`ruff`/`mypy`/`pytest`(全量)与共享验收 25/25 全绿。
@wangzhizhou
wangzhizhou merged commit b713d8d into main Oct 20, 2026
11 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