用 Splinter 为 Supabase 数据库 Schema 做静态检查:liam 项目 `@liam-hq/db` 的 Lint 集成实战

发布时间:2026/9/18 20:13:00

用 Splinter 为 Supabase 数据库 Schema 做静态检查:liam 项目 `@liam-hq/db` 的 Lint 集成实战 用 Splinter 为 Supabase 数据库 Schema 做静态检查liam 项目liam-hq/db的 Lint 集成实战【免费下载链接】liamAutomatically generates beautiful and easy-to-read ER diagrams from your database.项目地址: https://gitcode.com/GitHub_Trending/li/liam在 liam一个自动从数据库生成美观易读 ER 图的工具这样的项目中Supabase 数据库 schema 的稳定性与安全性直接决定了上层应用的可靠性。本文以 frontend/internal-packages/db/scripts/db-lint/README.md 为核心结合仓库中run-splinter.sh、splinter.sql、package.json 与 database-ci.yml 的源码级实现完整讲解如何在本地与 CI 中运行 Splinter 数据库 lint、如何解读 21 条检查规则以及如何利用调试开关排查问题。读完本文你将能在自己的 Supabase 项目中落地一套规则驱动、CI 强制、可本地复现的 schema 质量防线。Splinter 是什么为什么 liam 需要它Splinter 是 Supabase 官方维护的一套数据库 lint 检查工具它以一段纯 SQL 的形式分发核心逻辑全部写在splinter.sql中通过查询 PostgreSQL 的系统目录pg_catalog来发现 schema 层面的问题覆盖性能与安全两大类主题——例如外键缺少覆盖索引、RLS行级安全未开启、策略引用了可被用户篡改的user_metadata等。liam 的liam-hq/db包以 supabase/ 下的迁移脚本管理 schema任何 schema 缺陷比如忘记给外键加索引、新建表未开 RLS都会在 ER 图生成、API 查询链路上放大。因此该包在scripts/db-lint/目录中内置了 Splinter 集成并把它接入 Pull Request 的 CI 流程让问题在合并前就被拦截。目录中只有三个文件职责清晰文件职责splinter.sql官方 Splinter 规则的完整合集当前文件实际包含 21 条检查README 标注为 15 条run-splinter.sh薄封装脚本执行查询、格式化输出、暴露调试辅助开关README.md使用指南即本文所依据的文档规则集一览21 条检查覆盖性能与安全splinter.sql的头部注释splinter.sql明确标注了其来源为官方 Splinter 仓库、采用 MIT 许可证并以set local search_path 开头避免搜索路径干扰。整个文件是一个大型union all查询每个分支输出统一结构的行字段依次为name、title、level、facing、categories、description、detail、remediation、metadata、cache_key。当前规则集共 21 条按检查级别和类别归纳如下规则名级别类别检查内容unindexed_foreign_keysINFOPERFORMANCE外键约束缺少覆盖索引可能拖慢查询auth_users_exposedERRORSECURITYauth.users通过视图/物化视图暴露给 anon 或 authenticated 角色auth_rls_initplanWARNPERFORMANCERLS 策略中对current_setting()/auth.function()逐行重复求值应改为(select ...)形式no_primary_keyINFOPERFORMANCE表没有主键unused_indexINFOPERFORMANCE索引从未被扫描idx_scan 0可考虑删除multiple_permissive_policiesWARNPERFORMANCE同一角色同一操作存在多条 permissive 策略policy_exists_rls_disabledERRORSECURITY表创建了 RLS 策略但未启用 RLSrls_enabled_no_policyINFOSECURITY表启用了 RLS 但没有任何策略duplicate_indexWARNPERFORMANCE存在两条完全相同的索引定义security_definer_viewERRORSECURITY视图以SECURITY DEFINER定义绕过查询者的权限与 RLSfunction_search_path_mutableWARNSECURITY函数未固定search_path存在搜索路径篡改风险rls_disabled_in_publicERRORSECURITY暴露给 PostgREST 的 schema 中表未启用 RLSextension_in_publicWARNSECURITY扩展被安装到publicschemarls_references_user_metadataERRORSECURITYRLS 策略引用了用户可编辑的 Supabase Authuser_metadatamaterialized_view_in_apiWARNSECURITY物化视图对 anon/authenticated 角色可 SELECT物化视图不支持 RLSforeign_table_in_apiWARNSECURITY外部表暴露在 API 中外部表不遵守 RLSunsupported_reg_typesWARNSECURITY在pg_catalog之外使用reg*类型列会阻碍pg_upgradeinsecure_queue_exposed_in_apiERRORSECURITYpgmq的队列表q_%未开 RLS 且暴露在 API 中table_bloatINFOPERFORMANCE表膨胀超过阈值bloat 70.0且浪费空间 200MBfkey_to_auth_uniqueERRORSECURITY用户自定义外键指向authschema 的 unique 约束extension_versions_outdatedWARNSECURITY扩展版本落后于默认推荐版本几个值得注意的实现细节security_definer_view有 PostgreSQL 版本前提查询中带有substring(pg_catalog.version() from PostgreSQL ([0-9])) 15的判断因为security_invoker选项在 PG 15 才引入。这与 supabase/config.toml 中major_version 15的本地环境设定一致。table_bloat有明确的过滤阈值只有bloat 70.0且raw_waste 200 MB才报告避免噪音splinter.sql。unused_index做了大量排除idx_scan 0且非唯一、非主键、非扩展依赖表防止误报splinter.sql。几乎所有规则都维护了排除名单pg_catalog、auth、storage、extensions等系统/托管 schema 一律跳过聚焦用户自己的 schema。每条规则都携带remediation修复指引字段运行脚本会将其打印出来例如fkey_to_auth_unique的修复建议是删除引用 auth schema 的外键约束table_bloat则提示vacuum full会带来停机时间、并建议调整 autovacuum 参数。本地运行三条命令打通README 给出的本地运行方式如下在frontend/internal-packages/db目录下cd frontend/internal-packages/db pnpm supabase:start # 启动本地 Supabase 栈 SPLINTER_DEBUG1 pnpm db:lint # DATABASE_URL 默认指向本地栈 pnpm supabase:stop # 可选结束后关闭栈这三个命令分别对应 package.json 中的supabase:start、supabase:stop与db:lint脚本。关键点在于db:lint脚本的完整定义db:lint: bash -lc DATABASE_URL${DATABASE_URL:-postgresql://postgres:postgreslocalhost:54322/postgres} ./scripts/db-lint/run-splinter.sh也就是说即使你不显式设置DATABASE_URL脚本也会回退到本地 Supabase 栈的连接串localhost:54322与 supabase/config.toml 中[db] port 54322一致。如果你希望检查其他数据库实例只需覆盖环境变量DATABASE_URLpostgresql://user:passwordhost:port/dbname pnpm db:lint如果你在 monorepo 工作区根目录可以用 pnpm 的 filter 语法直接对liam-hq/db包执行SPLINTER_DEBUG1 pnpm -F liam-hq/db db:lint包装脚本内部run-splinter.sh的执行流水线run-splinter.shrun-splinter.sh是理解整个 lint 流程的最佳入口它的执行流水线如下前置校验以set -e开头先检查DATABASE_URL是否设置、splinter.sql是否存在缺失即红色报错退出run-splinter.sh。执行查询将splinter.sql全文作为一条查询交给psql使用-t -A -F$\t输出无表头、以 Tab 分隔的结果临时写入文件run-splinter.sh。退出码处理psql非零退出时输出原始错误并退出否则继续。问题计数用awk -F$\t $1 ! 统计第一列规则名非空的行数作为问题总数run-splinter.sh。分级渲染逐行按level字段分流——ERROR红色、WARN黄色、INFO蓝色打印[级别] 标题、detail详情以及可选的 Remediation修复指引run-splinter.sh。汇总与退出末尾输出 Errors / Warnings / Info 三项计数只要任一级别存在问题就以exit 1失败run-splinter.sh。这里体现了该项目的一个关键策略ERROR、WARN、INFO 一律视为失败。这不是脚本的默认行为而是仓库有意的严格选择——README 明确说明Currently, ERROR, WARN, and INFO findings all fail the job and block the build。调试辅助SPLINTER_DEBUG1能告诉你什么当结果异常比如输出被截断、解析错位、psql 报错但信息不够时打开调试开关SPLINTER_DEBUG1 pnpm -F liam-hq/db db:lint脚本会额外打印四类信息run-splinter.sh原始输出的总行数wc -l前 5 行原文第一行的十六进制转储od -An -tx1用于排查 Tab 分隔符、不可见字符等编码问题psql的退出状态码。之所以需要 hex dump是因为脚本依赖 Tab 分隔符做字段解析任何混入的空格、换行或编码问题都会让渲染错乱调试模式可以在 CI 与本地之间做快速对照。CI 集成数据库质量门禁Splinter 的 CI 入口是 .github/workflows/database-ci.yml。该工作流的触发条件覆盖三种场景PR 触发当 PR 改动frontend/internal-packages/db/**或工作流文件本身时运行merge_group合并队列merge queue场景workflow_dispatch支持手动触发。Run Splinter Lint步骤database-ci.yml的执行内容与本地完全一致- name: Run Splinter Lint run: pnpm -F liam-hq/db db:lint env: DATABASE_URL: postgresql://postgres:postgreslocalhost:54322/postgres SPLINTER_DEBUG: 1该 job 同时承担了 PGTap 数据库测试supabase test db整体流程是actions/checkout→supabase/setup-cli→supabase start启动本地栈 →pnpm-setup→ 运行 Splinter lint → 加载setup-testing.sql→ 运行 PGTap 测试。也就是说lint 与测试共享同一个本地 Supabase 实例任何 ERROR/WARN/INFO 发现都会让 job 失败、阻塞 PR 合并。扩展与维护如何增删规则run-splinter.sh的输出解析对字段顺序是敏感的如果你基于此集成扩展自己的规则需要遵守约定在splinter.sql的union all中追加一个select分支输出顺序必须与既有规则一致name, title, level, facing, categories, description, detail, remediation, metadata, cache_keylevel必须是ERROR/WARN/INFO之一脚本的case分支与配色映射依赖它run-splinter.shremediation允许为null脚本会跳过null值的打印metadata使用jsonb_build_object构造便于机器消费的结构化信息cache_key建议用规则名_对象标识的格式拼接保证每个问题实例可去重、可追踪。若想临时跳过某条规则也可以直接编辑splinter.sql中对应分支但要注意保持search_path 的设置避免依赖会话级搜索路径导致结果漂移。小结liam 在liam-hq/db中落地了一套小而完整的数据库 lint 方案以官方 Splinter 的纯 SQL 规则集为检查引擎用一个 120 行左右的 Bash 脚本完成执行、分级渲染与退出码控制再通过 pnpm 脚本与 GitHub Actions 实现本地一键复现、CI 强制拦截。对任何以 Supabase/PostgreSQL 为存储、且希望把 schema 质量前置到开发流程中的项目来说这套组合splinter.sql run-splinter.sh database-ci.yml都是可以直接借鉴的范本。【免费下载链接】liamAutomatically generates beautiful and easy-to-read ER diagrams from your database.项目地址: https://gitcode.com/GitHub_Trending/li/liam创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/18 20:13:00

