Files
gongxue-base/docs/refactor/tenant-foreign-key-audit.md
2026-07-12 19:26:57 +08:00

38 lines
1.9 KiB
Markdown

# 租户外键完整性审计
## 目的
RLS 负责控制一行是否可见,但不能保证一条租户内记录引用的父记录也属于同一租户。历史 schema 仍有一批只引用父表 `id` 的外键,因此上线门禁同时执行:
- 快速 schema 指纹:生产 readiness 查询 `pg_catalog`,发现新增、删除、改名、未验证的租户间外键即阻断。
- 完整数据审计:只在 `local``test``ci` 隔离克隆库执行,逐条检查现有数据是否满足租户不变量并输出 JSON 证据。
默认规则是子表与父表 `tenant_id` 必须一致。当前只有三个显式例外:
- 平台审计规则允许 `tenant_id is null`,代表全局规则;租户专属规则必须与告警租户一致。
- 租户采用公共题库时,源题库可以属于平台租户,但必须是 `source_scope='platform'`
- 公共题库通知可以指向平台源题库,同样必须是 `source_scope='platform'`
新增例外必须同时补业务理由、查询不变量、合同测试和 schema 指纹。不得只更新指纹跳过审计。
## 执行
隔离库必须已应用全部迁移,并在 `app_private.environment_safety` 标记为 `local/test/ci``allow_destructive_tests=true`。该命令只读,但会扫描相关业务表,因此沿用破坏性测试确认口令,防止误连生产主库:
```bash
DATABASE_URL='postgresql://postgres:postgres@127.0.0.1:55432/postgres' \
node scripts/tenant-foreign-key-audit.js \
--confirm=SMOKE_SEED_LOCAL_OR_CI_ONLY \
--write=docs/refactor/launch-artifacts/tenant-foreign-key-audit.json
```
通过条件:
- `schema.schemaMatches=true`
- `schema.unvalidatedRelations=[]`
- `data.auditedRelations` 等于指纹关系数
- `data.invalidRelations=0`
- `status=pass`
生成的 JSON 及 SHA-256 需要写入 `production-launch-evidence.json``db.tenant-foreign-key-audit` 检查项。