feat(db): 新表授权面收敛机制落地(白名单驱动 · 增量锚定 · fail-closed · 只增不减)
依据:A 侧(wecom-yanxue)裁定 编号 2「准予但需调整」+ R1(裁定件 yanxue-20260928-newtable-grant-surface-impl-plan-ruling.md,md5 272d1a8b4db0db0e9f35f5e62695ae50) 三条开口 (a) 空锚=合法零集 / (b) --anchor-file 载体等价 / (c) drill WARN 不阻断(两条独立分支) 改动面(3 件,全部开发工作树): - 新增 backend/scripts/grant_surface_sync.py:项目侧原型逐字复制 + Δ1/Δ2/Δ3/Δ4 + R1 Δ1 锚语义(未给=缺锚 rc=2 / 空集=合法零集)、Δ2 连接身份与 db_migrate 同口径并拒绝 cma_api、 Δ3 --anchor-file(读 db-migrate-journal 指针件)、Δ4 anchor_source 入 JSON R1-a 同源自证(journal 在册 + status=applied + finished_at 一致 + 目录内最新 -applied) R1-b 未收敛锚累积由 db_migrate.write_anchor_pointer 实现、R1-c 收敛回写 converged_at - db_migrate.py 加性 +2 处:新增 write_anchor_pointer()(原子写 journal/last-anchor.json); cmd_apply 成功/失败两路径各调一次;零变更面未动(列级差异只告警 / create_all 幂等 / --check 不写指针 / --rollback 与 resolve_journal 语义 / JSON 键集) - deploy.sh 加性 1 步 [4b-2/5] 授权面收敛(插在「✓ 结构迁移完成」与「# 5. 重启后端服务」之间): apply 跑 --apply --anchor-file ... --drift-policy warn,rc!=0 ⇒ 打印缺裁定清单 + exit 1 (后端不重启、旧码继续服务);drill 跑 --check,读数原样打印、WARN 不阻断 证据(全部零生产面): - py_compile x3 通过;bash -n deploy.sh 通过(PYTHONPYCACHEPREFIX 隔离,仓内零新增 pyc) - 纯函数用例 11/11(零连库):语句均为 GRANT / 无 REVOKE / 语句表 ⊆ write_tables / 域外权限 SystemExit - 沙箱 S1–S9 回归 9/9 一致(SUMMARY.txt 与项目侧基线逐字节相同 md5 1a697e002a2cba8ae9b5ad9cc71b022d) - 锚/R1 新例 18/18:缺锚/缺件/status=failed/R1-a 四负例均 rc=2 零写入;空锚 rc=0 executed=[] - R1 验收链:发布1 建表 X(∉白名单) ⇒ rc=3 零写入 + 片段 exit 1 ⇒ 不修白名单重跑 ⇒ 仍 rc=3 ⇒ 补白名单 ⇒ rc=0 + X 获授权 + converged_at 落定 ⇒ 三次重跑 executed=[](幂等) - 既有 backend/tests:1509 passed / 0 failed,改前(HEAD 导出树)与改后失败集零差异 边界:本地 commit,零 push / 零部署 / 零重启 / 零连生产库 / 零 DDL-DML-GRANT-REVOKE; 上线(push + 部署 ⇒ 授权面生效)另单另铸 approval ID 且必附 R2 预演 diff(本单不为任何动作铸 ID)
This commit is contained in:
@@ -213,6 +213,8 @@ echo " ✓ 依赖检查完成"
|
||||
# cma-create-all-minpriv-rootfix-20260916:DDL 已从应用启动剥离(CMA_AUTO_CREATE 默认关),
|
||||
# 新模型必须由**有 DDL 权限的账号**在重启前建表;此处失败即中止部署(后端保持旧码运行),
|
||||
# 避免 2026-09-16 那种「启动 create_all 被 cma_api 拒 → 崩溃循环」。
|
||||
# [4b-2] 授权面收敛:与本节同属「重启前特权步」,锚 = 本次 create_all 的 created_tables
|
||||
# (经 journal/last-anchor.json 转交);本步只发 GRANT、从不 REVOKE、缺裁定即中止
|
||||
echo "[4b/5] 数据库结构迁移(特权账号,重启前)..."
|
||||
cd "$DEPLOY_SRC/backend"
|
||||
MIGRATE_ARG="--apply"
|
||||
@@ -226,6 +228,44 @@ fi
|
||||
cd "$DEPLOY_SRC"
|
||||
echo " ✓ 结构迁移完成(幂等;journal: $DEPLOY_SRC/backend/scripts/backups/db-migrate-journal/)"
|
||||
|
||||
# 4b-2. 授权面收敛(白名单驱动 · 增量锚定 · fail-closed · 只增不减)
|
||||
# 背景:新表建表([4b] create_all)不在任何自动授权步内 ⇒ 表在、写权缺 ⇒ 端点 500 / 1142
|
||||
# 锚 = 本次 db_migrate --apply 写出的 journal/last-anchor.json(R1-a 同源自证:锚件引用本次 journal)
|
||||
# 本步只发 GRANT(从不 REVOKE);缺白名单裁定 ⇒ 非零退出、后端不重启、旧码继续服务
|
||||
# 回滚:去掉本步([4b-2/5])即可 —— 本步不建对象、不改表结构、不 REVOKE,不执行即无残留
|
||||
echo "[4b-2/5] 授权面收敛(白名单驱动 · 增量锚定 · fail-closed)..."
|
||||
cd "$DEPLOY_SRC/backend"
|
||||
if [ "$MODE" = "drill" ]; then
|
||||
# drill:只读预检,读数原样打印,WARN 不阻断(与 [4b] 的「只读预检」口径一致)
|
||||
SYNC_RC=0
|
||||
./venv/bin/python3 scripts/grant_surface_sync.py --check \
|
||||
--anchor-file scripts/backups/db-migrate-journal/last-anchor.json || SYNC_RC=$?
|
||||
if [ "$SYNC_RC" -ne 0 ]; then
|
||||
echo " [warn] [4b-2] drill 读数非零 rc=$SYNC_RC(缺裁定/缺锚清单见上方 coverage.missing_caliber)"
|
||||
echo " [warn] 生产 apply 时会据此中止(exit 1,后端不重启);drill 不阻断"
|
||||
fi
|
||||
SYNC_PLAN_RC=0
|
||||
./venv/bin/python3 scripts/grant_surface_sync.py --check || SYNC_PLAN_RC=$?
|
||||
if [ "$SYNC_PLAN_RC" -ne 0 ]; then
|
||||
echo " [warn] [4b-2] drill 全域只读预演 rc=$SYNC_PLAN_RC(见上方 plan/matrix/drift)"
|
||||
else
|
||||
echo " [info] [4b-2] drill 全域只读预演已完成(语句计划与 statements_md5 见上方 plan)"
|
||||
fi
|
||||
else
|
||||
SYNC_RC=0
|
||||
./venv/bin/python3 scripts/grant_surface_sync.py --apply \
|
||||
--anchor-file scripts/backups/db-migrate-journal/last-anchor.json --drift-policy warn \
|
||||
|| SYNC_RC=$?
|
||||
if [ "$SYNC_RC" -ne 0 ]; then
|
||||
echo "❌ [4b-2] 授权面收敛失败 rc=$SYNC_RC → 中止部署(后端未重启,旧码继续服务)"
|
||||
echo " 缺裁定清单见上方 coverage.missing_caliber(未登记白名单的新建表须先走裁定另单)"
|
||||
echo " 回滚: 去掉本步([4b-2/5])即可;本步从不 REVOKE/DROP,不执行即无残留"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
cd "$DEPLOY_SRC"
|
||||
echo " ✓ 授权面收敛完成(只增不减;指针: $DEPLOY_SRC/backend/scripts/backups/db-migrate-journal/last-anchor.json)"
|
||||
|
||||
# 5. 重启后端服务(运行树 = 部署树:幂等改写 unit,改前备份,附一行回滚)
|
||||
echo "[5/5] 重启后端服务..."
|
||||
if [ "$MODE" = "drill" ]; then
|
||||
|
||||
Reference in New Issue
Block a user