EGM96模型校正DEM高程基准:从原理到实操的完整指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/18 21:13:03

球面邻域匹配度:量化打车难的时空诊断模型

简介:本资源是一份面向数学建模初学者与竞赛参与者的实战型分析报告,聚焦“互联网”背景下城市出租车资源配置优化这一典型交通管理问题,旨在通过数据建模解决“打车难”这一现实痛点。报告基于2015年成都真实时空数据,构建了以“…

2026/9/18 21:13:03

变压器绕组变形试验详解:从FRA曲线到Python量化诊断

简介:变压器绕组变形试验培训PPT课件是一份面向变电检修、运维及电气试验人员的专业培训资源,针对110kV及以上电力变压器绕组变形检测方法进行了系统梳理。包内共1个PPT,单份课件体积仅707KB,方便直接下载使用。课件共37页&#x…

2026/9/18 21:13:03

RAG系统工程实战:从检索增强到可信可溯的生产级落地

1. 这不是“加个检索”那么简单:RAG早已脱离玩具阶段,进入系统工程深水区你搜“RAG实战”,刷出来的90%内容还在教你怎么用LangChain加载PDF、调个OpenAI API、跑通一个能回答“公司年报里提到多少次‘数字化转型’”的demo。这就像十年前教人…

2026/9/18 21:13:03

