78 lines
4.0 KiB
Markdown
78 lines
4.0 KiB
Markdown
# 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 巡检行可单独删除。
|