Pin the activity-lock fixes and tighten the guard spec
ci / test-pg (pull_request) Failing after 2m17s
ci / test (pull_request) Failing after 2m21s

Why: the first pin allowed adopt to recreate a missing database and could write the guard record through a lock symlink. The spec now matches the refusal rules from review.
Evidence: Backend 1f7bcac; SELF tests named in that commit.
Impact: Dev gitlink moves from 89acd16 to 1f7bcac. Operators still see the same migrate command.
Refs: docs/recovery/u8-sqlite-instance-guard.md
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-12 14:17:02 +00:00
co-authored by Cursor
parent 33f40b9ba7
commit a0259118f7
2 changed files with 5 additions and 3 deletions
+4 -2
View File
@@ -11,7 +11,7 @@
| 规则 | 行为 |
|---|---|
| 路径 | 先 `Abs`,已存在的路径再 `EvalSymlinks`。数据库文件若是符号链接,锁放在解析后的真实文件旁边 |
| 锁文件 | `<db>.lock`(默认名 `agent-system.db.lock`)。`O_RDWR\|O_CREAT\|O_CLOEXEC`,模式 0600。永不 unlink |
| 锁文件 | `<db>.lock`。`O_RDWR\|O_CREAT\|O_CLOEXEC\|O_NOFOLLOW`,模式 0600。永不 unlink。数据目录不存在时,活动服务在取锁前创建该目录 |
| 互斥 | `flock(LOCK_EX\|LOCK_NB)`。占用返回「活动服务已在运行」,调用方不得打开库 |
| 替换检测 | 取锁后比较 fd 与路径的 device/inode,不一致则关闭并重试,仍不一致则拒绝 |
| 硬链接 | 解析后的数据库 `nlink>1` 直接拒绝,不能用 adopt 绕过 |
@@ -33,7 +33,9 @@ svc 的 `runtime/<name>/.start.lock` 只串行化脚本生命周期,挡不住
`instance_id` 取 `AGENT_SYSTEM_INSTANCE_ID`。表和锁文件都已有非空值且与本次不一致时拒绝。本次为空则不比较,保留表内原值。
显式 `--adopt-instance-guard`(仅 `serve` 与 `migrate`)在已持锁的前提下重写两边记录。硬链接拒绝不受该标志影响。
显式 `--adopt-instance-guard`(仅 `serve` 与 `migrate`)在已持锁的前提下重写两边记录。它只接受「数据库文件还在但 inode 已变」和「锁记录损坏」。记录还在而数据库文件消失时,adopt 也不打开、不新建空库。锁文件若是指向数据库的符号链接,或与数据库同一 inode,直接拒绝且不写入。硬链接拒绝不受该标志影响。
身份校验在写入守卫之前完成。`AGENT_SYSTEM_INSTANCE_ID` 已设置但与库内身份不符时,不留下本次的 instance id。
## 3. 耐久