关于 db-constraints
用于数据库审计的技能,检查声明式约束与可空性带来的模式正确性风险。它关注必填值、有效范围、唯一身份,以及可能未按预期生效的约束。
主要功能
- 01查找缺失的 NOT NULL 约束
- 02检查域规则是否有 CHECK 约束
- 03识别缺失或区分大小写的唯一性
- 04检测可空列上的 UNIQUE 陷阱
- 05查找未验证的约束
适用场景
- 01审查必需的外键和字段
- 02检查数量、价格或日期规则
- 03审计邮箱或用户名的唯一性
- 04调查软删除表中的重复风险
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ hainrixz/ claude-db --skill db-constraints安装后在 Claude Code 中输入/db-constraints确认已加载。
详细介绍
db-constraints(M5)
约束是数据库保证始终成立的不变量,无论写入该行的是哪个应用、脚本或迁移。没有约束,“这永远成立”就只是一种期望,而非事实。本模块属于 design 轴(Constraints 类别)。它适用于强制执行声明式约束的引擎;文档存储则归入 Validación-schema 类别。
检查内容
- 缺少 NOT NULL:语义上必填的列(指向必需父记录的外键、
email、status、时间戳)被设为可空,允许不完整或无效的行。 - 缺少 CHECK:未强制执行领域规则——
quantity >= 0、price >= 0、status IN (...)、start_date <= end_date、email ~ '@'。应用“验证”了这些规则,但数据库没有。 - 缺少 UNIQUE:自然键(email、username、slug、external_id)没有 UNIQUE 约束,允许出现重复值,导致联接和身份验证出错。
- 大小写不敏感的唯一性(电子邮件):对大小写可能不同的列(例如
email)使用普通UNIQUE,仍会允许[email protected]和[email protected]作为不同的行存在——造成身份重复。应明确指出补救方法:使用citext列类型,或在lower(col)上创建UNIQUE表达式索引(例如CREATE UNIQUE INDEX ON users (lower(email))),让大小写折叠后的值发生冲突。 - 可空 UNIQUE 陷阱:对可空列添加 UNIQUE 约束,而引擎将每个 NULL 视为不同值,导致重复值漏网(例如,用于软删除唯一性的
UNIQUE(user_id, deleted_at)在deleted_at为 NULL 时失效)。建议使用部分/筛选唯一索引或NULLS NOT DISTINCT。 - 约束声明为 NOT VALID / NOCHECK,且从未验证。
轴与严重程度
- 轴:design;严重程度按区间表示,绝不虚构违规数量。
- 缺少 UNIQUE,导致身份验证/自然键允许重复身份:严重程度 4,
fail/warn,置信度directional。 - 可空 UNIQUE 悄然允许重复值:严重程度 4,
warn(不易察觉,影响大)。 - 必填外键/列缺少 NOT NULL:严重程度 3,
warn。 - 已声明的领域规则缺少 CHECK:严重程度 2–3,
warn,fixable: proposed。 - M5 不设严重程度 5 的上限;它会影响 Constraints 类别的取值。
Tier-0 静态检查
通过 scripts/parse-schema.mjs 解析 DDL/快照:列出缺少 NOT NULL 的列;检测缺少 UNIQUE/唯一索引的自然键列名;查找成员列可空的 UNIQUE 约束(可空陷阱);扫描 quantity/price/日期范围列是否缺少 CHECK。对程序源码的解析结果保持为 directional。
Tier-1 验证查询
盘点约束和可空性:
-- $DATABASE_URL, read-only
SELECT c.table_name, c.column_name, c.is_nullable,
tc.constraint_type
FROM information_schema.columns c
LEFT JOIN information_schema.constraint_column_usage ccu
ON ccu.table_name = c.table_name AND ccu.column_name = c.column_name
LEFT JOIN information_schema.table_constraints tc
ON tc.constraint_name = ccu.constraint_name AND tc.constraint_type IN ('UNIQUE','CHECK')
WHERE c.table_schema NOT IN ('pg_catalog','information_schema');
确认可空 UNIQUE 是否确实存在重复值:
SELECT user_id, count(*) FROM memberships WHERE deleted_at IS NULL
GROUP BY user_id HAVING count(*) > 1;
发现项
按照 schema/finding.schema.json 输出。示例:
M5.users.email_no_unique—email没有 UNIQUE 约束;可能存在重复身份(严重程度 4,warn,轴design,fixable: proposed)。M5.memberships.over_nullable_unique—UNIQUE(user_id, deleted_at)允许deleted_at为 NULL 时出现重复值(严重程度 4,warn,轴design)。M5.order_items.quantity_no_check— 没有CHECK (quantity >= 0)(严重程度 3,warn)。M5.events.user_id_nullable— 必填外键列可空(严重程度 3,warn)。 每个发现项:evidence.observed引用列/约束 DDL 原文;verification.reproduce是上文可运行的查询(method: ddl_parse/constraint_check/query_stat);expected_impact按区间表示并标注置信度。
诚实性
- 应用层验证能降低风险,但不能替代数据库约束——多个写入方(作业、管理员脚本、副本)可以绕过应用。应明确说明这一点;不要声称应用验证与数据库约束等效。
- 可空 UNIQUE 陷阱因引擎而异(Postgres 15 之前将 NULL 视为不同值;15 起支持
NULLS NOT DISTINCT)。建议应限定于检测到的引擎/版本,不要泛化。 - 没有 Tier-1 计数时,绝不要声称存在重复值/违规;仅凭静态检查,结论应为
directional。
评论
支持 Markdown