Repository navigation
Description
发现于 #4983 的实现过程(为 permissions[].rowLevelSecurity[].using/.check 立 authoring gate 时,照着 validateOrgAxisRedLines 的遍历核对可授权面)。按 Prime Directive #10 单独记账 —— 不在那一单的范围内,且该文件当时正被 #4991 占用。
事实
packages/lint/src/validate-org-axis-red-lines.ts(main,含 #4984 与 #5004 之后)仍有三处 ?? 别名读法:
const permissionSets = asArray(cfg.permissions ?? cfg.permissionSets);
...
asArray(object.rowLevelSecurity ?? object.rls).forEach(...)
...
asArray(cfg.sharingRules ?? cfg.sharing).forEach(...) // 两处对照 spec 实际声明的键:
| 读法 | spec 现状 |
|---|---|
cfg.permissions |
✅ StackSchema 唯一声明的 permission-set 键(stack.zod.ts) |
cfg.permissionSets |
❌ 未声明 |
object.rowLevelSecurity |
❌ ObjectSchema 根本没有这个键 —— rowLevelSecurity 只声明在 PermissionSetSchema 上(permission.zod.ts),authorable-surface.json 里也只有 security/PermissionSet:rowLevelSecurity 一条 |
object.rls |
❌ 未声明;rls 只是 PERMISSION_SET_KEY_ALIASES 里 → rowLevelSecurity 的被拒别名 |
cfg.sharingRules |
✅ 声明 |
cfg.sharing |
❌ 未声明 |
后果
该规则是 input: 'parsed'。Zod object 默认 strip 未声明键,所以在 os validate / os build 这两道门上,permissionSets / objects[].rowLevelSecurity / objects[].rls / sharing 在规则看到 stack 之前就已经不存在了 —— 这几条分支对任何 spec 合法的 stack 都永远不执行。只有 os lint(不 parse,跑 normalized 层)才可能命中,而能命中的恰恰是 os validate / os build 会拒绝的 stack。
这正是 #4984 的缺陷形状:红线读了被拒的别名,于是对每一个 schema 接受的 stack 都是惰性的。#4984 修掉了 sharing rule 那一半(criteria / filter / sharedTo / recipient),并在文件里写下了理由 ——
Alias tolerance belongs at the schema's refusal, not in a consumer (Prime Directive #12).
—— 但同一文件里另外三处 ?? 没有一起清掉。其中 objects[].rowLevelSecurity 那一整段(约 20 行,连同 objects[N].rowLevelSecurity[M].using 这条 path 格式)是整块死代码:对象级 RLS 从来不是可授权面。
危险不在漏报,在于误导:该段落 + validate-org-axis-red-lines.test.ts 里对应的用例,会让下一个作者(或 AI 作者)合理地相信 objects[].rowLevelSecurity 是一个真实的授权面并照着写,而运行期没有任何东西读它。
建议
- 三处
??收敛为声明键:cfg.permissions、cfg.sharingRules。 - 删掉
objects[].rowLevelSecurity ?? objects[].rls那一整段遍历(以及测试里对应的两条用例),或者——如果对象级 RLS 是想要的授权面——那是一次 spec 变更(给ObjectSchema加键 + 运行期读者),不是 lint 里的一条??。二选一,别两头都不落地。 - 顺带核对:
validate-security-posture.ts等邻居规则是否有同形别名读法。
参考
- validateOrgAxisRedLines 读的 sharing-rule 键是 spec 拒收的:ADR-0105 D6 ① 在 criteria 路径上从不触发 #4984(sharing rule 那一半)、ADR-0105 D6 ② 只拦 business_unit 收件人,漏了 unit_and_subordinates —— 同一个跨 org BU 授权,更宽的那个反而放行 #4991 / fix(lint): ADR-0105 D6 ② 的收件人词表扩至 ADR 原文范围 ——
unit_and_subordinates也判红 (#4991) #5004(同文件的覆盖面修复) - ADR-0056 D4 的 RLS authoring gate 从未接线:isSupportedRlsExpression 没有任何非测试消费者 #4983 的
validate-rls-predicate-enforceability.ts采取了相反做法:只读cfg.permissions,并用一条测试钉住permissionSets/objects[].rowLevelSecurity判绿,理由写在该文件## Scope段。
Activity
xuyushun441-sys commentedon Aug 3, 2026
认领(PM 分派)
session_018iARDqtrhQgz6fVHDeDkbQclaude/issue-5009-org-axis-dead-branchesdomain:devx(落点packages/lint/src/validate-org-axis-red-lines.ts;ADR-0105 D6 ② 只拦 business_unit 收件人,漏了 unit_and_subordinates —— 同一个跨 org BU 授权,更宽的那个反而放行 #4991/PR fix(lint): ADR-0105 D6 ② 的收件人词表扩至 ADR 原文范围 ——unit_and_subordinates也判红 (#4991) #5004 已合入,该文件空闲)#4984 修了 sharing rule 半边,本单清剩下三条 spec 合法 stack 到不了的别名分支(
cfg.permissionSets/objects[].rowLevelSecurity ?? .rls整段 /cfg.sharing)。要求沿用 #4992 的 meta-guard 模式:留下的每条遍历分支都要有 spec 合法 fixture 能走到,走不到的删 —— 危险不在死代码本身,在它会让下一个作者相信objects[].rowLevelSecurity是真实授权面(#5008 刚差点因此复制它)。Generated by Claude Code
xuyushun441-sys commentedon Aug 3, 2026
审核通过 — PR #5018 已取消草稿并挂上 auto-merge(SQUASH)
议题列三条,实测四条:
str(rule.object ?? rule.objectName)是同函数内同形状的第四条死别名(objectName被.strict()按名拒绝,且object必填)—— 同一表达式簇一并处置,对。objects[].rowLevelSecurity比议题描述的更死:我立案时按"Zod strip 未声明键"推理,实测 ObjectSchema 是.strict()—— 带该键的 stack 不是丢键,是整包被os validate/os build拒绝。结论不变,证据更强,且这正是"读代码定,不信议题转述"的又一例。canonical 化三条的反向验证方向与我的任务书预设相反,dev 如实报告而非套模板 —— 这是本单我最认可的一点。canonical 键本就是
??的第一顺位,spec 合法的违规 stack 改动前就判红,不存在 before绿/after红;真正该证的是反方向:改动前对permissionSets/objectName拼法的非法 stack 判红(规则替 schema 越权把门),改动后判绿(schema 才是那道门)。三条钉子测试正是在原实现上转红的那几条。模板是工具,不是真理 —— 发现模板不适配时说出来,比硬凑一份符合模板的证据有价值得多。meta-guard 两层且经变异验证:declared-key guard(从源码抽每个 receiver 读的键,断言 ⊆ 对应 schema 的
.shape)+ reachability guard(每个findings.push调用点必须被至少一条过 safeParse 的 fixture 触达,且 fixture 不得产出源码未声明的 path)。变异回放:加回任何一条死分支 → 2~4 条红。顺带修掉规则 ① 的 fixture 从未过 safeParse 的问题(#4984 的守卫漏了 permission set 面),补了permissionSet()helper。纯减法改动,findings 单调不增,真实元数据结构上不可能新红(且逐处 grep 复核过)。
衍生 #5017 已入队:同形别名读法在
validate-expressions.ts(canonical 的condition竟排??链第三顺位,前两位是被 schema 按名拒绝的别名)与validate-security-posture.ts(obj.security?.sharingModel—— ObjectSchema 无security键)。这个缺陷族在 lint 包里看来是成建制的,#5017 之后建议做一次全包扫尾。Generated by Claude Code
fix(lint): 删除 validateOrgAxisRedLines 里 spec 合法 stack 到不了的四条分支 (objec…
fix(lint): 收敛 validate-expressions / validate-security-posture 的 spec…
fix(lint): 收敛 validate-rule-compilability 的 spec 不声明键 `??` 别名读法 (obje…
fix(lint): validateFormLayout 走视图容器阶梯,两条规则不再对真实 app 全盘报绿 (objectstack…