Add the access-groups console UI - #1599
Open
TheLiberal wants to merge 4 commits into
Open
Conversation
Tenant-scoped access_group/access_group_member tables plus a nullable connection.access_group column. A restricted org connection is invisible and uninvokable for non-members on every read and invoke surface, with no existence oracle; membership is read live per call. Management rides executor.accessGroups behind host admin gates (cloud /org/access-groups*, self-host /api/admin/access-groups*), never the any-member ExecutorApi. Platform view and subject-less org bindings stay unfiltered by design.
The cascade tripwire caught the gap: the hand-written purge list must name every tenant table, and access_group/access_group_member were missing.
A toolkit granted to a group exists only for its members: the slug resolves to nothing for anyone else (toolkit MCP sessions block-all, identical to an unknown slug) and its CRUD reads answer not-found. Grants are managed through the extension's setAccessGroup, exposed only on the host admin planes; the group-deletion path refuses to orphan a toolkit grant. Plugins gain a read-only core seam (accessGroups.visibleGroupIds) to apply the same restricted-is-invisible rule core applies to connections.
A shared admin page at /access-groups (the /users pattern): groups CRUD, a member roster joined to /account/members identities with a picker, and the connection/toolkit restriction lists with a restrict-connection dialog. The API definition moves into @executor-js/api with both hosts serving identical /admin/access-groups* routes, so ONE shared client and atom set works everywhere; cloud additionally gains the mount on its production extension-routes root. The access-groups segment joins the reserved org slugs so no org can shadow the console route.
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.
Stacked on #1597 and #1598 — includes their commits until they merge; only the last commit is new here.
The admin console for access groups, following the
/userspattern end to end:@executor-js/api(admin/access-groups-api.ts) and both hosts serve identical/admin/access-groups*routes (the endpoints are new on this stack, so cloud's briefly-divergent/org/*paths are dropped rather than kept), which lets ONE shared client work everywhere — same construction asAdminApiClient./access-groups: groups CRUD, a per-group member roster joined client-side to/account/membersidentities (userIdis the same principal id the group API stores) with a picker, the connection/toolkit restriction lists read from the unfiltered admin plane (an admin's own product listings are group-filtered like everyone's), and a restrict-connection dialog fed by the admin's visible org connections. 401/403 renders an explicit denied state.console-routes.ts(excluded on local/desktop and host-cloudflare, which serve no admin plane), admin-gated nav entries on both hosts via the existinguseAdminNavItemsgate, andaccess-groupsadded toRESERVED_ORG_SLUGSso no org slug can shadow the console route (the route-contract test enforces this).extensions/routes.ts) — the earlier mount only coveredmakeApiLive.Verified in the browser against a booted self-host dev instance (group create, member sheet + picker, restriction lists) and over HTTP with two accounts: admin gate 401/403, restricted connection and toolkit invisible to non-members including the admin's own runtime and
includeBlocked=true, grant/revoke applying on the next call of an open token, and group deletion refused while referenced.