回收 411 MB(470 M → 58.8 M),全部经回收站,可恢复: - 待清理/(146.2 M,含 relay 分片 128 M 与 42 项过程目录) - tmp/(32.4 M,按接续棒命名的过程临时区) - .workbuddy/tmp/(39.5 M) - 4 份 workbuddy.db 冗余副本(101 M,09-23 事故的坏副本 / 抢救产物) - tmp/im16/gw/centrifugo 二进制(63.9 M,可重下)+ 缓存残留 入库范围:常驻规则(CODEBUDDY.md / README.md / state.py)、在途接续入口与 接续包、docs/、交付物/、交接单/、归档/、scripts/、.codebuddy/、 .workbuddy/memory/;共 398 件,其中 >60 KB 的 26 件全为文档。 排除(.gitignore):tmp/、待清理/、运行态日志与缓存、*.db 与 DB 备份整目录、 打包二进制(*.tar.gz / *.tgz)、记忆修复前备份。
59 lines
2.7 KiB
Python
59 lines
2.7 KiB
Python
#!/usr/bin/env python3
|
||
# 档案 18/17 P1(H2):把平台策略文件在实例内设为只读(bwrap --ro-bind-try)
|
||
# 用法: python3 patch-b1-write-protect.py /opt/dshs
|
||
import io, os, sys
|
||
root = sys.argv[1] if len(sys.argv) > 1 else '.'
|
||
p = os.path.join(root, 'src/supervisor/orchestrator.ts')
|
||
s = io.open(p, encoding='utf-8').read()
|
||
|
||
# 1) spawnAsUser 增加 role 形参(用于定位 profile 目录名)
|
||
old_sig = """ private async spawnAsUser(
|
||
userId: string,
|
||
command: string,
|
||
args: string[],
|
||
options: { cwd: string; env: Record<string, string> },
|
||
): Promise<{ child: ChildProcess; unit?: string }> {"""
|
||
new_sig = """ private async spawnAsUser(
|
||
userId: string,
|
||
command: string,
|
||
args: string[],
|
||
options: { cwd: string; env: Record<string, string> },
|
||
role: InstanceRole = 'main',
|
||
): Promise<{ child: ChildProcess; unit?: string }> {"""
|
||
assert old_sig in s, 'sig'
|
||
s = s.replace(old_sig, new_sig, 1)
|
||
|
||
# 2) 调用点传入 role
|
||
old_call = """ const { child, unit } = await this.spawnAsUser(userId, command, [...args, ...launchArgs], { cwd: folder, env })"""
|
||
new_call = """ const { child, unit } = await this.spawnAsUser(userId, command, [...args, ...launchArgs], { cwd: folder, env }, role)"""
|
||
assert old_call in s, 'call'
|
||
s = s.replace(old_call, new_call, 1)
|
||
|
||
# 3) 在 --bind root root 之后追加平台策略文件的只读覆盖
|
||
old_bind = """ '--bind', tmpDir, '/tmp',
|
||
'--bind', root, root,
|
||
'--unshare-pid',"""
|
||
new_bind = """ '--bind', tmpDir, '/tmp',
|
||
'--bind', root, root,
|
||
// 2026-09-11(档案 18 v3 收尾 / 档案 17 §P1):平台策略文件在实例内**只读**。
|
||
// 威胁模型:用户可把 <userRoot>/home/profiles/web 加为工作区,随后用 bash 直接改写
|
||
// cordis.patch.yml(去掉平台段 → 恢复全盘 picker)或 package.json(挂任意 bundle)→
|
||
// 属"绕过平台策略"(跨租户仍不成立,uid/bwrap 隔离不变)。
|
||
// 只读三个文件;**不动 cordis.yml**——实测 dsh 启动时会写它(01:16:22),ro 会导致启动异常。
|
||
// 注意:必须放在 '--bind root root' **之后**(bwrap 后写覆盖前写)。
|
||
...(() => {
|
||
const profileDir = join(homeRoot(root), 'profiles', role === 'main' ? 'web' : 'headless')
|
||
const protectedFiles = ['cordis.patch.yml', 'package.json', 'pnpm-lock.yaml']
|
||
const out: string[] = []
|
||
for (const name of protectedFiles) {
|
||
const file = join(profileDir, name)
|
||
out.push('--ro-bind-try', file, file)
|
||
}
|
||
return out
|
||
})(),
|
||
'--unshare-pid',"""
|
||
assert old_bind in s, 'bind'
|
||
s = s.replace(old_bind, new_bind, 1)
|
||
io.open(p, 'w', encoding='utf-8', newline='').write(s)
|
||
print('B1 补丁脚本已生成')
|