fix(security,hono): /me/apps registry + capability resolution; anchor-bindable member_default (ADR-0090 D5)#2773
Merged
Merged
Conversation
…tion; member_default becomes anchor-bindable (ADR-0090 D5) #2752 — GET /me/apps read metadata.list('app') while stack apps live in the ENGINE REGISTRY, returning [] for every principal; and its capability/tab filters read execCtx fields that resolveCtx never populates, so even after sourcing the registry every requiredPermissions app was hidden from everyone, including the platform admin. It now reads registry.getAllApps() (nav contributions merged, metadata service as additive fallback) and resolves the caller's effective systemPermissions/tabPermissions the same way /auth/me/permissions does. The DB permission-set loader also carries system_permissions/tab_permissions now (direct grants of e.g. setup.access used to vanish at this endpoint). #2753 — the everyone-anchor gate refused the platform's own baseline on every boot ("refusing to bind fallback set to everyone"). Two aligned changes: describeHighPrivilegeBits is calibrated to the exact ADR-0090 D5 bit list (the blanket '*' wildcard rejection moves to the GUEST tier where D9 specifies it), and member_default drops allowDelete from its wildcard. BEHAVIOR: deleting records is no longer a baseline right — members keep create/read/edit-own; the owner-scoped delete RLS stays as a narrowing defense. Bootstrap's existing binding path now succeeds: "what new users get" is literally "what is bound to everyone" (one channel, D5), proven by the new me-apps-and-everyone-baseline dogfood (5 tests) and live browser checks (admin sees setup via setup.access; member does not). #2754 investigated, not reproducible: the enterprise organizations package does not exist yet and cloud's multi-org wiring imports the retired plugin-org-scoping (filed cloud#796); design options recorded on the issue. Access-pillar dogfood findings filed: objectui#2381 (explain panel cannot target another user despite full REST/D12 support), objectui#2382 (已分配用户 counts direct grants only — position-held users show as 0). Closes #2752. Closes #2753. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
📓 Docs Drift CheckThis PR changes 4 package(s): 98 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #2752, closes #2753 — the two remaining permission-runtime issues from the ADR-0090 dogfood series. Also records the #2754 investigation and two new Access-pillar findings.
#2752 —
/me/appswas dead, twice overmetadata.list('app')while stack apps are registered into the engine registry (runtime AppPlugin) →{"apps":[]}for every principal, leavingtabPermissionsandAppSchema.requiredPermissionswith no enforced consumer. Now sourcesregistry.getAllApps()(nav contributions merged; metadata service as additive fallback).execCtx.systemPermissions/tabPermissions, whichresolveCtxnever populates — so even with apps listed, everyrequiredPermissionsapp was hidden from the platform admin too. The endpoint now resolves the caller's effective surface the same way/auth/me/permissionsdoes (evaluator + bootstrap + metadata + DB loader), and the DB loader finally carriessystem_permissions/tab_permissions(a direct grant ofsetup.accessused to vanish here).Live proof (fresh boot): admin
/me/apps→['account', 'setup', 'showcase_app'](setup via thesetup.accesscapability); plain member →['account', 'showcase_app']; anonymous →[]. (Studio's absence is by design — serve.ts deliberately doesn't load@objectstack/studioas an app tile.)#2753 — the baseline now actually binds to
everyoneEvery boot logged
refusing to bind fallback set to everyone — high-privilege bits {"set":"member_default","offending":"delete/purge/transfer on '*'"}— the platform's own default violated its own D5 tier and flowed through the separate fallback channel D5 explicitly rejected. Two aligned changes:describeHighPrivilegeBitscalibrated to the ADR text (D5 lists exactly VAMA, delete/purge/transfer, systemPermissions). The blanket'*'-wildcard rejection was an over-tightening — it moves to the guest tier where D9 specifies it ("explicit objects only"). Spec + lint + runtime gate share the predicate, so all three surfaces stay in lockstep;check:api-surfaceunchanged.member_defaultdropsallowDeletefrom its wildcard.With the baseline anchor-safe, bootstrap's existing binding path succeeds: "what new users get" ≡ "what is bound to
everyone" — same table, audit, and explain path. Proven by the newme-apps-and-everyone-baselinedogfood (5 tests: registry-sourced app list, capability gating, anonymous empty, the everyone←member_default binding row, and the delete-refusal).#2754 — investigated, not currently reproducible
The enterprise
organizationspackage does not exist yet, and cloud's multi-org wiring still imports the retiredplugin-org-scoping(dead code — filed objectstack-ai/cloud#796). Design options recorded on #2754 for whoever lands the package.Access-pillar dogfood (business-admin walkthrough on this branch's build)
Worked: matrix edit → draft → 变更 badge; per-object OWD+Ext badges; suggested-binding lifecycle (
/security/suggested-bindingsshows the showcase everyone-suggestionconfirmed); explain panel end-to-end for self; REST explain-another-user with D12 authorization. Filed:Verification
126/126 turbo tasks green (incl. all dogfoods with the new baseline posture); live browser + REST checks above on a fresh
--ui --seed-adminboot.🤖 Generated with Claude Code