You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
ADR-0056 D4: exposed so an authoring-time gate (objectstack compile) can REJECT a predicate the runtime would silently drop — the class of bug where owner == current_user.name (==, unsupported) compiled to nothing and left an object unprotected. A false here means "this predicate will never enforce".
sqlPredicateToCel 和 isSupportedRlsExpression两个都住在 plugin-security,那是一个 runtime。@objectstack/lint 的包契约是 "Depends on @objectstack/spec; never on a runtime"。
发现于 #4698 的实现过程(
packages/lint侧已落地 sharing-rule 那条,见 PR)。这是同一缺陷类的姊妹面,但修不进那个 PR,原因写在下面。事实
isSupportedRlsExpression(packages/plugins/plugin-security/src/rls-compiler.ts) 的 TSDoc 明确说明它存在的唯一理由:仓内消费者盘点(
grep -rn isSupportedRlsExpression --include=*.ts packages/):packages/plugins/plugin-security/src/rls-compiler.ts— 定义处packages/plugins/plugin-security/src/security-plugin.test.ts— 它自己的单测packages/qa/dogfood/test/authz-conformance.matrix.ts— 一致性矩阵里的一行描述文字即:那个 authoring gate 从来没有被任何 authoring 命令调用过。函数本身就是一个 declared-but-never-read 的实例 —— 而且它恰好是为了修 declared-but-never-read 而写的。
后果
stack.permissions[].rowLevelSecurity[].using/.check是可授权面(PermissionSetSchema.rowLevelSecurity)。一条不可下推的谓词在运行期走RLSCompiler.compileExpression→compileCelToFilter返回!ok→return null→ 单策略路径变成RLS_DENY_FILTER(fail closed)。所以它不是安全漏洞,而是一条看起来在授权、实际在拒绝的策略:管理员写了一条 policy,用户被一律拒访,现场没有任何指向这条 policy 的诊断。
os validate/os build/os lint全绿。为什么没有随 #4698 一起做
判据本身是可机械判定的(和 sharing rule 那条同一个编译器),但判据的实现位置不对:
isSupportedRlsExpression,它先经sqlPredicateToCel把遗留 SQL-ish 子集(=→==,IN→in)桥接成 canonical CEL,再问isPushdownableCel。sqlPredicateToCel和isSupportedRlsExpression两个都住在plugin-security,那是一个 runtime。@objectstack/lint的包契约是 "Depends on @objectstack/spec; never on a runtime"。抄一份尤其危险:
sqlPredicateToCel是一个正则重写,它的IN/=边界条件(引号内字面量不重写、对 CEL 输入幂等)是这条规则判绿判红的分界线。两份实现只要漂移一格,lint 就会在 authoring 时否掉运行期其实能执行的策略 —— 误伤方向,比漏报更糟。建议做法(engine / security 车道)
sqlPredicateToCel上提到@objectstack/formula(它已经是isPushdownableCel的家,而且 lint 已经依赖它)。plugin-security从那里 re-export 或直接引用,保持一份定义。ADR-0058 D1 说的就是 "a single canonical shape gate",桥接属于那个 gate 的一部分。packages/lint加一条规则,判据 =isPushdownableCel(sqlPredicateToCel(expr)),覆盖permissions[].rowLevelSecurity[].using和.check,以及对象上直接授权的objects[].rowLevelSecurity[](validateOrgAxisRedLines已经在走这两条路径,可以照抄遍历)。error,理由同 sharing-rule 那条:没有任何一种读法下这条 policy 会按作者写的那样授权。examples/与packages/plugins/plugin-security/src/objects/default-permission-sets.ts里现存的每一条using/check都能下推,新 gate 不会让任何现有代码变红。验证脚本(实测,非推断)
相关:#4698(母议题,declared-but-never-read 的模式)、ADR-0056 D4、ADR-0058 D1。