feat(abac): user-scoped private Tools/Agents/Skills via allowedPrincipals (#149) - #193
Open
k5s-bot[bot] wants to merge 1 commit into
Open
feat(abac): user-scoped private Tools/Agents/Skills via allowedPrincipals (#149)#193k5s-bot[bot] wants to merge 1 commit into
k5s-bot[bot] wants to merge 1 commit into
Conversation
…pals Resolves #149. Adds an optional `allowedPrincipals` to the Tool, LocalTool, Agent, and Skill CRDs — an ABAC private-scoping layer enforced by the orchestrator ON TOP of the existing RBAC `allowedRoles` filter (ADR 0036). Empty/unset = public (unchanged). Non-empty = private: a caller is a retrieval candidate only if RBAC passes AND their resolved principal (ADR 0030 §6, `identity.principal ?? subject`) is listed. Skills derive their effective private set by intersecting their own list with any private tool/agent they reference, so a skill can never widen a private tool's audience. - core-controller: `AllowedPrincipals` on Tool/LocalTool/Agent/Skill specs; regenerated deepcopy + CRD manifests. - agent-orchestrator: `allowedPrincipals` on the descriptors, read from the CRDs by every registry; `callerPrincipal` added to the tool/agent/skill query filters; enforced in all three Qdrant stores (query + getByIds) via a shared qdrant-abac helper; skill audience derivation extended; graph threads the principal through a single `callerFilter(identity)` at every store call. - Fail-closed and rolling-upgrade safe (explicit `private` flag on upsert). - ADR 0036 + README/docs; unit tests across stores, registries, derivation. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018PGNNomuXvbzwgcaF6gxDb
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.
Resolves #149 ("User Scoped Skills, Agents and Tools").
What & why
The issue asks for a way to mark a Skill, Agent, or Tool as privately scoped
to specific users, in addition to the existing RBAC controls. RBAC today
(
allowedRoles, ADR 0004) gates by role — a class of caller — which can'texpress "only this person (or this handful) may see and use this resource"
without minting a throwaway one-person role and attaching it everywhere.
This adds an optional
allowedPrincipalsto theTool,LocalTool,Agent, andSkillCRDs — an ABAC (attribute-based access control) layer theorchestrator enforces on top of RBAC. The design is written up in
ADR 0036.
Semantics
keeps working unchanged.
when both hold: RBAC passes (
allowedRoles ∩ callerRoles) and thecaller's resolved principal (ADR 0030 §6 —
identity.principal, falling backto
subject; e.g.github:<login>) is one ofallowedPrincipals.allowedPrincipals, and their effective private set is the intersection ofthat with the
allowedPrincipalsof every referenced tool/agent that isitself private — so a skill can never widen a private tool's audience.
Changes
core-controller (Go):
AllowedPrincipals []string(optional) onToolSpec,LocalToolSpec,AgentSpec,SkillSpec, with doc comments.zz_generated.deepcopy.goand the CRD manifests underconfig/crd/basesviamake generate manifests(chartcrds/copies aregitignored build artifacts, synced by the same target).
agent-orchestrator (TS):
allowedPrincipalsonToolDescriptor/AgentDescriptor/SkillDescriptor,read from the CRDs by every registry.
callerPrincipaladded to the tool/agent/skill query filters and enforced inall three Qdrant stores (
query+getByIds) via a sharedvector-store/qdrant-abac.tshelper (payload gainsallowedPrincipals+ adenormalized
privateflag; the filter ANDs apublic OR names-meclause).derive-access.tsextended to derive the skill's effective principal set.graph.tsthreads the principal through onecallerFilter(identity)used atevery store
query/getByIdssite — so ABAC is enforced identically on RAGretrieval, the active-skill/active-agent re-checks, IntegrationRoute forced
targets, and a skill's tool resolution. A private resource never enters the
candidate/skill-tool set, so it can never be planned or launched.
Docs/tests: ADR 0036 (+ index), orchestrator README, and unit tests across
the stores, registries, and skill-access derivation (incl. inheritance,
intersection, disjoint/unreachable, and private-respond-only cases).
Verification
apps/agent-orchestrator:tsc --noEmitclean; full vitest suite 592passed.
controllers/core-controller:go build ./...andgo vet ./api/...clean;make generate manifestsregenerates cleanly.Notes / out of scope
allowedPrincipalsgates discovery & selection; it's orthogonal toidentityProviders(which governs whose credential a launch runs with).creating user as an owner, and any management UI — listing principals on the
CR is the v1 scope; groups can layer on later without changing the filter.
Maintainer: apply the ai-review label to this PR to request an automated
code review, or the ai-triage label to have review feedback addressed and
the branch brought back in sync with its base. (The automation can't label its
own PR, so this needs a human.)