Skip to content

Commit b821b29

Browse files
fix(lint): 删除 validateOrgAxisRedLines 里 spec 合法 stack 到不了的四条分支 (#5009) (#5018)
该规则注册为 `input: 'parsed'`,看到的是 `ObjectStackSchema` 解析后的产物。 #4984 修掉了 sharing rule 字段层的 `??` 别名读法,同一文件里还留着四条同形 分支,读的键 spec 都不声明 —— 逐条对着 schema 的 `.shape` 与 `safeParse` 实测核过: - `cfg.permissions ?? cfg.permissionSets` → `cfg.permissions`。 `ObjectStackSchema.shape` 无 `permissionSets`;stack 根 strip 未声明键, 实测 `safeParse({ manifest, permissionSets: [...] })` 成功但 `data` 里 没有该键 —— 规则看到 stack 之前它已经不存在。 - `cfg.sharingRules ?? cfg.sharing`(两处)→ `cfg.sharingRules`。同上。 - `str(rule.object ?? rule.objectName)` → `str(rule.object)`。 `SharingRuleSchema` 是 `.strict()`,`objectName` 被按名拒绝 ("Unrecognized key(s) on this sharing rule: `objectName`");`object` 又是必填,解析过的规则上不可能缺。 - `asArray(object.rowLevelSecurity ?? object.rls)` 整段遍历(约 20 行) **删除**。依据:`ObjectSchema.shape` 两个键都没有(实测键表里只有 `sharingModel` / `access` / `tenancy` 等,无 `rowLevelSecurity`、无 `rls`), 且 `ObjectSchema` 是 `.strict()` —— 带对象级 RLS 的 stack 在 `os validate` / `os build` 被整包拒绝,报 "Unrecognized key(s) on this object: `rowLevelSecurity`"。对象级 RLS 从来不是可授权面 (`authorable-surface.json` 里只有 `security/PermissionSet:rowLevelSecurity`)。 对任何 spec 合法的 stack,判定结果不变 —— 反向验证:新测试跑在改动前的 实现上,29 条由 `safeParse` fixture 驱动的断言全绿,8 条转红的全部是 (a) 扫源码的 meta-guard,或 (b) 喂非 spec 合法 stack 的新钉子测试。 代价从来不是漏报,是误导:那段死代码连 `objects[N].rowLevelSecurity[M].using` 的诊断 path 都写好了,足以让下一位作者相信对象级 RLS 是真实授权面并照着写 (#5008 差点如此)。别名容忍属于 producer 的拒绝,不属于 consumer(Prime Directive #12)。 meta-guard(#4992 模式),让下一条死分支在 review 前就红: - declared-key guard:规则源码里从 stack / permission set / RLS policy / object / sharing rule 上读的每个键,必须出现在对应 schema 自己的 `.shape` 里。扫源码而非行为是刻意的 —— 不可达分支没有行为可断言。 - reachability guard:每个 `findings.push` 调用点都必须被至少一条过 `safeParse` 的 fixture 触达(现存三个点,全覆盖)。 - 规则 ① 的 fixture 现在也走 `PermissionSetSchema.safeParse`。 四条分支各自做过变异验证:加回任意一条,至少两条测试转红。 真实元数据零新红:examples/ 与 default-permission-sets 中无 `parent_organization_id`,唯一的 `rowLevelSecurity` 用法在 permission set (保留的那条分支)上,`sharing:` 出现在 view 定义内而非 stack 根。 邻居规则同形别名读法已另行记账为 #5017(未认领),不在本 PR 范围。 Claude-Session: https://claude.ai/code/session_018iARDqtrhQgz6fVHDeDkbQ Co-authored-by: Claude <noreply@anthropic.com>
1 parent bf1edef commit b821b29

3 files changed

Lines changed: 524 additions & 53 deletions

File tree

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
---
2+
"@objectstack/lint": patch
3+
---
4+
5+
fix(lint): 清除 `validateOrgAxisRedLines` 里 spec 合法 stack 永远到不了的四条分支 (#5009)
6+
7+
`validate-org-axis-red-lines.ts``input: 'parsed'` 规则 —— 它看到的是
8+
`ObjectStackSchema` 解析后的产物。#4984 修掉了 sharing rule 字段那一层的 `??`
9+
别名读法,但同一文件里还留着四条同形分支,每一条读的键 spec 都不声明:
10+
11+
| 原读法 | spec 事实 | 处置 |
12+
|:--|:--|:--|
13+
| `cfg.permissions ?? cfg.permissionSets` | stack 根 **strip** 未声明键,`permissionSets` 解析后必为 `undefined` | 收敛为 `cfg.permissions` |
14+
| `cfg.sharingRules ?? cfg.sharing`(两处) | 同上 | 收敛为 `cfg.sharingRules` |
15+
| `str(rule.object ?? rule.objectName)` | `SharingRuleSchema``.strict()`,按名拒绝 `objectName`;`object` 又是必填 | 收敛为 `rule.object` |
16+
| `asArray(object.rowLevelSecurity ?? object.rls)` 整段(约 20 行) | **`ObjectSchema` 两个键都不声明**,且 `.strict()` —— 带对象级 RLS 的 stack 在 `os validate` / `os build` 直接被拒("Unrecognized key(s) on this object") | **删除** |
17+
18+
对任何 spec 合法的 stack,判定结果不变:这些分支本来就永远不执行(反向验证 ——
19+
新测试跑在改动前的实现上,29 条由 `safeParse` fixture 驱动的断言全绿)。真正的
20+
代价从来不是漏报,而是误导:对象级 RLS **根本不是授权面**(`authorable-surface.json`
21+
里只有 `security/PermissionSet:rowLevelSecurity` 一条),而那段死代码连
22+
`objects[N].rowLevelSecurity[M].using` 的诊断 path 都写好了,足以让下一位作者
23+
(人或 AI)相信它是真的并照着写更多代码 —— #5008 差点就这么做了。
24+
25+
行为上唯一的差别落在 `os lint`(不 parse,跑 normalized 层):把别名拼法写进
26+
stack 的作者,不再从这条红线拿到诊断,而是从 schema 那里拿到一条指名道姓的
27+
拒绝。别名容忍属于 producer 的拒绝,不属于 consumer(Prime Directive #12)。
28+
29+
同时补上一层结构性 meta-guard(#4992 模式),让下一条死分支在 review 前就红:
30+
31+
- **declared-key guard** —— 规则源码里从 stack / permission set / RLS policy /
32+
object / sharing rule 上读的每一个键,都必须出现在对应 schema 自己的 `.shape`
33+
里。扫源码而不是扫行为是刻意的:不可达分支根本没有行为可断言。
34+
- **reachability guard** —— 每个 `findings.push` 调用点都必须被至少一条过
35+
`safeParse` 的 fixture 触达;走不到的分支不允许存在。
36+
- 规则 ① 的 fixture 现在也走 `PermissionSetSchema.safeParse`(此前只有 sharing
37+
rule 和 object fixture 有这层保护)。
38+
39+
四条分支各自被变异测试验证过:把任意一条加回去,都至少有两条测试转红。

0 commit comments

Comments
 (0)