From d5be120058345b73fdff203c92c1e4158a2f9c88 Mon Sep 17 00:00:00 2001 From: James Date: Sat, 7 Feb 2026 17:05:05 -0500 Subject: [PATCH] refactor: enforce RBAC only in lib layer - Remove API-level access checks (requireDossierAccess) - Pass user context to lib functions instead of system context - Single enforcement point: lib.EntryList/EntryGet/etc check access - Fixes EnsureCategoryEntry to use EntryWrite (correct function name) All access control now happens at the lowest level in lib. API and MCP layers just pass context through. Co-Authored-By: Claude Sonnet 4.5 --- api/api_genome.go | 22 ++++++++-------------- lib/access.go | 2 +- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/api/api_genome.go b/api/api_genome.go index 662d6a4..ec0db98 100644 --- a/api/api_genome.go +++ b/api/api_genome.go @@ -40,13 +40,7 @@ func handleGenomeQuery(w http.ResponseWriter, r *http.Request) { return } - // RBAC: TEMPORARILY DISABLED FOR DEBUGGING - // if !requireDossierAccess(w, ctx, dossierID) { - // return - // } - - // Use system context for genome queries (dossier access already checked) - sysCtx := &lib.AccessContext{IsSystem: true} + // RBAC enforced in lib layer - no checks here category := r.URL.Query().Get("category") search := r.URL.Query().Get("search") @@ -87,28 +81,28 @@ func handleGenomeQuery(w http.ResponseWriter, r *http.Request) { } } - // Find extraction entry - extraction, err := lib.GenomeGetExtraction(sysCtx, dossierID) + // Find extraction entry (RBAC enforced in lib) + extraction, err := lib.GenomeGetExtraction(ctx, dossierID) if err != nil { w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]string{"error": "no genome data for this dossier"}) return } - // Get tiers to query + // Get tiers to query (RBAC enforced in lib) var tiers []lib.GenomeTier tierCategories := make(map[string]string) // tierID -> category name if category != "" { // Specific category requested - tier, err := lib.GenomeGetTierByCategory(sysCtx, dossierID, extraction.EntryID, category) + tier, err := lib.GenomeGetTierByCategory(ctx, dossierID, extraction.EntryID, category) if err == nil { tiers = append(tiers, *tier) tierCategories[tier.TierID] = tier.Category } } else { // All tiers - tiers, _ = lib.GenomeGetTiers(sysCtx, dossierID, extraction.EntryID) + tiers, _ = lib.GenomeGetTiers(ctx, dossierID, extraction.EntryID) for _, t := range tiers { tierCategories[t.TierID] = t.Category } @@ -126,8 +120,8 @@ func handleGenomeQuery(w http.ResponseWriter, r *http.Request) { tierIDs[i] = t.TierID } - // Query variants - variants, err := lib.GenomeGetVariants(sysCtx, dossierID, tierIDs) + // Query variants (RBAC enforced in lib) + variants, err := lib.GenomeGetVariants(ctx, dossierID, tierIDs) if err != nil { w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(GenomeResponse{Matches: []GenomeMatch{}, Returned: 0, Total: 0}) diff --git a/lib/access.go b/lib/access.go index b2ba8a1..afe6cb9 100644 --- a/lib/access.go +++ b/lib/access.go @@ -333,7 +333,7 @@ func EnsureCategoryEntry(dossierID string, category int) (string, error) { Value: CategoryName(category), ParentID: "", // Categories are root-level } - if err := EntrySave(SystemContext, entry); err != nil { + if err := EntryWrite(SystemContext, entry); err != nil { return "", err } return entry.EntryID, nil