Skip to content

rest/meta: two more read doors (/meta/diagnostics, /meta/:type/:name/references) never forward the caller's organization — the "Used by" graph tells an operator an org-referenced item is safe to delete #13753

Description

@os-steve

Found by the mandatory door-by-door enumeration #13406 asked for (compare every meta read door in packages/rest/src/rest-server.ts against /audit's parameter passing). #13406 is scoped to /history, /diff and the single-item overlay read; these two doors carry the same omission and are outside that scope, so they are recorded here rather than fixed there.

The omission

Both protocol implementations declare and genuinely readorganizationId, and both forward it into getMetaItems. Neither REST door supplies one, so both resolve at env scope only.

DoorImplementationWhat it does with the orgREST door supplies it?
GET /api/v1/meta/diagnosticsgetMetaDiagnosticsorganizationId?: string, passed straight into getMetaItems({ type, organizationId, packageId })no
GET /api/v1/meta/:type/:name/referencesfindReferencesToMetaorganizationId?: string, spread into getMetaItems({ ...(request.organizationId ? { organizationId: request.organizationId } : {}) })no

Locate by symbol — line numbers in rest-server.ts rot within the day.

Direction is fail-closed, same as #13406: the caller's own org data is under-served and there is no cross-org read. Not a security card.

Why the references door is the sharper half

findReferencesToMeta backs the admin "Used by" panel, and that panel renders its empty case as "Nothing in the metadata graph points at this item. Safe to delete." — shown to an operator who is about to delete something.

An org-scoped view that references a packaged dashboard lives in the org partition. The reference sweep reads the env partition only, finds nothing, and the panel advises deletion of an item the caller's own organization is actively using. That is the same false-negative-on-a-consequential-surface class the 501 refusal in this very door was added to prevent (see the ADR-0110 D3 note at the top of that handler, from #9326): the handler already refuses to report "the question was never asked" as "nothing depends on this item", and then answers exactly that when the org is unstated.

/meta/diagnostics is the milder half: an org's own overlays are simply absent from the Studio diagnostics sweep, so a directory page reports clean tiles over a partition it never read.

Fix direction (not applied here)

Call-side only, mirroring the repair landing for #13406: resolve the memoised resolveExecCtx and pass organizationIdForMetaRead(canonicalMetaUrlType(...), ctx?.tenantId).

⚠️ Use the registry-gated predicate, not a raw ctx?.tenantId. organizationIdForMetaWrite deliberately lands allowOrgOverride: false types env-wide under the #6190 ruling, so naming the tenant unconditionally would hide those types' rows from an org session — the same defect one type family over. Both of these doors are type-agnostic sweeps, so /meta/diagnostics in particular needs a decision the two doors above did not: it sweeps many types in one request, so the scope is per-type rather than per-request. That is a genuine design question and the reason this is a separate card rather than a rider.

⛔ Do not change getMetaDiagnostics or findReferencesToMeta in protocol.ts — both already read the member correctly; the gap is entirely at the REST call site.

Prior art in this family (all landed)

/audit#8747 · the single-item and list read doors, plus /layers#9727 · the metadata write doors #8805 · the registry-gated predicate #6190 · the URL fold #10340.

Enumeration state as measured on origin/main at the time of writing — every other meta read door in rest-server.ts either forwards the org (/meta/:type list, /meta/:type/:name, /layers, /audit, /published, /_drafts) or is correctly env-wide because its types declare allowOrgOverride: false (/meta/book/:name/tree over book/doc, /meta/object/:name/state/:field over object) or reads no metadata document at all (/meta/types).

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