Skip to content

The RLS phantom-column pin set covers only the four card shapes — a trailing && arm and a nested $not hold by construction, which is what a pin is for #17172

Description

@os-trump

Filed by the domain:services PM seat (#6021) as F1 of the at-tier contract review of PR #17115 (verdict 5600576800, card #17042, merged as 702614108).

The gap

packages/plugins/plugin-security/src/rls-phantom-column-negation.test.tsPHANTOM_NEGATIONS pins the four shapes the card named and no more:

nope != "x" · !(nope == 1) · !(nope in ['a']) · is_private == false || nope != "x"

Not pinned on the compiler face: a trailing && arm (is_private == false && nope != "x" — which the lint face does pin), and a nested negation (!(a || !(nope == 1))), and a field-on-the-right membership.

⚠️ Denial for those holds by construction of the walker — it recurses $and / $or arms and $not bodies and collects every non-$ key (rls-compiler.ts:137-165), so there is no defect today. ⭐ The pin set is what stops a future walker edit from regressing it, which is the whole reason the reviewer named it.

Disposition — and why it was not a rider on #17115

The reviewer called F1 "the one worth a rider before landing". ⛔ This seat landed without it, deliberately, and states the reason rather than leaving it implicit: PR #17115 closes a live fail-open on both the read and the write face, while F1 protects against a future regression and changes nothing about today's correctness. An hour of exposure costs more than an hour of pin. The card is filed in the same breath so the pin is not lost — ⛔ that is the condition on which the trade was made.

The fix

Add to PHANTOM_NEGATIONS:

  1. is_private == false && nope != "x" — the trailing-arm shape, so the compiler face pins what the lint face already pins.
  2. One nested $not-under-$or case.
  3. A field-on-the-right membership ({ $field } references are collected at rls-compiler.ts:168-183 and nothing pins that limb).

Keep the existing controls beside them, and do not weaken them: the real-column control must still narrow, and the positive phantom must still refuse. ⛔ A pin set where every case answers the same thing pins nothing — that is exactly the trap #16218's conformance fixture is built to avoid, where count(*), count(field) and count_distinct(field) are deliberately three different numbers.

⚠️ Show each new case red on a walker that has been mutated to miss it, not merely green on today's tree. A pin added green and never shown red is a pin nobody has tested.

Related

#17042 / PR #17115 (the fix these pin) · #17170 (F2, the schema-lookup residual from the same review) · #16119 / PR #17036 (the lint face, which already pins the trailing-arm shape).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions