Skip to content

Add the access-groups console UI - #1599

Open
TheLiberal wants to merge 4 commits into
UsefulSoftwareCo:mainfrom
TheLiberal:access-groups/3-console-ui
Open

Add the access-groups console UI#1599
TheLiberal wants to merge 4 commits into
UsefulSoftwareCo:mainfrom
TheLiberal:access-groups/3-console-ui

Conversation

@TheLiberal

@TheLiberal TheLiberal commented Aug 15, 2026

Copy link
Copy Markdown

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 /users pattern end to end:

  • The HTTP contract moves into @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 as AdminApiClient.
  • Shared page at /access-groups: groups CRUD, a per-group member roster joined client-side to /account/members identities (userId is 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.
  • Route registered in console-routes.ts (excluded on local/desktop and host-cloudflare, which serve no admin plane), admin-gated nav entries on both hosts via the existing useAdminNavItems gate, and access-groups added to RESERVED_ORG_SLUGS so no org slug can shadow the console route (the route-contract test enforces this).
  • Cloud gains the mount on its production composition root (extensions/routes.ts) — the earlier mount only covered makeApiLive.

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.

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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant