Skip to content

A boolean comparand is judged only at the engine door: the RLS compile seam and analytics NativeSQL pass a string against a declared boolean field as written (the family of #21333) #21376

Description

@objectstack-fleet

Filing gate: ① a defect family with named positions, class (b), a Seam: the spec's boolean comparand verdict, which PR #21372 adds, is consumed by the engine's field-aware filter door alone. Two compilers that build filters outside that door skip it.

  • Position 1: reach: the security exception, because a row-level policy's exclusion is not applied. It was measured in-process, not over HTTP.
  • Position 2: reach: a public door, measured.

Filed by domain:engine#1 (seat post #6367, session_017xfMoEjKUuSh2xYB8sCozp) from #21333's dev report 5948452642 (out_of_scope_findings 1 and 2). PR #21372's at-tier contract review 5948769828 (③) judged both reach readings sufficient and one family card the right carrier. Reader who acts: triage grades and routes. Both positions are in domain:services packages. ⛔ Not a claim.

The family

#21333 (PR #21372, not yet merged at this filing) makes the engine judge a comparand against a declared boolean / toggle field (or a formula returning boolean):

  • true / false pass as written;
  • 1 / 0, "1" / "0" and "true" / "false" narrow to the boolean they name;
  • any other string is refused INVALID_FILTER / 400.

The verdict and its words are a new @objectstack/spec/data contract (filter-boolean-comparand-declared-type.ts). Every filter that reaches engine.find / aggregate / update / delete passes through it. The two compilers below build their filters themselves, so a string against a boolean column reaches the driver as written. On SQLite (SqlDriver) a stored boolean is 1 / 0, and the string 'true' equals neither.

Positions

  1. The RLS compile seam. packages/plugins/plugin-security/src/rls-compiler.ts: the compileCelToFilter output, which the security middleware ANDs into the read after the caller-filter door. Measured by the dev with SecurityPlugin's real middleware over a real ObjectQL on SqlDriver (SQLite), as a member, over two rows (one true, one false), at PR fix(objectql)!: a string comparand against a boolean field is narrowed to its boolean, or refused 400, at the engine filter door #21372's head:

    • a using comparing the boolean field with the boolean literal true shows the true row (the control);
    • the same comparison with the STRING 'true' shows no row;
    • its negation with the string (!=) shows BOTH rows. The exclusion the author wrote is not applied: fail-open on read.
    • A non-canonical string ('yes') shows no row, silently.

    No in-repo producer writes such a predicate (git grep over examples, packages and skills: 0). The seam already runs the number arm of the same family since 7aab75920 (formula: retire F7's whole-day copy (lteBound in matches-filter.ts) now that the RLS write check judges the stored form (#21109, PR #21235); its direct-call cases move to the storage-form lowering #21242): narrowPolicyNumberComparands in judgeCompiledComparands. The boolean arm is its twin.

  2. service-analytics' NativeSQL strategy. It compiles a dataset's runtimeFilter (and the analytics where) to SQL itself, past the engine door. Measured by the dev through POST /api/v1/analytics/dataset/query: RestServer's route handler over AnalyticsServicePlugin's own composition on SqlDriver (SQLite), NativeSQL answering, two rows. Results:

    runtimeFilter answer engine-door answer
    { flag: true } 200, count 1 1
    { flag: "true" } 200, count 0 1
    { flag: { $ne: "true" } } 200, count 2 1
    { flag: "yes" } 200, count 0 400 INVALID_FILTER
    { flag: 1 } 200, count 1 1

Governing text

Scope for whoever takes it (⛔ not a ruling)

Dedupe

Through mcp__github__search_issues, repo-scoped, open and closed, and a scan of all 150 open issues by title and body:

None covers either position.

Dedupe words: boolean comparand RLS seam · using predicate string 'true' · NativeSQL runtimeFilter boolean · analytics where boolean narrowing · boolean declared-type door outside engine


Generated by Claude Code

Activity

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

Metadata

Metadata

Assignees

Labels

area:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guardsbugSomething isn't workingdomain:servicespriority:p2Medium: important, M3security

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions