回收 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)、记忆修复前备份。
5.1 KiB
5.1 KiB
B 档落地 · 插件建库权限(角色级授权 CREATEDB)
拍板:2026-09-23 用户原话「B」⇒ 建库通路 = B 档(给
dshs角色加CREATEDB)。 状态:✅ 已在 47 落地并通过 11 条验收(2026-09-23 05:4x)。 机位:仅 47(PG 只在 Manager 上;106 无 PG)。 前置件:交付物/建库权限-D档被证伪与修正判定-20260923.md(本档为何取代 D 档)。
一 拍板内容与落地动作
ALTER ROLE dshs CREATEDB; -- 唯一一句 DDL(幂等)
平台侧建库 = 用现有 dshs 连接、单语句执行:
CREATE DATABASE dshs_pl_<pluginId> OWNER dshs ENCODING 'UTF8' TEMPLATE template0;
🔴 必须单语句、不走事务 —— CREATE DATABASE 不能在事务块内(这是 D 档被证伪的同一条 PG 限制,B 档同样受约束,只是不再需要函数封装)。平台侧用 pg 的非事务执行路径(顶层 client.query('CREATE DATABASE …'),⛔ 不要包在 BEGIN/COMMIT 里)。
二 验收(11 条 · 实测读数)
| # | 断言 | 实测 | 判定 |
|---|---|---|---|
| ① | dshs 可建库 |
建库成功 | ✅ |
| ② | 重名建库被拒(幂等靠错误码捕获) | ERROR: database … already exists |
✅ |
| ③ | 新库属主 = dshs |
dshs_pl_bselftest/dshs |
✅ |
| ④ | 可连新库并建表 | create table 成功 |
✅ |
| ⑤ | 新库内对象归 dshs |
表数 = 1 |
✅ |
| ⑥ | 权限精确(须 f|t|f) |
false|true|false |
✅ |
| ⑦ | ⛔ 未拿到 CREATEROLE |
t(= 无该权) |
✅ |
| ⑧ | ⛔ 仍非超级用户 | t(= 非超管) |
✅ |
| ⑨ | 库名白名单 | PG 侧零拦截(建 evil_probe 成功) |
⚠️ 见 §三 |
| ⑩ | 内核表完好 | 13 |
✅ |
| ⑪ | 现有库未损 | 2(dshs + postgres) |
✅ |
| — | 清理后残留 | 0 | 服务 dshs = active |
✅ |
⑥ 是本档的核心断言:只多出 CREATEDB 一位,rolsuper / rolcreaterole 必须保持 false。
三 🔴 本档的已知代价(必须由平台代码兜住)
⑨ 揭示了 B 档的真实缺口:PG 侧没有"只允许建 dshs_pl_* 前缀库"的原生机制 ⇒ 白名单只能靠平台代码自觉。这正是 09-22 否掉 A 档的同一条理由,B 档原样继承。
因此平台侧必须强制三点(缺一即为该档的漏洞面):
- 库名单点生成 —— 库名只能来自
.dsh声明的换算函数(包名去 scope、小写、-→_、前缀dshs_pl_),⛔ 不接受外部传入的任意串。 - 建库前正则复校 —— 照抄 D 档那条:
^dshs_pl_[a-z][a-z0-9_]{0,40}$,不匹配直接 400,⛔ 不把变量拼进 SQL 字符串(用标识符引用或参数化)。 - 每次建库落台账 + 审计 —— 写
plugin_datastores(库名 / 插件 ID / 建库时间 / 结果),使"平台到底建过哪些库"可对账;DROP须 admin 二次确认(DB-03 §六-4)。
四 回滚
ALTER ROLE dshs NOCREATEDB; -- 一句话回滚
影响面:已建好的 dshs_pl_* 库不受影响(属主是 dshs,平台照常建表读写)⇒ 只是新插件建不了库。回滚点 = 平台建库口返回 PG_CREATEDB_MISSING(503)。
五 ⚠️ 必须同步落的文档(回滚/重建时不能漏)
dsh-server-docs/DEPLOY-本部署.mdDB 初始化步骤追加:ALTER ROLE dshs CREATEDB;(标 🔴 用途 = 插件建库;⛔ 不得顺手给CREATEROLE/SUPERUSER)。交接单/插件投放与分库线-①…md——§五 S4-2建库 = admin 显式按钮;§十-D1原文「上传钩子建库」须同步改。DB-03-插件数据面规范.md——§三(谁建库)/§四(何时建)/§六(台账表plugin_datastores)。
六 平台侧代码接口
// src/db/plugin-data/datastore.ts
export function pluginDbNameOf(pkgName: string): string // 纯函数:包名 → dshs_pl_*
export function assertPluginDbName(dbName: string): void // ^dshs_pl_[a-z][a-z0-9_]{0,40}$
export async function createPluginDatabase(client: PoolClient, dbName: string): Promise<'created' | 'exists'>
// 错误映射(供路由层用):
// PG 42P04 duplicate_database ⇒ 'exists'(幂等,非错误)
// PG 42501 权限不足 ⇒ 503 PG_CREATEDB_MISSING(未授 CREATEDB / 已回滚)
// 名称不合白名单 ⇒ 400 invalid_plugin_db_name(平台侧复校,⛔ 不下发到 PG)
错误码变更:D 档的
PLUGIN_DB_HELPER_MISSING随档位作废,恢复为PG_CREATEDB_MISSING。
七 未做(具名原因)
| 项 | 原因 |
|---|---|
| 平台侧代码实现(§六) | 属交接单 §五 S4 的代码面,按用户拍板的「A 档排期」= 等 IM 线整阶段收官后一次性跑完 |
| §五 三份文档回写 | 本轮落点已定,但改交接单/DB-03 会与他线共享文件冲突;按 R9 拉长到同一批执行 |
drop_plugin_database |
⛔ 不在本次拍板范围(DB-03 §六-4 将来一并走) |