中国地面气候日值数据集V3.0处理指南:缺测值与格式陷阱详解

干过中国地面气候日值数据集(V3.0)的人,多少都经历过这种崩溃瞬间:明明从数据网下载了标准化产品,跑出来的气温曲线却直接飙到三千多摄氏度,降水序列里无缘无故出现一条四位数毫米的“极端暴雨”。我最早处理这批数据的时候&#…

2026/9/18 21:08:03

企业数智库建设:四层数据链路、KPI规则与知识图谱落地

简介:面向企业高层管理者、技术负责人与数字化项目骨干的《企业数智库建设指南》PDF文档,聚焦知识驱动的智能交互如何提升运营效率与决策科学性。内容从数智库内核与实现路径切入,梳理信息化提供客观数据、数字化构建实时业务模型、智能化借助…

2026/9/18 14:13:01

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/18 0:01:09

Google Colab 实战:运行模型、数据加载与报错排查

1. 为什么我劝你先搞懂 Colab 的运行模型1.1 Colab 到底是什么,跟本地跑代码差在哪Google Colab 简单说就是一台跑在浏览器里的 Linux 虚拟机,你打开一个 Notebook,背后就连上了一台带 GPU 的远程机器。你在单元格里敲的每一行 Python&#x…

2026/9/18 0:01:09

C语言数据类型与表达式详解

1. C语言数据与数据类型概述在C语言编程中,数据是程序处理的核心对象。理解数据的分类和特性是掌握C语言的基础。C语言中的数据主要分为四大类:常量、变量、表达式和函数。这些数据类型构成了C语言程序的基本元素,每种类型都有其独特的特性和…

2026/9/18 0:01:09

SQL时间字段指定时间段查询:区间语义、索引与时区避坑

上周排查一个线上问题&#xff0c;用户反馈"昨天的订单一条都没查到"&#xff0c;但数据库里明明躺着两千多条。最后定位下来&#xff0c;不是数据丢了&#xff0c;也不是接口挂了&#xff0c;而是那个查询条件把时间段写成了> 2024-05-20 00:00:00 AND < 2024…

2026/9/18 14:13:03

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行&#xff0c;Type-C接口算是典型的“看着简单&#xff0c;做起来全坑”的东西。光引脚就24个&#xff0c;高低速信号、电源、控制线全部塞在一个小小的连接器里&#xff0c;如果PCB布局不做规划&#xff0c;打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/18 14:13:02

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/18 14:13:02

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码