Files
dsh_shenxian/dsh-server-docs/04-调整方案/44-基础运行时版本冻结.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

79 lines
4.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 44-基础运行时版本冻结(禁止用户升级 Python/pip/node)(2026-09-11 落地)
## 背景与动机
用户要求:**禁止用户通过任何方式升级 Python 3.12.14 / pip / node 这些基础包**,
避免版本差异导致插件功能无法使用。
## 一、盘点:绝大部分护栏已天然成立(无需新代码)
| 升级路径 | 结果 | 依据 |
|---|---|---|
| 改运行时本体 `/usr/local/dsh-runtime/**` | ❌ | `/usr` 是 **ro-bind**(实测 `touch` = Read-only file system) |
| `pip install`(默认写平台 site-packages) | ❌ | 同上 |
| `npm install -g` / `pnpm add -g` | ❌ | `/usr/local/lib/node_modules` 只读 |
| 用 `~/.local/bin` 里的 console script | ❌ | 实例 PATH 固定 `/usr/local/bin:/usr/bin:/bin`,**不含** `~/.local/bin` |
| 让 dsh / 插件用自己装的 node | ❌ | dsh 主进程由 orchestrator spawn,其 PATH 取自 **root** 环境(`scrubEnv`),与用户 shell 无关 |
## 二、唯一真实缝隙:Python 的 user-site
**实测证据**:`pip install --user` 一旦创建 `$HOME/.local/lib/python3.12/site-packages`,
该目录**就会进入 `sys.path` 且排在平台 `site-packages` 之前** →
用户装的同名包**盖住平台包**。实测 `import packaging` 拿到的是**用户版 26.3**(`ws/.local/...`)。
这正是"版本差异导致插件功能不可用"的来源。
> 注意:初始状态(该目录尚不存在时)`user-site` **不在** `sys.path`;是 pip 自己创建目录后才加入的。
## 三、实现(两条限制性 env,官方机制、互不冲突)
`src/supervisor/orchestrator.ts` · `baseEnv()`:
```
PYTHONNOUSERSITE = '1' // user-site 不进 sys.path
PYTHONUSERBASE = '/usr/local/dsh-runtime/.no-user-install' // pip --user 写只读位 → 明确报错
```
`src/supervisor/spawn.ts` · `ALLOWED_ENV` 同步放行这两个变量。
两条互相不冲突:`PYTHONNOUSERSITE` 只管 `sys.path`,不影响 pip 计算 `--user` 目标路径;
`PYTHONUSERBASE` 让 `--user` 的写入落在只读位 → **明确失败**而不是"装上了却不生效"。
## 四、版本漂移巡检
新增 `scripts/runtime-baseline.cjs`:
- `--accept` → 把当前版本写入基线 `/opt/dsh/state/runtime-baseline.json`;
- 默认 → 比对,漂移则逐项打印并 **exit 1**;一致则 `ok`。
- cron:`/etc/cron.d/dsh-maintenance` **每天 05:10** 跑,日志 `/var/log/dsh-runtime-baseline.log`。
- ⚠️ **有意升级运行时后必须跑 `--accept`**,否则会一直告警。
基线当前值:`python3 3.12.14 / pip 26.2.1 / node 22.23.2 / npm 10.9.8 / runtimePinned 3.12.14`。
## 验证记录(沙箱内,uid 100002)
| 检查 | 结果 |
|---|---|
| 版本基线 | python3 **3.12.14** / pip **26.2.1** / node **v22.23.2** / npm 10.9.8 |
| `PYTHONNOUSERSITE` / `PYTHONUSERBASE` | `1` / `/usr/local/dsh-runtime/.no-user-install` |
| user-site 在 `sys.path` | **False** |
| `pip install --user` | **明确拒绝**:`ERROR: Can not perform a '--user' install. User site-packages are disabled for this Python.` |
| 历史污染是否还能盖平台包 | **✅ 已失效** |
| `pip install --target <ws>/.pylibs` + `PYTHONPATH` | ✅ 仍可用(requests 2.34.2) |
| `npm -g` / `/usr/local/lib/node_modules` | 只读 ✅ |
| 基线巡检 | 写入 → 第二次比对 `ok 运行时版本与基线一致` |
## R5 方向判定
本改动虽触碰 **R5 触发文件**(`spawn.ts` 的 `ALLOWED_ENV`、`orchestrator.ts` 的 `baseEnv`),
但**方向是收窄**(限制用户侧安装能力,不是放开)→ 按 R5 可直接做,已在 commit 与本节留痕。
## 给用户/AI 的正规替代路径(已写入技能)
需要额外 Python 依赖时:
- `pip install --target <ws>/.pylibs <pkg>` + `PYTHONPATH=<ws>/.pylibs`(实测可用);
- 或自建 **venv**(venv 会用平台解释器副本,不影响平台 runtime)。
## 回滚
删掉 `baseEnv` 里那两行(及 `ALLOWED_ENV` 两项)→ `npm run build` → `systemctl restart dshs`。
cron 巡检行可单独删除。