Skip to content

[finding] service-analytics is a second filter emitter that still refuses $field — a CEL rule that now pushes down on the drivers still 400s through the analytics faces #7604

Closed as duplicate

Description

@os-zhuang

Reported by the dev seat while implementing #5222 (PR #7582), filed by the spec-lane PM as its own card per that PR's scope boundary. Recording, not claiming.

The residue

#5222 landed cross-field push-down ({ $field: 'col' } → a real column reference) in driver-sql, closing the split where one CEL permission/RLS rule behaved differently depending on whether the query reached a database. service-analytics has its own independent filter emitters — read-scope-sql and filter-normalizer — each carrying its own mirrored comparand gate, and both still refuse $field.

So the split is narrowed, not closed: a CEL rule containing a field-to-field comparison now works through the ObjectQL/driver path and still answers 400 when lowered through the analytics faces.

Why it was correctly left out of #5222

That issue's maintainer rulings (2026-08-06) are about the driver: same-table columns only, declared-only enumeration, tenant-isolation column forbidden as a referent, federated tables refused. Nothing in them speaks to the analytics emitters, and #5222's dev seat declined to widen a security-relevant acceptance surface in a second subsystem as a side effect — the right call.

Note the envelope difference already recorded in #5222's blast-radius sweep: read-scope-sql refuses with READ_SCOPE_COMPILE_FAILED / 500 rather than INVALID_FILTER / 400, deliberately, because it is compiling an RLS read scope. Any disposition here has to say what that path should do — a 500 on a rule the drivers now execute is a worse split than the 400.

What a card here would have to decide

  1. Do the analytics emitters implement $field under the same four constraints [spec] SqlDriver 将 $field 编译为列对列比较(cross-field comparison push-down) #5222 adopted (same-table, declared-only, tenant column forbidden, federated refused), or do they stay refusing by design because an analytics read scope is a different trust boundary?
  2. If they implement: is the constraint set shareable, or does each emitter re-derive it? [spec] SqlDriver 将 $field 编译为列对列比较(cross-field comparison push-down) #5222 deliberately kept its corpus out of packages/spec/src/data so it would not enrol every driver in conformance DEBT — the same reasoning needs re-running for a second consumer.
  3. If they keep refusing: READ_SCOPE_COMPILE_FAILED / 500 should probably become a loud, documented refusal rather than a compile failure, so the rule author learns the rule is unsupported here instead of seeing a server error.

Natural lane: domain:spec for the acceptance decision (precedent: #5222 itself, #7464). Reference implementation and the constraint arguments: PR #7582.

Refs: #5222, #5041, PR #7582, ADR-0015, ADR-0112.

Activity

  1. os-zhuang commented on Aug 11, 2026

    @os-zhuang
    ContributorAuthor

    Findings triage — closing as duplicate of #7598 (filed 06:51Z, ~31 min before this card; already pm:queue + domain:services).

    Same residue, same two fix sites: #7598 names the service-analytics read-scope / Cube filter compilers refusing $field after #5222's driver-side landing; this card names read-scope-sql and filter-normalizer — the same pair. One piece of work keeps exactly one dispatch entry, and #7598 got there first with routing and queue state already in place (routing verdict there: all fix sites in service-analytics ⇒ domain:services; blocked-in-fact on #5222's PR #7582 landing).

    What this card adds that #7598's executor must not lose (cross-linked on #7598):

    1. The envelope split: read-scope-sql refuses via READ_SCOPE_COMPILE_FAILED / 500, not INVALID_FILTER / 400 — any disposition has to say what that path does; a 500 on a rule the drivers now execute is the worse split.
    2. The four [spec] SqlDriver 将 $field 编译为列对列比较(cross-field comparison push-down) #5222 constraints (same-table, declared-only, tenant column forbidden, federated refused) are the porting baseline, and whether the constraint corpus is shareable or re-derived per emitter needs the same out-of-conformance-DEBT reasoning [spec] SqlDriver 将 $field 编译为列对列比较(cross-field comparison push-down) #5222 ran.
    3. The refuse-by-design alternative (analytics as a different trust boundary) — if taken, the refusal must become loud and documented rather than a compile failure.

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions