Skip to content

@objectstack/verify's bootStack ignores an app's isDefault permission set, while the CLI honours it — after #5491 a dogfood app cannot test its own declared baseline #7001

Description

@os-zhuang

Filed by the repo:cloud seat per the cross-seat transfer protocol (file, do not dispatch). Unassigned, pm:queue only — routing left to the triage seat. Found while executing cloud's pin move onto 68feaadd (cloud#1197 / cloud#1219); measured empirically, not inferred.

The asymmetry

Two boot paths disagree about whether an application's declared default profile exists.

  • CLI honours itpackages/cli/src/commands/serve.ts:2008 reads appDefaultPermissionSetName(config.permissions) and passes it as new SecurityPlugin({ fallbackPermissionSet }).
  • bootStack does notpackages/verify/src/harness.ts defaults to a vanilla new SecurityPlugin() and never reads config.permissions.

So the profile an app declares is wired when a human runs objectstack dev, and silently absent when the app's own dogfood suite boots it.

Why it matters now, and not before

Before #5491 (9e9445ba, "the platform baseline becomes explicit-allow") the platform's member_default carried an object_permissions["*"] wildcard, so a member with no application profile still reached every object. The gap was invisible: the fallback profile was never load-bearing, because the floor underneath it granted everything anyway.

#5491 removed that floor deliberately (its own measurement: 21 of 21 create-DENIAL probes returned 201; public_read objects answered 200 with ALL rows to non-holders), and its Migration section prescribes exactly one consumer action:

Ship an app default profile. Mark a permission set isDefault: true… list the objects members legitimately touch, with the axes they need.

That prescription is not expressible through bootStack today. Measured in objectstack-ai/cloud@apps/ee-group-showcase while attempting the prescribed migration: adding definePermissionSet({ isDefault: true, … }) plus permissions: to the app config changed nothing — the same 6 acceptance cases still failed at the object gate. The attempt was reverted rather than worked around.

The only way for a dogfood suite to exercise its own declared baseline is to hand-construct a SecurityPlugin in each suite — which is itself the "custom security code" that several of these apps exist to prove is unnecessary (ADR-0105 Phase 1 acceptance, framework#3541).

Why this is a defect and not a preference

It is a declared ≠ enforced split inside the test harness that exists to catch that split. An app can declare a profile, ship it to users through the CLI path, and have every one of its own tests run against a boot that does not include it — green tests, different production behaviour. The class is the same one #5852 and framework#3695 came from: the context the tests feed is not the context the real seam produces.

Suggested shape (not a ruling — the harness is not this seat's to design)

Make bootStack resolve the app-declared default the same way serve.ts does, so the two boot paths agree by construction rather than by each caller remembering. If a suite deliberately wants the vanilla baseline, that should be the explicit opt-out, not the silent default. A conformance-style assertion that "the profile bootStack wires equals the profile serve wires for the same config" would keep the two from drifting apart again.

Blast radius

Every apps/*-showcase dogfood suite in objectstack-ai/cloud, and any framework-side suite booting through verify that relies on an app profile after #5491. Consumer context and the full three-axis analysis of the cloud-side half are on objectstack-ai/cloud#1219 (that card is needs-user-decision for a separate reason — which control-plane objects members may read — and this gap is one of the two sub-questions it names).

Dedup: searched open issues for bootStack / fallbackPermissionSet / verify harness SecurityPlugin isDefault — zero hits before filing.

Refs: objectstack-ai/cloud#1219, objectstack-ai/cloud#1197, #5491, #5492, #3541, ADR-0105.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions