merge: integrate v7-rbac-visibility on top of skills feature
Brings together the two unmerged feature lines onto one integration branch: - skills/review/proposals/revisions (via fix/mcpd-instance-health-and-retry, which contains the full skills-1..7 chain + mcpd env/retry/readiness fix) - v7 visibility scope + ownership for Llms and Agents Auto-merge resolved schema.prisma, mcpd main.ts, mcplocal config, CLI create, and completions with no conflicts. Both Prisma migrations coexist. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
-- v7: per-user RBAC scoping for virtual Llms and Agents.
|
||||
--
|
||||
-- `Llm.ownerId` is new — we don't have a record of who created legacy
|
||||
-- rows, so existing data is left NULL (treated as "no owner, public").
|
||||
-- The list/get filter in the service layer handles NULL ownerId
|
||||
-- correctly: a NULL-owner public row stays visible to everyone.
|
||||
--
|
||||
-- `Llm.visibility` and `Agent.visibility` default to 'public' so the
|
||||
-- backfill is automatic — pre-v7 setups continue to behave identically.
|
||||
-- New rows created post-deploy carry the value the service writes
|
||||
-- (mcplocal virtuals → 'private'; CLI `mcpctl create llm` → 'public'
|
||||
-- by default unless `--visibility private` is passed).
|
||||
|
||||
ALTER TABLE "Llm"
|
||||
ADD COLUMN "ownerId" TEXT,
|
||||
ADD COLUMN "visibility" TEXT NOT NULL DEFAULT 'public';
|
||||
|
||||
ALTER TABLE "Agent"
|
||||
ADD COLUMN "visibility" TEXT NOT NULL DEFAULT 'public';
|
||||
|
||||
-- Composite index supports the list-filter hot path:
|
||||
-- `WHERE visibility='public' OR ownerId=$1`
|
||||
-- on tables that may grow as more publishers / users come online.
|
||||
CREATE INDEX "Llm_visibility_ownerId_idx" ON "Llm"("visibility", "ownerId");
|
||||
CREATE INDEX "Agent_visibility_ownerId_idx" ON "Agent"("visibility", "ownerId");
|
||||
@@ -225,6 +225,30 @@ model Llm {
|
||||
lastHeartbeatAt DateTime? // bumped on every publisher heartbeat
|
||||
status LlmStatus @default(active)
|
||||
inactiveSince DateTime? // when status flipped from active; used for 4-h GC
|
||||
// ── Per-user RBAC scoping (v7) ──
|
||||
// `ownerId` records who created/published the row. NULL on legacy rows
|
||||
// (those created before the v7 migration) — those continue to behave
|
||||
// as `visibility=public` for back-compat. New rows always carry an
|
||||
// ownerId set by the service layer (`User.id` of the authenticated
|
||||
// caller, or the publishing mcplocal user for virtuals).
|
||||
//
|
||||
// `visibility` controls who can see / use the row:
|
||||
// - 'public' : anyone with the resource grant (`view:llms`,
|
||||
// `run:llms:<name>`, etc.) sees it. Legacy default
|
||||
// mirrors today's behavior — explicit
|
||||
// `mcpctl create llm` calls keep this default.
|
||||
// - 'private' : only the owner sees it by default; other users need
|
||||
// an explicit name-scoped RBAC binding
|
||||
// (`view:llms:<name>`, `run:llms:<name>`). The list
|
||||
// endpoint hides foreign-private rows from
|
||||
// unauthorized callers; get/describe returns 404 to
|
||||
// prevent name enumeration.
|
||||
//
|
||||
// mcplocal-published virtual Llms default to 'private' on register —
|
||||
// a workstation-published model isn't typically meant for the whole
|
||||
// org until the publisher explicitly shares it. See docs/virtual-llms.md.
|
||||
ownerId String?
|
||||
visibility String @default("public")
|
||||
version Int @default(1)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
@@ -238,6 +262,10 @@ model Llm {
|
||||
@@index([kind, status])
|
||||
@@index([providerSessionId])
|
||||
@@index([poolName])
|
||||
// List filter on the hot path: "rows visible to caller X" decomposes
|
||||
// into `visibility='public' OR ownerId=X` + an RBAC join. Composite
|
||||
// index keeps the predicate fast even on a large table.
|
||||
@@index([visibility, ownerId])
|
||||
}
|
||||
|
||||
// ── Groups ──
|
||||
@@ -641,6 +669,14 @@ model Agent {
|
||||
status LlmStatus @default(active)
|
||||
inactiveSince DateTime?
|
||||
ownerId String
|
||||
// v7: per-user RBAC scoping. Mirrors `Llm.visibility` semantics —
|
||||
// 'public' (default, today's behavior) lets anyone with the resource
|
||||
// grant see the agent; 'private' restricts to owner + explicit
|
||||
// name-scoped RBAC bindings. mcplocal-published virtual agents
|
||||
// default to 'private' on register so a workstation-published persona
|
||||
// isn't broadcast to the whole org until shared explicitly. Existing
|
||||
// rows backfill to 'public' so pre-v7 setups keep working unchanged.
|
||||
visibility String @default("public")
|
||||
version Int @default(1)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
@@ -662,6 +698,7 @@ model Agent {
|
||||
@@index([defaultPersonalityId])
|
||||
@@index([kind, status])
|
||||
@@index([providerSessionId])
|
||||
@@index([visibility, ownerId])
|
||||
}
|
||||
|
||||
// ── Personalities (named overlay bundles of prompts on top of an Agent) ──
|
||||
|
||||
Reference in New Issue
Block a user