Skip to content

Add per-toolkit access-group grants - #1598

Open
TheLiberal wants to merge 3 commits into
UsefulSoftwareCo:mainfrom
TheLiberal:access-groups/2-toolkit-grants
Open

Add per-toolkit access-group grants#1598
TheLiberal wants to merge 3 commits into
UsefulSoftwareCo:mainfrom
TheLiberal:access-groups/2-toolkit-grants

Conversation

@TheLiberal

Copy link
Copy Markdown

Stacked on #1597 — includes its commits until it merges; only the last commit is new here.

A toolkit granted to a group exists only for that group's members: its slug resolves to nothing for anyone else (a toolkit MCP session then blocks everything, identical to an unknown slug) and its CRUD reads answer not-found — the same restricted-is-invisible rule #1597 applies to connections.

  • accessGroup is an optional field on the toolkit record (absent = unrestricted, so every pre-existing record keeps its semantics); gates in getBySlugEntry / requireToolkit / list read membership live per call through a new read-only plugin core seam, ctx.core.accessGroups.visibleGroupIds().
  • Grants are managed via setAccessGroup / listRestrictedToolkits on the toolkits extension, exposed only on the host admin planes — deliberately not on the member-facing toolkit routes. The management path reads the raw record so an admin can ungrant a toolkit they are not a member of; their runtime view stays filtered like everyone's.
  • Group deletion now also refuses while a toolkit grant references the group (the engine covers connections; toolkit grants live in plugin storage the engine cannot see, so the host plane holds that line).

Tests: toolkit visibility/grant suite (member vs non-member slug resolution, admin-runtime-filtered, live ungrant, personal/unknown-toolkit rejection) plus the self-host node test extended with the toolkit-grant HTTP round trip and the delete-while-granted refusal.

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.
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