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
$expand is still ungated at SEVEN more buildExpandFields call sites — kanban, tree, ObjectView, map, gallery, timeline and PagePreview, none of which passes a column list #7429
Filed unassigned by the domain:ui execution seat (session session_01EMrWaQw3XS5DxTHxp4yRyC) while implementing objectui#7230 / PR #7428. Not fixed there: these sites are outside that card's declared file surface.
Duplicate check run before filing, with a control that fires: the query returned 14 on-topic issues including #7230, #7215 and #7216 (the sibling $select gap). A non-empty on-topic hit set makes the absence of a match a reading rather than a broken query. None of the 14 covers these seven sites.
The scope correction this records
objectui#7230 states that buildExpandFields "is called from five more places, none of them gated". Measured on main at bf244f400, the production call sites are:
So the helper has 13 production call sites, not 7, and #7230's "five more places" undercounts the remainder by seven. This is a counting correction, not a criticism of that card's analysis — its reasoning transfers to these sites unchanged.
Measured
Every line number and count below read from main at bf244f400. checkField / usePermissions counts are whole-file greps, so a 0 means the file has no field-level gate anywhere, not merely none at this call.
site
shape
checkField in file
usePermissions in file
packages/plugin-kanban/src/ObjectKanban.tsx:284
buildExpandFields(objectDef?.fields) — no column list
0
0
packages/plugin-tree/src/ObjectTree.tsx:454
buildExpandFields(objectSchema?.fields) — no column list
0
0
packages/plugin-view/src/ObjectView.tsx:908
buildExpandFields((objectSchema as any)?.fields) — no column list
0
0
packages/plugin-map/src/ObjectMap.tsx:707
buildExpandFields(objectSchema?.fields) — no column list
0
0
packages/plugin-list/src/ObjectGallery.tsx:312
buildExpandFields(objectDef?.fields) — no column list
buildExpandFields(schema?.fields) — no column list
0
0
⚠️ All seven are the SHARP shape, not the mild one
Not one of them passes a column list. buildExpandFields reads an absent column list as "no column restriction" and falls back to every declared relation on the object, denied ones included:
// packages/core/src/utils/expand-fields.tsif(columns&&Array.isArray(columns)&&columns.length>0){// ...intersect with the visible columns}returnreferenceFieldNames;// ← every declared relation
So these are not surfaces that merely fail to filter a column list — they have none, and therefore ask the server to resolve the maximum possible relation set. That is the ordinary configuration of each, not a corner of it. It is the same reading objectui#7230 recorded for calendar / gantt / record-detail, and it applies here verbatim.
PagePreview is worth calling out separately only because it is a designer preview surface, where the reviewer may plausibly hold different grants from the page's eventual audience; that is a reason to look, not a claim, and it has not been measured.
Severity — precise rather than alarming
Same grading as objectui#6898, #7215 and #7230: p2, defence-in-depth, not a live disclosure against ObjectStack's own server. The mechanism was read rather than assumed by the #7215 lane:
FieldMasker.maskRecord does delete result[field] and objectql's engine writes the expanded record back under that same key, so one statement removes both; the expansion sub-read itself takes the referenced object's full CRUD + RLS + FLS treatment (objectstack#7626).
It is load-bearing for a non-enforcing backend, and the client-request side is real regardless: these components ask the server to resolve relations the current principal cannot read.
The shape is settled — do not re-derive it
PR #7229 settled it and PR #7428 applied it unchanged at four more sites. The gate goes on buildExpandFields's OUTPUT:
Gating the input is impossible here anyway (the call passes undefined), and gating the output makes the "checkField answers false for an undeclared key" trap structurally unreachable — the helper returns only declared reference-bearing fields, so every name judged is declared by construction. An unanswered policy must filter nothing, and perms belongs in the dependency list of whatever effect or memo builds the projection.
Three of these packages will need @object-ui/permissions added to dependencies (plugin-kanban, plugin-tree, plugin-map, plugin-timeline — plugin-list and app-shell already have it); check:phantom-deps enforces that.
Not measured
Whether any of these seven is reachable by a principal with a denied lookup in a shipped configuration. They are measured as code shape, exactly as #7230's five were before that card's implementation reproduced each one. The first task should be a failing test per site, on the model of packages/plugin-grid/src/__tests__/expandFls-7215.test.tsx and the five files PR #7428 adds. If a site turns out to be unreachable, that is a finding — record it and pin the behaviour rather than fixing it.
Sizing note for triage
Not necessarily one card. plugin-kanban, plugin-tree, plugin-map and plugin-timeline are lazily loaded by the console and PR #7428 measured their chunks as absent from the eager closure entirely (0 bytes). ObjectGallery lives in plugin-list and PagePreview in app-shell, both of which have eager chunks — so if the framework per-chunk headroom (#7399) is still tight when this is scheduled, the same measure-then-split discipline #7230 carried applies.
Related: objectui#7230 / PR #7428 (the four buildExpandFields sites just gated, plus the dashboard's computeLookupExpand; read its implementation first) · objectui#7215 / PR #7229 (where the shape was settled) · objectui#6898 (the original $select gate) · objectui#7216 (the sibling $select gap in ListView's speculative view bindings).
Filed unassigned by the
domain:uiexecution seat (sessionsession_01EMrWaQw3XS5DxTHxp4yRyC) while implementing objectui#7230 / PR #7428. Not fixed there: these sites are outside that card's declared file surface.Duplicate check run before filing, with a control that fires: the query returned 14 on-topic issues including #7230, #7215 and #7216 (the sibling
$selectgap). A non-empty on-topic hit set makes the absence of a match a reading rather than a broken query. None of the 14 covers these seven sites.The scope correction this records
objectui#7230 states that
buildExpandFields"is called from five more places, none of them gated". Measured onmainatbf244f400, the production call sites are:$expandprojection at both build sites #7229 (ObjectGrid,ListView)$expandat the five remaining build sites #7428 (ObjectCalendar,ObjectGantt,RecordDetailView,DetailView) — the fifth site on that card,ObjectDataTable, builds its own whitelist viacomputeLookupExpandand does not call this helperSo the helper has 13 production call sites, not 7, and #7230's "five more places" undercounts the remainder by seven. This is a counting correction, not a criticism of that card's analysis — its reasoning transfers to these sites unchanged.
Measured
Every line number and count below read from
mainatbf244f400.checkField/usePermissionscounts are whole-file greps, so a0means the file has no field-level gate anywhere, not merely none at this call.checkFieldin fileusePermissionsin filepackages/plugin-kanban/src/ObjectKanban.tsx:284buildExpandFields(objectDef?.fields)— no column listpackages/plugin-tree/src/ObjectTree.tsx:454buildExpandFields(objectSchema?.fields)— no column listpackages/plugin-view/src/ObjectView.tsx:908buildExpandFields((objectSchema as any)?.fields)— no column listpackages/plugin-map/src/ObjectMap.tsx:707buildExpandFields(objectSchema?.fields)— no column listpackages/plugin-list/src/ObjectGallery.tsx:312buildExpandFields(objectDef?.fields)— no column listpackages/plugin-timeline/src/ObjectTimeline.tsx:199buildExpandFields(objectDef?.fields)— no column listpackages/app-shell/src/views/metadata-admin/previews/PagePreview.tsx:134buildExpandFields(schema?.fields)— no column listNot one of them passes a column list.
buildExpandFieldsreads an absent column list as "no column restriction" and falls back to every declared relation on the object, denied ones included:So these are not surfaces that merely fail to filter a column list — they have none, and therefore ask the server to resolve the maximum possible relation set. That is the ordinary configuration of each, not a corner of it. It is the same reading objectui#7230 recorded for calendar / gantt / record-detail, and it applies here verbatim.
PagePreviewis worth calling out separately only because it is a designer preview surface, where the reviewer may plausibly hold different grants from the page's eventual audience; that is a reason to look, not a claim, and it has not been measured.Severity — precise rather than alarming
Same grading as objectui#6898, #7215 and #7230: p2, defence-in-depth, not a live disclosure against ObjectStack's own server. The mechanism was read rather than assumed by the #7215 lane:
It is load-bearing for a non-enforcing backend, and the client-request side is real regardless: these components ask the server to resolve relations the current principal cannot read.
The shape is settled — do not re-derive it
PR #7229 settled it and PR #7428 applied it unchanged at four more sites. The gate goes on
buildExpandFields's OUTPUT:Gating the input is impossible here anyway (the call passes
undefined), and gating the output makes the "checkFieldanswers false for an undeclared key" trap structurally unreachable — the helper returns only declared reference-bearing fields, so every name judged is declared by construction. An unanswered policy must filter nothing, andpermsbelongs in the dependency list of whatever effect or memo builds the projection.Three of these packages will need
@object-ui/permissionsadded todependencies(plugin-kanban,plugin-tree,plugin-map,plugin-timeline—plugin-listandapp-shellalready have it);check:phantom-depsenforces that.Not measured
Whether any of these seven is reachable by a principal with a denied lookup in a shipped configuration. They are measured as code shape, exactly as #7230's five were before that card's implementation reproduced each one. The first task should be a failing test per site, on the model of
packages/plugin-grid/src/__tests__/expandFls-7215.test.tsxand the five files PR #7428 adds. If a site turns out to be unreachable, that is a finding — record it and pin the behaviour rather than fixing it.Sizing note for triage
Not necessarily one card.
plugin-kanban,plugin-tree,plugin-mapandplugin-timelineare lazily loaded by the console and PR #7428 measured their chunks as absent from the eager closure entirely (0 bytes).ObjectGallerylives inplugin-listandPagePreviewinapp-shell, both of which have eager chunks — so if theframeworkper-chunk headroom (#7399) is still tight when this is scheduled, the same measure-then-split discipline #7230 carried applies.Related: objectui#7230 / PR #7428 (the four
buildExpandFieldssites just gated, plus the dashboard'scomputeLookupExpand; read its implementation first) · objectui#7215 / PR #7229 (where the shape was settled) · objectui#6898 (the original$selectgate) · objectui#7216 (the sibling$selectgap inListView's speculative view bindings).