Files
dsh_shenxian/dsh-server-docs/04-调整方案/43-平台root污染用户工作区与属主自愈.md
T
admin 5ad755116e chore(docs): 文档库并入代码仓(R4 选 a)+ 索引/台账跟进
1) dsh-server-docs/ 从工作区(原 E:\...\aliyun-dsh-server\dsh-server-docs)**整体并入本仓**,
   保留目录名 ⇒ 仓库内 dsh-server-docs/... 的相对引用天然继续有效;旧目录(含其 .git)已归档到
   工作区 _中间产物_待清理/,未随本提交带入。
2) .gitattributes:新增 `dsh-server-docs/** -text` —— 原文档库是 `* -text` + autocrlf=false,
   必须保持纯 LF,否则会被本仓的 CRLF 规则翻掉。
3) 活引用里的绝对路径已全部改到新位置(docs 的 INDEX / README / scripts / skills + 用户级 skills
   + ~/.workbuddy/settings.json 的 hooks);历史档案(04-调整方案/、archive/)按「只增不改」未动。
   ⚠️ hooks 路径改动需「完全重启会话」才生效(配置是会话启动快照)。
4) 交接单/T08:新增 §16「生产整体切换执行记录」(形态 / 落地动作 / **4 个只有真上线才暴露的真 bug** /
   验收证据 / 回滚命令 / 残留项);台账 T08 行 → 已完成并归档;03-路线图 §二 登记 T08 收尾项。
5) 统一称谓:**「本机」只指跑 WorkBuddy 的开发机**,47 / 106 一律写「远程服务器」。
2026-09-15 18:47:13 +08:00

3.0 KiB
Raw Blame History

43-平台 root 污染用户工作区与属主自愈(2026-09-11 落地)

背景与动机

从 guest 最新会话取证时发现:会话里 pip install --user 会失败。复核后确认是平台自身 bug,不是权限策略问题。

现象与根因

  • 现象:guest 的 ws/.local、ws/.local/share/pnpm 属主是 root:root → 之后用户 pip install --user 报 Permission denied: '.../ws/.local/lib' —— 在自己的目录里装不了包。 admin 工作区无此问题(从未被 root 的 pnpm 触碰)。
  • 根因:平台以 root 执行 pnpm,且 HOME 指向用户工作区: src/web/routes/business-plugins.ts(pnpmEnv)与 scripts/ensure-biz-plugins.cjs。 pnpm 于是在用户家目录建出 root 属主的 .local/share/pnpm(store)。
  • 为什么不能简单改 HOME:代码注释已写明 —— 需与 dsh 实例共用同一个 pnpm store, 否则报 ERR_PNPM_UNEXPECTED_STORE(此前已踩过)。所以不能把平台侧 pnpm 的 HOME 挪走。

实现(只 chown、不删除)

  1. scripts/ws-cleanup.cjs 新增 reclaimOwnership(root, uid):
    • 递归 lstat + lchownSync,不跟随软链;
    • 只改属主,不删除任何文件(用户资产与 root 建的 pnpm store 都保留,root 依旧可读写);
    • 与清理阈值无关,always 执行;新增 --reclaim-only 模式(只做回收、不跑清理)。
  2. 即时:scripts/ensure-biz-plugins.cjs 在 pnpm add 成功之后,立刻调 ws-cleanup --apply --reclaim-only --user-id <id> → 消除"当天不可用"的窗口。
  3. 兜底:/etc/cron.d/dsh-maintenance 新增 每小时 25 * * * * 跑 --apply --reclaim-only。
  4. 顺带修一个潜在死循环:ensure-biz-plugins.cjs 里 dest 的文件名硬编码 business-plugins-0.2.0.tgz → 改为 basename(ARTIFACT)。 (否则一旦走安装分支,依赖名会停在旧版本 → !upToDate 恒真 → 每次运行都重装。)

验证记录

检查 结果
存量修复(全量扫描) guest 49 项 root 属主 → chown -R 后 0 项;admin 本就 0
人为造污染 → 自愈 造 51 项 root 污染 → --reclaim-only 一次回收为 0
文件内容/可用性 不变(0 字节测试文件回收后属主 100002:100002,仍可读写)
真实跑 ensure-biz-plugins.cjs guest: 已是 business-plugins-0.2.1.tgz → 跳过 —— 无回归

回滚 / 注意

  • 回滚:cp scripts/ws-cleanup.cjs.bak-<ts> scripts/ws-cleanup.cjs(并删掉 cron 行)。
  • 该 pass 只 chown,不会让任何体积统计/清理行为改变;.local 仍在 T1 清理名单里 (超阈值时会被移入 trash,30 天可恢复)——本改动不改变这一点。
  • 迁移到新服务器时:本自愈逻辑在 scripts/ 内随仓库走;但新机上首次仍会重新产生 root 属主的 .local(pnpm 行为),由 cron/ensure 兜底收回 → 属正常。