habinrahman/rls-inspector

GitHub: habinrahman/rls-inspector

Supabase 行级安全(RLS)策略的可视化调试工具,自动检测常见策略配置错误并生成可复制粘贴的 SQL 修复方案。

Stars: 0 | Forks: 0

Setup time React 18 Vite 5 Tailwind CSS Supabase MIT License CI Tests

RLS Inspector

Supabase 行级安全 (RLS) 策略可视化调试工具。
列出表上的每一个策略。暴露缺失的 WITH CHECK 子句、过度宽松的规则以及常见的安全错误。提供可直接复制粘贴的 SQL 修复方案。

纯客户端 —— 凭据绝不会离开您的浏览器。零后端。零遥测。

## 为什么开发此工具 本工具主要解决以下三个痛点: | # | 问题 | 导致的后果 | |---|---------|-------------| | 1 | **`permission denied for table foo`** | Supabase 最常见的错误日志 —— 它不会告诉您 N 个策略中到底是*哪一个*拒绝了查询,以及为什么。 | | 2 | **SQL Editor 绕过 RLS** | 在 Supabase Dashboard 编辑器中正常运行的查询,在生产环境中会静默失败,因为编辑器使用 `postgres` 角色运行。 | | 3 | **AI 生成的策略存在隐蔽错误** | 来自 Lovable、Bolt.new 或 Cursor 的 `@supabase` 集成的策略,经常在上线时带有缺失的 `WITH CHECK`、`USING (true)` 或被遗忘的角色授权 —— 这些故障在几天后会表现为令人费解的 "permission denied"。 | RLS Inspector 直接从 `pg_policies` 读取策略元数据,对其进行标准化,并在几秒钟内(而不是几小时内)呈现人工审查会发现的那些问题。 ## 预览 ![RLS Inspector 演示](https://static.pigsec.cn/wp-content/uploads/repos/cas/f5/f57c371c3585a1b84454dae7f028151a98d3270a0807472c618b6dfa2a7dfc45.gif)

使用模拟的 Supabase RPC 录制 —— 无需实际项目。重新录制:npm run record:demo

ASCII 预览(静态) ``` ┌──────────────────────────────────────────────────────────────────────────┐ │ RLS Inspector · Supabase debugger ● nwkxop…supabase.co │ ├──────────────────────────────────────────────────────────────────────────┤ │ [Table: posts — 3 policies] · [Test as: alice@…] · [Analyze] │ │ │ │ posts 3 POLICIES · 0 ROWS · 1 SELECT 1 INSERT │ │ ────────────────────────────────────────────────────────────────────── │ │ │ INSERT · Users can insert their own posts permissive │ │ │ WITH CHECK (auth.uid() = user_id) │ │ │ │ │ SELECT · Users can view their own posts permissive │ │ │ USING (auth.uid() = user_id) │ │ │ │ │ UPDATE · Anyone can update ▲ overly permissive │ │ │ USING true unrestricted│ │ │ WITH CHECK — not set — │ │ │ │ Findings 1 critical · 1 warning│ │ ▌ Critical · UPDATE policy missing WITH CHECK │ │ Suggested fix: ALTER POLICY "Anyone can update" ON "posts" │ │ WITH CHECK (auth.uid() = user_id); [Copy SQL] │ └──────────────────────────────────────────────────────────────────────────┘ ```
## 功能 ### 静态分析引擎 分析引擎(`lib/analysis.js`)对每个策略运行六项确定性检查,并始终输出四项最佳实践建议: | # | 检查项 | 严重性 | 触发条件 | 重要性说明 | |---|-------|----------|-------------------|-------------| | 1 | 缺失 `WITH CHECK` | **严重** | `INSERT` 或 `UPDATE` 策略没有 `with_check` 子句 | 用户可以写入违反策略预期不变性的数据行 —— 这是 Supabase RLS 最常见的 bug。 | | 2 | 过度宽松 | 警告 | `USING` 子句的字面量完全等于 `true` 或 `TRUE` | 允许所有人执行该操作。除非是刻意设计的公开表,否则这几乎总是错误的。 | | 3 | 缺失 `SELECT` 覆盖 | 警告 | 表具有 `INSERT`/`UPDATE` 策略,但没有 `SELECT` 策略 | 用户可以写入自己无法读取的数据 —— 会表现为“保存后数据消失”的 bug。 | | 4 | 复杂条件 | 警告 | `USING` 子句包含 `function`、`array` 或 `json` 关键字 | 可能会跳过索引;在大表上需要标记以进行 `EXPLAIN` 审查。 | | 5 | 使用了 `auth.role()` | 警告 | `USING` 子句引用了 `auth.role()` | 提醒确保对 role 列建立索引以提高性能。 | | 6 | 缺失 auth 上下文 | 警告 | 非 `SELECT` 策略没有引用 `auth.uid()`、`auth.role()`、`auth.email()`、`current_user` 或 `session_user` —— 且 `USING` 不为 `true` | 策略无法区分不同用户 —— 统一地允许或拒绝访问。 | **最佳实践建议**(始终输出): | 建议 | 描述 | |------------|-------------| | 使用不同的用户角色测试 | 策略会根据每个用户的 auth 上下文和角色表现出不同的行为。 | | 监控策略拒绝情况 | 启用 PostgreSQL 日志记录,以查看生产环境中哪些策略正在拒绝查询。 | | 记录您的策略 | 为 RLS 策略添加注释,解释其业务逻辑。 | | 定期安全审计 | 随着应用的发展,每季度审查一次 RLS 策略。 | 每个严重发现都包含一个**可直接复制粘贴的 `ALTER POLICY`** 语句,该语句带有正确引用的 Postgres 标识符(通过 `format(%I)` 样式的引用)和合理的 `WITH CHECK` 模板。 ### 策略可视化 策略被渲染为带有颜色编码的卡片,并根据操作类型在左侧边缘显示条纹: | 命令 | 颜色 | 图标 | |---------|-------|------| | `SELECT` | 蓝色 | 眼睛 | | `INSERT` | 翡翠绿 | 加号 | | `UPDATE` | 琥珀色 | 铅笔 | | `DELETE` | 红色 | 垃圾桶 | | `ALL` | 紫色 | 数据库 | 每张卡片显示策略名称、宽容/限制徽章、应用的角色、`USING` 子句、`WITH CHECK` 子句(或“未设置”警告),以及检测到的问题的内联严重性徽章。 ### 附加功能 - **优雅的辅助程序检测** —— 如果缺少 SQL 辅助函数,UI 会显示明确的“运行 `setup_supabase_functions.sql`”消息,而不是晦涩的 PostgREST 错误(检测 Postgres 错误代码 `42883`) - **备用用户** —— 当 `get_auth_users` RPC 失败时,会注入两个占位用户,以便分析仍能继续进行 - **键盘快捷键** —— `Cmd/Ctrl + K` 聚焦表选择器 - **剪贴板复制** —— 建议的 SQL 修复带有一键复制按钮 - **加载骨架屏** —— 数据获取期间的微光动画 - **仅深色模式** —— 专为开发者工具使用而设计(color-scheme: dark,`#09090b` 背景) ## 架构 ### 系统概览 ``` flowchart LR subgraph Browser["Browser (entire application)"] UI["React UI
ConnectionForm · AnalysisToolbar
PolicyVisualizer · AnalysisPanel"] Engine["lib/analysis.js
detectIssues()"] SDK["@supabase/supabase-js"] UI --> Engine UI --> SDK end subgraph Supabase["Your Supabase Project"] PostgREST["PostgREST
(anon role)"] RPCs["4 SECURITY DEFINER RPCs
setup_supabase_functions.sql"] Catalog["pg_class · pg_policies
auth.users · public.*"] PostgREST --> RPCs --> Catalog end SDK -- "anon key (HTTPS)" --> PostgREST style Browser fill:#18181b,stroke:#3f3f46,color:#fafafa style Supabase fill:#064e3b,stroke:#10b981,color:#fafafa ``` ### 数据流 ``` sequenceDiagram participant User participant UI as React UI participant SDK as supabase-js participant PG as PostgREST participant SQL as SQL Helpers participant Cat as pg_catalogs User->>UI: Enter URL + anon key UI->>SDK: createClient(url, anonKey) SDK->>PG: RPC get_all_tables() PG->>SQL: SECURITY DEFINER call SQL->>Cat: Query pg_class + pg_policies Cat-->>SQL: Table list + RLS state SQL-->>PG: JSON response PG-->>SDK: Tables array SDK-->>UI: Populate table picker User->>UI: Select table UI->>SDK: RPC get_auth_users() SDK->>PG: Fetch users PG->>SQL: Query auth.users SQL-->>PG: User list (max 200) PG-->>SDK: Users array SDK-->>UI: Populate user picker User->>UI: Click Analyze UI->>SDK: RPC get_table_policies(table) + get_table_row_count(table) SDK->>PG: Parallel RPC calls PG->>SQL: Fetch policies + count SQL-->>PG: Policy data + row count PG-->>SDK: Results SDK-->>UI: Raw policy data UI->>UI: detectIssues(policies, tableName) UI-->>User: Render PolicyVisualizer + AnalysisPanel ``` ### 组件架构 ``` graph TD Main["main.jsx
ReactDOM entry"] App["App.jsx — RLSInspector
Top-level orchestrator"] Main --> App subgraph "App.jsx inline components" TopBar["TopBar
Sticky header + connection indicator"] Logo["Logo
Gradient brand mark"] DV["DisconnectedView
Hero + ConnectionForm wrapper"] CV["ConnectedView
Toolbar + results layout"] EA["ErrorAlert
Dismissible error banner"] PS["PoliciesSkeleton
Loading shimmer"] ES["EmptyState
Contextual placeholder"] Footer["Footer
Privacy statement + links"] end subgraph "src/components/" CF["ConnectionForm.jsx
URL + anon key form"] AT["AnalysisToolbar.jsx
Table/user pickers + Analyze CTA"] PV["PolicyVisualizer.jsx
Color-coded policy cards"] AP["AnalysisPanel.jsx
Findings + SQL fix suggestions"] end subgraph "src/lib/" AN["analysis.js
detectIssues() · 6 checks + 4 suggestions"] end App --> TopBar App --> DV App --> CV App --> Footer TopBar --> Logo DV --> CF DV --> EA CV --> AT CV --> PV CV --> AP CV --> EA CV --> PS CV --> ES AP --> AN style Main fill:#18181b,stroke:#3f3f46,color:#fafafa style App fill:#18181b,stroke:#10b981,color:#fafafa ``` ## 项目结构 ``` . ├── index.html # Vite HTML entry — Inter + JetBrains Mono via Google Fonts ├── package.json # 4 runtime deps, 5 dev deps, ES modules ├── vite.config.js # React plugin, port 5173, auto-open ├── tailwind.config.js # Inter / JetBrains Mono / 6-step type scale ├── postcss.config.js # tailwindcss + autoprefixer ├── setup_supabase_functions.sql # Server-side contract: 4 idempotent RPCs ├── LICENSE # MIT └── src/ ├── main.jsx # ReactDOM.createRoot entry point ├── index.css # Tailwind layers + scrollbar + animations ├── App.jsx # Orchestrator (state, data fetching, layout) │ # inline: TopBar, Logo, DisconnectedView, │ # ConnectedView, ErrorAlert, PoliciesSkeleton, │ # EmptyState, Footer ├── components/ │ ├── ConnectionForm.jsx # URL + anon key card with validation │ ├── AnalysisToolbar.jsx # Table picker, user picker, Analyze button │ │ # inline: Picker │ ├── PolicyVisualizer.jsx # Policy cards with color-coded stripes │ │ # inline: Stat, PolicyCard, CodeBlock, Badge │ └── AnalysisPanel.jsx # Findings panel with copy-pasteable SQL fixes │ # inline: Pill, Finding, SuggestedFix └── lib/ └── analysis.js # detectIssues() — 6 rules, 4 suggestions # also exports: testPolicyCondition(), # extractColumnsFromCondition() (unused — future) ``` ## 技术栈 | 层级 | 选择 | 版本 | 理由 | |-------|--------|---------|-----------| | 框架 | React | ^18.2.0 | 快速 HMR,零配置,单页工具不需要 SSR。 | | 打包工具 | Vite | ^5.0.8 | 即时开发服务器,优化的构建,原生 ESM。 | | 样式 | Tailwind CSS | ^3.4.1 | Token 作为类;不会出现并行设计系统文件导致的不一致问题。 | | 图标 | lucide-react | ^0.292.0 | 一致的 24×24 线条图标;替换所有 Emoji 图标。 | | 字体 | Inter (UI) + JetBrains Mono (代码) | Google Fonts CDN | 经典的开发工具双字体搭配。Inter 使用 OpenType 特性 `cv02`、`cv03`、`cv04`、`cv11`。 | | 数据 | @supabase/supabase-js | ^2.38.4 | 所有 Supabase RPC 调用的单一依赖项。无需 auth 流程 —— 仅使用 anon key。 | | PostCSS | postcss + autoprefixer | ^8.4.31 / ^10.4.16 | Tailwind CSS 处理流水线所需。 | **总依赖数:** 4 个运行时,5 个开发。无状态库,无 UI 库,无动画库,无路由。 ## SQL 辅助程序契约 `anon` 角色默认无法通过 PostgREST 读取 `pg_policies`、`pg_class` 或 `auth.users`。RLS Inspector 附带 [`setup_supabase_functions.sql`](./setup_supabase_functions.sql) —— 一个幂等的 SQL 文件,用于安装四个 `SECURITY DEFINER` 函数: | 函数 | 返回值 | 用途 | |----------|---------|---------| | `get_all_tables()` | `(name TEXT, rls_enabled BOOLEAN, policy_count BIGINT)` | 列出 `public` schema 中所有表及其 RLS 状态。填充表选择器。 | | `get_table_policies(table_name TEXT)` | `(policyname TEXT, cmd TEXT, qual TEXT, with_check TEXT, roles TEXT[], permissive TEXT)` | 返回表上的每个 RLS 策略。这是可视化工具的核心数据源。 | | `get_auth_users(max_count INT DEFAULT 50)` | `(id UUID, email TEXT)` | 来自 `auth.users` 的近期用户。服务端限制最多 200 行。 | | `get_table_row_count(table_name TEXT)` | `BIGINT` | 总行数(绕过 RLS)。用作 “X / Y 行” 的分母。 | ### SQL 安全模式 每个函数都实现了以下安全强化措施: ``` graph TD A["SECURITY DEFINER"] --> B["Runs as function owner
(bypasses RLS for catalog reads)"] C["SET search_path = pg_catalog, public"] --> D["Prevents search_path hijacking"] E["STABLE volatility"] --> F["Optimizer knows results
don't change within a transaction"] G["REVOKE ALL FROM PUBLIC"] --> H["No implicit access"] I["GRANT EXECUTE TO anon, authenticated"] --> J["Explicit least-privilege grant"] K["format(%I) in get_table_row_count"] --> L["SQL injection protection
via identifier quoting"] M["EXCEPTION WHEN OTHERS"] --> N["Graceful NULL return
on any error"] style A fill:#064e3b,stroke:#10b981,color:#fafafa style C fill:#064e3b,stroke:#10b981,color:#fafafa style E fill:#064e3b,stroke:#10b981,color:#fafafa style G fill:#064e3b,stroke:#10b981,color:#fafafa style I fill:#064e3b,stroke:#10b981,color:#fafafa style K fill:#064e3b,stroke:#10b981,color:#fafafa style M fill:#064e3b,stroke:#10b981,color:#fafafa ``` ### 安全声明 ### 卸载 ``` DROP FUNCTION IF EXISTS public.get_all_tables(); DROP FUNCTION IF EXISTS public.get_table_policies(TEXT); DROP FUNCTION IF EXISTS public.get_auth_users(INT); DROP FUNCTION IF EXISTS public.get_table_row_count(TEXT); ``` ## 快速开始 ### 1. 克隆并安装 ``` git clone https://github.com/habinrahman/rls-inspector.git cd rls-inspector npm install npm run dev ``` 开发服务器将在 `http://localhost:5173` 启动并自动打开。 ### 2. 在您的 Supabase 项目中安装 SQL 辅助程序 1. 打开 [Supabase dashboard](https://supabase.com/dashboard) 中的 **SQL Editor**。 2. 粘贴 [`setup_supabase_functions.sql`](./setup_supabase_functions.sql) 的全部内容并点击 **Run**。它是幂等的 —— 可安全地重新运行。 3. 验证: SELECT * FROM public.get_all_tables() LIMIT 5; ### 3. 连接 RLS Inspector 1. 进入 Supabase dashboard 的 **Settings → API**。 2. 复制 **Project URL** 和 **anon (public)** key。 3. 将两者粘贴到 `http://localhost:5173` 的连接表单中。 4. 点击 **Connect**。 ### 4. 分析 1. 从下拉菜单中选择一个表(显示 RLS 状态和策略数)。 2. 从 `auth.users` 中选择一个用户(或使用自动生成的占位符)。 3. 点击 **Analyze** 获取策略并运行全部六项静态检查。 **总设置时间:约 5 分钟。** ## 开发 ``` npm run dev # Vite dev server on :5173 with HMR, auto-open npm run build # Production bundle to dist/ npm run preview # Serve production build on :4173 npm test # Vitest unit tests for lib/analysis.js npm run test:watch # Watch mode ``` ### 环境变量 **无需任何变量。** 凭据是在运行时通过 UI 输入的。开发或生产构建均不需要 `.env` 文件。 ### 设计系统 Tailwind 配置定义了自定义的 6 级排版比例: | Token | 大小 | 行高 | 字重 | 用途 | |-------|------|-------------|--------|-----| | `display` | 28px | 34px | 700 | 页面标题 | | `h2` | 18px | 24px | 600 | 章节标题 | | `h3` | 14px | 20px | 600 | 卡片标题 | | `body` | 14px | 20px | — | 默认文本 | | `small` | 13px | 18px | — | 辅助文本 | | `micro` | 11px | 14px | 600 | 标签、徽章 | ## 部署 RLS Inspector 是一个静态 SPA。不需要服务端运行时。 ### Vercel(推荐) ``` npm install -g vercel vercel --prod ``` 或者使用直接调用 `vercel` 的 `npm run deploy`。 ### 任意静态主机 | 设置 | 值 | |---------|-------| | 构建命令 | `npm run build` | | 输出目录 | `dist/` | | 环境变量 | 无 | 适用于 **Netlify**、**Cloudflare Pages**、**GitHub Pages**、**Render** 或任何静态文件服务器。 ## 安全模型 ``` flowchart TB subgraph "Security Boundary: Browser" A["User enters URL + anon key"] --> B["Held in React useState()"] B --> C["Lost on page refresh"] B --> D["Never written to localStorage"] B --> E["Never sent to any third party"] B --> F["supabase-js connects directly
to user's own Supabase project"] end subgraph "Security Boundary: Supabase" G["PostgREST validates anon key"] H["4 SECURITY DEFINER RPCs"] I["Read-only catalog queries"] end F --> G --> H --> I style A fill:#18181b,stroke:#3f3f46,color:#fafafa style G fill:#064e3b,stroke:#10b981,color:#fafafa ``` **此设计的安全特性:** | 属性 | 实现 | |----------|---------------| | 无后端 | 所有处理均在浏览器中完成 | | 不存储凭据 | URL + anon key 存在于 React state 中,刷新后即丢失 | | 无遥测 | 零分析、零跟踪、零外部调用 | | 无写操作 | 所有四个 SQL 辅助程序均为只读 | | 注入安全 | `get_table_row_count` 使用 `format(%I)` 进行标识符引用 | | 受限访问 | RPC 仅读取 `public` schema 元数据 + 有边界的 `auth.users` | | 幂等安装 | SQL 文件使用 `CREATE OR REPLACE`,可安全地重新运行 | | 干净卸载 | SQL 文件底部有注释掉的 `DROP` 块 | **已知局限(与安全相关):** - URL 验证仅接受 `*.supabase.co` 域名 —— 客户端正则表达式目前会拒绝自托管的 Supabase 实例或自定义域名 - 未配置 Content Security Policy 标头 - 客端对 RPC 调用没有速率限制 - 没有 React Error Boundary —— 未处理的异常会导致应用白屏 ## 工程决策 ### 为什么没有状态管理库? 整个应用的状态存在于 `App.jsx` 中,通过 11 次 `useState` 调用。状态图是一个简单的线性流水线:连接 → 选择表 → 选择用户 → 分析 → 显示结果。没有横切状态关注点,兄弟组件之间没有共享状态,也没有需要跨导航保留的状态。添加 Redux、Zustand 或 Jotai 只会增加包大小和复杂性,而没有任何好处。 ### 为什么没有路由? RLS Inspector 是一个单屏工具。“未连接”和“已连接”状态是同一组件内的条件渲染,而不是单独的路由。路由会增加依赖项,需要 URL 同步逻辑,并引入关于深层链接到不应被添加书签的连接状态的边缘情况(因为凭据没有被持久化)。 ### 为什么用 `SECURITY DEFINER` 而不是 `SECURITY INVOKER`? PostgREST 连接使用 `anon` 角色,该角色无权访问 `pg_class`、`pg_policies` 或 `auth.users`。`SECURITY DEFINER` 以函数所有者(通常是 `postgres`)的身份执行函数,从而绕过这些限制。权衡之处在于这些函数具有提升的权限 —— 通过将它们设为只读、显式设置 `search_path` 以及将授权范围限定为 `anon` + `authenticated` 来缓解此问题。 ### 为什么使用静态分析而不是运行时评估? 仅凭 `anon` key,该工具无法为特定的 `auth.uid()` 铸造 JWT 并以该用户身份执行策略。真正的模拟需要项目的 JWT 密钥。“以用户 X 身份测试”选择器为结构分析提供了上下文,但实际上并不会在运行时评估 `(auth.uid() = user_id)`。这是一种刻意的设计约束 —— 该工具在不要求访问密钥的情况下也非常实用。 ### 为什么有 4 个运行时依赖? | 决策 | 被否决的替代方案 | 原因 | |----------|---------------------|--------| | 仅用 React(无元框架) | Next.js, Remix | 不需要 SSR、路由或 API 路由。使用元框架纯属额外开销。 | | 仅用 Tailwind(无 UI 库) | shadcn/ui, Radix | 该应用约有 12 个独特的 UI 元素。组件库会增加依赖,却不能节省可观的开发时间。 | | lucide-react(无 Emoji) | Emoji 图标,Heroicons | 所有图标的描边粗细保持一致。Emoji 在不同操作系统上的呈现效果不同。 | | supabase-js(无原生 fetch) | fetch + 手动 JWT | supabase-js 负责处理 PostgREST RPC 调用约定、错误标准化和重试逻辑。 | ## 已知局限 明确声明这些是为了建立信任: | 局限性 | 影响 | 变通方法 | |------------|--------|------------| | **无法模拟用户** | “以用户 X 身份测试”仅为结构性分析 —— 不会在运行时评估 `auth.uid()` | 实现真正的模拟需要 JWT 密钥(参见路线图) | | **无 `EXPLAIN` 分析** | 性能分析结果是基于模式的(`USING` 子句中的关键字),而不是基于查询计划的 | 在 SQL Editor 中手动运行 `EXPLAIN ANALYZE` | | **无角色授权检查** | 命名了未授权角色的策略在结构上看起来会“没问题” | 手动检查 `pg_roles` | | **仅限 `public` schema** | 内部 schema 和非公开表被排除在外 | 修改 `get_all_tables()` 以支持其他 schema | | **仅限 `*.supabase.co` URL** | 客户端验证会拒绝自托管的 Supabase 或自定义域名 | 修改 `ConnectionForm.jsx` 中的正则表达式 | | **`testPolicyCondition()` 和 `extractColumnsFromCondition()`** | 从 `analysis.js` 导出,但尚未接入 UI —— 为未来的运行时分析保留的脚手架 | 尚未集成 | ## 路线图 | 想法 | 形式 | 复杂度 | |------|-------|------------| | **真实用户模拟** | 使用项目的 JWT 密钥(输入一次,从不存储)签署 JWT,并运行 `SELECT` 以查看用户可以读取的实际行 | 高 | | **`EXPLAIN ANALYZE` 集成** | 呈现查询计划并标记大表上的顺序扫描 | 中 | | **快照差异对比** | 粘贴昨天的 `pg_dump --schema-only` 和今天的;标记每个发生更改的策略 | 中 | | **Markdown 审计导出** | 一键生成用于 SOC-2 / HIPAA 文档的“策略审计报告” | 低 | | **多 schema 支持** | 移除 `WHERE schemaname = 'public'` 约束,添加一个 schema 选择器 | 低 | | **测试套件** | 通过 Vitest 为 `analysis.js` 提供单元测试 | ✅ 完成 | | **CI/CD 流水线** | 使用 GitHub Actions 进行测试、构建和审计 | ✅ 完成 | | **自托管 Supabase 支持** | 放宽 URL 验证正则表达式以接受自定义域名 | 低 | 欢迎对以上任何项目提交 PR。 ## 常见问题
输入我的 anon key 安全吗? anon key 是**设计为公开的** —— 它包含在前端代码中。RLS Inspector 仅通过 HTTPS 将其发送到**您自己的** Supabase 项目。凭据存在于 React state 中,并在刷新后清除。它们永远不会被发送到任何第三方服务器。
为什么我需要 setup_supabase_functions.sql? `anon` 角色默认无法通过 PostgREST 读取 `pg_policies`、`pg_class` 或 `auth.users`。这四个 `SECURITY DEFINER` 辅助程序公开了只读的目录元数据,以便工具可以列出策略。
此工具可以模拟用户并在运行时测试策略吗? 目前不能。静态分析检查策略的**结构**(缺失 `WITH CHECK`、`USING (true)` 等)。真正的模拟需要使用您项目的 JWT 密钥签署 JWT —— 这已在[路线图](#roadmap)中。
我应该在生产环境中安装 SQL 辅助程序吗? 对于包含真实用户数据的生产数据库,建议仅将 `EXECUTE` 权限授予 `authenticated`(而非 `anon`),或者针对镜像了生产策略的预发布环境项目使用此工具。
## 贡献 请参见 [CONTRIBUTING.md](CONTRIBUTING.md)。安全:[SECURITY.md](SECURITY.md)。社区标准:[CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)。变更日志:[CHANGELOG.md](CHANGELOG.md)。 ## 许可证 [MIT](./LICENSE) —— 随意使用。 版权所有 © 2026 Habin。 ## 鸣谢 为了应对无数次出现 `permission denied for table foo` 日志而开发。设计灵感来源于 [Vercel](https://vercel.com) 部署日志的密集度以及 [Linear](https://linear.app) 问题视图的严谨性 —— 密集、严谨、专一。
标签:React, Supabase, Syscalls, Vite, 代码审查工具, 前端工具, 数据可视化, 自定义脚本, 行级安全