feat(db): RLS library-visibility enforcement — invariant GREEN
The dashboard leak is closed at the database engine. The black-box
invariant (restricted user + hidden library => absent from every
media-returning surface) went RED->GREEN with this change set; clause-
protected surfaces never regressed, proving enforcement came from the
policies, not the test.
Phase 3 of plan ~/.opencode/plan/server-rls-library-visibility.md:
- schema.sql: idempotent RLS block — ENABLE + FORCE on media_items,
SELECT policy mirroring COALESCE(is_visible,true) exactly, permissive
per-command write stand-ins (FOR ALL would OR into SELECT).
- internal/rls + internal/database/scoped.go: ScopedDB declares the
acting user per statement (LOCAL GUC). DESIGN CORRECTION during
execution: the decorator never refuses — the ENGINE is the fail-loud
layer (policies raise on governed tables; auth lookups and settings,
ungoverned, simply work). A decorator refusal would have been a new
convention gate — plan B thinking — and broke login (chicken-and-egg:
credentials are checked before any identity exists).
- database/schema.go: the migration tx declares a synthetic identity —
schema.sql's dedup DO block SELECTs media_items, which raises once
policies are live (plan A11). Caught by the two-boot gate: boot 1
created the policies after the block ran; boot 2 raised.
- router.go: RLS bridge at BOTH c.Set("user") sites (JWT + device
auth) — echo-local c.Set never reaches the stdlib ctx the DB layer
receives.
- search: the search service's raw DBTX path receives the ScopedDB
itself, never the bare pool.
- harness: the server under test is wired exactly like main.go; the
seed handle is also ScopedDB-wired but carries seedCtx() — a
synthetic identity with no visibility rows — because sqlc :one
inserts use RETURNING, which evaluates the SELECT policy even on
INSERT. Regex UUID-scraping in the invariant replaced with a
structured JSON decode.
- invariant test: RED -> GREEN across every surface incl. View All;
403 pins and admin-scoping pins hold.
This commit is contained in:
1 parent
8c3d919aa0
commit
922b92a8b6
5 files changed
+6
-13
No files matched your search
@@ -2,7 +2,6 @@ package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
@@ -367,8 +366,6 @@ func TestPreviewCollection(t *testing.T) {
|
||||
}
|
||||
|
||||
func createPreviewTestMediaItems(t *testing.T, db *database.Queries, libraryID string, count int) []string {
|
||||
ctx := context.Background()
|
||||
|
||||
libUUID, err := uuid.Parse(libraryID)
|
||||
require.NoError(t, err, "Should parse library ID")
|
||||
|
||||
|
||||
Reference in new issue
Block a user