Skip to content

Commit 9d95500

Browse files
committed
chore(changeset): the body read refusal ships as a narrowing (wip)
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016GiHYRmLSNWTfbX9gVQkpz
1 parent 269f49d commit 9d95500

2 files changed

Lines changed: 21 additions & 2 deletions

File tree

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
'@objectstack/runtime': minor
3+
---
4+
5+
fix(runtime)!: an app-authored body may not read the stored-metadata tables either; it reaches them through the metadata API only (#21594)
6+
7+
Clause-②: yes (narrowing)
8+
9+
<!-- adr-0087: not-required (no-migration-prescription) no metadata body, authorable key, spelling, export or stored shape moves; what changes is which reads a sandboxed hook, action or job body may make of the two stored-metadata tables, so `objectstack migrate meta` has nothing to rewrite. The other categories are closed on facts: the package publishes (not `unpublished`); no ADR-0087 id covers a refused read (not `registered` / `already-registered`); and the change is runtime behaviour, not a declaration (not `runtime-interface-only` / `type-surface-only`). -->
10+
11+
**BREAKING**: this narrows what an app-authored body may do with the two stored-metadata tables, `sys_metadata` and `sys_metadata_history`. With the binding and write refusals already in this release, an app-authored body now reaches them through the metadata API only.
12+
13+
- **Reading.** A sandboxed hook, action or job body's read of either table through `ctx.api` answers `PERMISSION_DENIED` / 403 before the read runs. That covers `find`, `findOne`, `count` and `aggregate`, inside a transaction or not, with or without elevation, and whatever filter, sort, grouping, search or projection the read carries. A body is served nothing of these tables, neither the stored row nor a projection of it, and the answer does not depend on what the read asks. A hook body that reads them fails the write that fired it.
14+
- **FROM → TO.** FROM a body reading `ctx.api.object('sys_metadata')` or `ctx.api.object('sys_metadata_history')`, which was served the body projected and the content hash keyed, TO the metadata API: `GET /api/v1/meta/:type/:name` for a definition, and `GET /api/v1/meta/:type/:name/history` for its versions. The one-line fix is to move the read out of the body, to the metadata API or to host code. No shipped example reads either table from a body.
15+
- **This supersedes, for bodies, two earlier entries of this release:** the served read of these tables, and the evaluate-shape refusals (`INVALID_FIELD` / 400) and default-search narrowing of that read. For a body, all of these now give way to this refusal. It also supersedes the binding-and-write entry's note that a body's reads are unchanged.
16+
- **Unchanged:** host code that registers its own action handlers (its `ctx.api` and `ctx.engine.find` are still served as the generic data door serves these tables, with the door's evaluate refusals); the binding and write refusals; the platform's own readers; the generic data door and the metadata API; and every other object.
17+
18+
It ships as `minor` under the launch-window convention for accept-set narrowings.

‎packages/runtime/src/stored-metadata-reader-seam.test.ts‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55
* reads it serves, through which derived contexts, and that it serves each one
66
* exactly once. The composed contexts are pinned end to end, against the data
77
* door, in `stored-metadata-reader-contexts.pin.test.ts`; this file holds the
8-
* routes a body or handler can take around the seam that the composition does
9-
* not exercise one by one.
8+
* routes a handler can take around the seam that the composition does not
9+
* exercise one by one. [#21594] A sandboxed body is not served here: its body
10+
* layers refuse a family read first (`stored-metadata-body-reads.test.ts`).
1011
*/
1112

1213
import { describe, it, expect } from 'vitest';

0 commit comments

Comments
 (0)