性质
观察类(finding),不加 pm:queue:不进生成器,今天没有用户会撞上它 —— 影响面是「读源码的作者被一段过时的语法规范误导」。不认领,仅记录。
来自 #6762 / PR #6918 的 out-of-scope finding(Prime Directive #10),未指派。
2026-08-09 更新 —— 本卡范围已收窄,只剩未发布的那一半。
早先本卡的评论区还记录了同文件 :79 模块级 docblock 的同类问题(「A small, fixed expression grammar (equality, set-membership, always-true)」,会逐字渲染到 content/docs/references/security/rls.mdx:79)。经 PM 裁定,那一半是已发布面、属于 #6762 的条目范围,已在 PR #6918 内一并修掉,不再属于本卡。
因此本卡现在纯粹是属性级 TSDoc(不进生成器)—— 这也让 finding 这个等级从「勉强站得住」变成「确实正确」。下方评论区里关于 :79 的那条记录已过时,仅作历史留存。
事实
packages/spec/src/security/rls.zod.ts 中 using 属性上方的 TSDoc 块(origin/main @ 2672f855f 实测 :296-354)写着:
* The reference RLS compiler implements a deliberately **small, fixed
* grammar** rather than a general SQL parser. Exactly four forms compile;
* anything else fails closed (the policy matches zero rows). Keep `using`
* to one of:
*
* 1. `field = current_user.< prop >` — equality against a context value
* 2. `field = 'literal'` — equality against a single-quoted string literal
* 3. `field IN (current_user.< array_prop >)` — set membership ...
* 4. `1 = 1` — always true / no restriction
*
* There is intentionally **no** support for `AND`/`OR`/`NOT`, comparison
* operators other than `=`, ...
(上面两处 < prop > / < array_prop > 是为绕开 GitHub body sanitizer 加的空格,源码里没有空格。)
这与实测不符。在 PR #6918 里我对 isSupportedRlsExpression(packages/formula/src/rls-predicate.ts)逐条实测:
- ENFORCES:
!=、<、<=、>、>=;in 对 current_user.* 数组以及对内联字面量列表(status in ['draft', 'pending']);&&;||;裸 true。
- FAILS CLOSED:SQL 的
AND / OR / NOT IN / IS NULL / LIKE、算术、子查询、跨对象 traversal、裸真值字段、取反 !。
所以这段块注释一半对一半错:它说 SQL 的 AND/OR 不支持 —— 对;它说「恰好四种形式编译」「除 = 外没有比较算子」—— 错,CEL 的 &&/|| 与全套比较算子都会真正下推。
isSupportedRlsExpression 自己的注释早就点破了这点:"This is broader than the historical 4 forms — comparisons (amount > 100) and == now ENFORCE"。
为什么 PR #6918 只打标记、不重写
PR #6918 已在 :310 处加了一段 ⚠️ STALE 标记指向本卡,说明下方四项枚举 under-states、.describe() 才是当前事实。标记不是修复:它把「两条互相矛盾的断言」降级为「一条断言 + 一句诚实警告」,本卡落地时应连同标记一并移除。
之所以不在那张卡里重写:
- 它不进生成器。
gen:docs 只渲染属性的 .describe() 和模块级 docblock,从不渲染属性级 TSDoc。实测复证:给这段 TSDoc 加标记后 content/docs/references/** 零 diff。所以它是观察类。
- 它是一段约 60 行的语法规范散文,还顺带对 context values、§7.3.1 dynamic membership、prohibited 清单做规范性陈述 —— 重写值得自己一轮复核,塞进一张两条目 sweep 卡会被淹没。
建议的修法
把这段块注释按 .describe() 与 :79 已确立的口径重述:讲能被下推的形态而非固定计数(⛔ 「四」换成「八」是同一个缺陷),canonical CEL 在前、SQL 拼写作为过渡桥接(ADR-0058 D1,sqlPredicateToCel 已标 @deprecated)。同属性的 5 条 @example("organization_id = current_user.organization_id" 等)也全是 SQL 方言,同一轮一起改比较合算。顺手移除 :310 的 STALE 标记。
⚠️ 注意 #6763:没有任何门读 spec 的 TSDoc @example,所以这些例子改完也仍然没有回归保护 —— 这条与 #6763 是同一根因的两个面。
Related
#6762 / PR #6918(.describe() 与已发布的 :79 模块 docblock,均已修)、#6763(无门读 TSDoc @example)、#6641 / PR #6729(check 子句的 @example)、ADR-0058 D1。
性质
观察类(
finding),不加pm:queue:不进生成器,今天没有用户会撞上它 —— 影响面是「读源码的作者被一段过时的语法规范误导」。不认领,仅记录。来自 #6762 / PR #6918 的 out-of-scope finding(Prime Directive #10),未指派。
事实
packages/spec/src/security/rls.zod.ts中using属性上方的 TSDoc 块(origin/main@2672f855f实测:296-354)写着:(上面两处
< prop >/< array_prop >是为绕开 GitHub body sanitizer 加的空格,源码里没有空格。)这与实测不符。在 PR #6918 里我对
isSupportedRlsExpression(packages/formula/src/rls-predicate.ts)逐条实测:!=、<、<=、>、>=;in对current_user.*数组以及对内联字面量列表(status in ['draft', 'pending']);&&;||;裸true。AND/OR/NOT IN/IS NULL/LIKE、算术、子查询、跨对象 traversal、裸真值字段、取反!。所以这段块注释一半对一半错:它说 SQL 的
AND/OR不支持 —— 对;它说「恰好四种形式编译」「除=外没有比较算子」—— 错,CEL 的&&/||与全套比较算子都会真正下推。isSupportedRlsExpression自己的注释早就点破了这点:"This is broader than the historical 4 forms — comparisons (amount > 100) and==now ENFORCE"。为什么 PR #6918 只打标记、不重写
PR #6918 已在
:310处加了一段⚠️ STALE标记指向本卡,说明下方四项枚举 under-states、.describe()才是当前事实。标记不是修复:它把「两条互相矛盾的断言」降级为「一条断言 + 一句诚实警告」,本卡落地时应连同标记一并移除。之所以不在那张卡里重写:
gen:docs只渲染属性的.describe()和模块级 docblock,从不渲染属性级 TSDoc。实测复证:给这段 TSDoc 加标记后content/docs/references/**零 diff。所以它是观察类。建议的修法
把这段块注释按
.describe()与:79已确立的口径重述:讲能被下推的形态而非固定计数(⛔ 「四」换成「八」是同一个缺陷),canonical CEL 在前、SQL 拼写作为过渡桥接(ADR-0058 D1,sqlPredicateToCel已标@deprecated)。同属性的 5 条@example("organization_id = current_user.organization_id"等)也全是 SQL 方言,同一轮一起改比较合算。顺手移除:310的 STALE 标记。@example,所以这些例子改完也仍然没有回归保护 —— 这条与 #6763 是同一根因的两个面。Related
#6762 / PR #6918(
.describe()与已发布的:79模块 docblock,均已修)、#6763(无门读 TSDoc@example)、#6641 / PR #6729(check子句的@example)、ADR-0058 D1。