Skip to content

fix(objectql): enforce per-option visibleWhen on checkboxes + string-match option values (objectui#2729)#3350

Merged
os-zhuang merged 1 commit into
mainfrom
feat/2729-checkboxes-option-gating
Jul 20, 2026
Merged

fix(objectql): enforce per-option visibleWhen on checkboxes + string-match option values (objectui#2729)#3350
os-zhuang merged 1 commit into
mainfrom
feat/2729-checkboxes-option-gating

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Addresses objectstack-ai/objectui#2729 (server-side enforcement of role-gated / dependent option values).

Context

Server-side per-option visibleWhen enforcement already exists (packages/objectql/src/validation/rule-validator.tsevaluateOptionVisibility, wired into insert / single-update / bulk-update). Investigating objectui#2729 surfaced that it covered select / multiselect / radio but left two holes that let gated values through on write — the exact "client hides it, server must reject it" boundary the issue is about.

Fixes

  1. checkboxes was not enforced. CHOICE_FIELD_TYPES omitted checkboxes, so fieldHasOptionVisibility returned false for it and its options were never re-evaluated. Since objectui#2735 shipped client-side checkboxes cascading, a gated checkboxes option was hidden in the UI yet accepted from a crafted write. Added checkboxes to the enforced set — picked values are now checked element-wise against each option's visibleWhen (record + current_user), like multiselect. (checkboxes is already treated as a multi-value option field by the enum validator, so this closes an inconsistency between the two validators.)

  2. Numeric option values could slip the gate. Option matching used strict ===, but the enum-membership validator (record-validator.ts) compares by String(...). A numeric option value submitted as a string (a normal REST/JSON round-trip) passed the enum check but its visibleWhen gate found no matching option and fail-opened. Matching now coerces both sides with String(...), so the enum and visibility validators agree on which option a written value denotes.

Not changed / by design

  • select / multiselect / radio behavior is unchanged.
  • Fail-open on unbound current_user (system writes) or unevaluable predicates is preserved — a broken cascade predicate must never brick a write; authorization gating depends on the engine binding current_user, as before.
  • dependsOn remains a client form-gating hint only; server enforcement keys off each option's visibleWhen (a cascade parent is expressed inside the child's predicate, e.g. record.country == 'cn'), matching the existing design.

Tests

  • Extended rule-validator.option-visibility.test.ts: checkboxes element-wise gating (+ needsPriorRecord), and numeric-value coercion (both are real regression guards — they fail on the pre-fix code).
  • Verified green: objectql src/validation/ + engine.test.ts (206 passed) and plugin.integration.test.ts real-registry path (36 passed). tsc --noEmit clean; eslint 0 errors (one pre-existing unrelated no-new warning).

🤖 Generated with Claude Code

…ption values by string (objectui#2729)

Server-side per-option gating covered select/multiselect/radio but two holes
let gated values through on write:

- checkboxes was excluded from CHOICE_FIELD_TYPES, so a gated `checkboxes`
  option (client widget cascades like multiselect since objectui#2715) was
  hidden in the UI but accepted from a crafted write. Now enforced element-wise
  on insert/update/bulk-update like multiselect.
- Option matching used strict `===` while the enum validator compares by
  String(...); a numeric option value sent as a string passed the enum check
  but missed its visibleWhen gate (fail-open). Now coerces both sides.

select/multiselect/radio behavior unchanged; fail-open on unbound current_user /
unevaluable predicates preserved. Adds checkboxes + coercion cases to
rule-validator.option-visibility.test.ts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jul 20, 2026 6:03am

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling size/s labels Jul 20, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/objectql.

13 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/concepts/metadata-lifecycle.mdx (via @objectstack/objectql)
  • content/docs/data-modeling/formulas.mdx (via packages/objectql)
  • content/docs/deployment/migration-from-objectql.mdx (via @objectstack/objectql)
  • content/docs/deployment/vercel.mdx (via @objectstack/objectql)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/objectql)
  • content/docs/kernel/services.mdx (via @objectstack/objectql)
  • content/docs/permissions/authentication.mdx (via @objectstack/objectql)
  • content/docs/plugins/index.mdx (via @objectstack/objectql)
  • content/docs/plugins/packages.mdx (via @objectstack/objectql)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/objectql)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/objectql)
  • content/docs/releases/implementation-status.mdx (via @objectstack/objectql)
  • content/docs/releases/v9.mdx (via @objectstack/objectql)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@os-zhuang
os-zhuang merged commit 674457a into main Jul 20, 2026
16 checks passed
@os-zhuang
os-zhuang deleted the feat/2729-checkboxes-option-gating branch July 20, 2026 06:07
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Jul 20, 2026
…d + Console)

Continues the v16 page from the latest front/back-end code. Since the rc.0 cut,
9 backend changesets landed and the objectui pin advanced 94d4876 -> af1b0db
(objectui objectstack-ai#2706-objectstack-ai#2736). Sourced from each repo's own changesets.

- Retitles the now-stale 'pending the next console pin' subsection: those 4
  frontend items (objectui#2701/objectstack-ai#2706/objectstack-ai#2707/objectstack-ai#2708) are now bundled as the pin
  advanced; points to the new running section.
- Adds a 'Landed since 16.0.0-rc.0' section:
  - Breaking/behavior: aiStudio/aiSeat alias removal (objectstack-ai#3308); date-arithmetic
    now a build-time error (objectstack-ai#3306); checkboxes per-option visibleWhen + string
    option matching (objectstack-ai#3350).
  - New backend: formula null-guard/floor/ceil (objectstack-ai#3306); engine-owned managedBy
    bucket (ADR-0103 addendum, objectstack-ai#3343); approvals viewer gating (objectstack-ai#3344) +
    decision attachments (objectstack-ai#3332); discovery transactionalBatch bit (objectstack-ai#3298);
    action resultDialog i18n (objectstack-ai#3347); collab-notification/storage localization
    + wired notifications REST routes (objectstack-ai#3354).
  - Console (now bundled): option-widget visibleWhen parity, approvals-inbox
    server-viewer gating + composer retirement, related-list pagination,
    inline-analytics renderer retirement, authenticated api-fetch threading,
    result-dialog i18n, engine-owned bucket UI, write-failure surfacing.
- Adds aiStudio/aiSeat and date-arithmetic to the upgrade checklist; updates
  the Console-section intro for the advanced pin.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AHVoqyH9VAjmbyMN1Ri2jf
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant