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

1.9 KiB

租户外键完整性审计

目的

RLS 负责控制一行是否可见,但不能保证一条租户内记录引用的父记录也属于同一租户。历史 schema 仍有一批只引用父表 id 的外键,因此上线门禁同时执行:

  • 快速 schema 指纹:生产 readiness 查询 pg_catalog,发现新增、删除、改名、未验证的租户间外键即阻断。
  • 完整数据审计:只在 localtestci 隔离克隆库执行,逐条检查现有数据是否满足租户不变量并输出 JSON 证据。

默认规则是子表与父表 tenant_id 必须一致。当前只有三个显式例外:

  • 平台审计规则允许 tenant_id is null,代表全局规则;租户专属规则必须与告警租户一致。
  • 租户采用公共题库时,源题库可以属于平台租户,但必须是 source_scope='platform'
  • 公共题库通知可以指向平台源题库,同样必须是 source_scope='platform'

新增例外必须同时补业务理由、查询不变量、合同测试和 schema 指纹。不得只更新指纹跳过审计。

执行

隔离库必须已应用全部迁移,并在 app_private.environment_safety 标记为 local/test/ciallow_destructive_tests=true。该命令只读,但会扫描相关业务表,因此沿用破坏性测试确认口令,防止误连生产主库:

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.jsondb.tenant-foreign-key-audit 检查项。