test(visibility): full suite green under RLS — sync paths, device-auth bridge, seed pool

Phase 5 (plan §7): the entire integration suite passes with the RLS
policies live. The suite was the triage enumerator the plan predicted:

- device_auth middleware: the THIRD identity bridge — KOReader/Kobo
  device-authenticated requests read media as the DEVICE OWNER
  (plan A9 called this path out; the flip was 404s on sync metadata).
- conflicts/analytics/progress handlers: detached
  context.Background() reads threaded to the request context (the
  requesting user's identity) — 12+ sites; resolve helpers take ctx.
- scanner: ScanFolders self-declares its configured admin identity
  (server maintenance, product-correct for any caller); generic job
  creation stamps the requesting admin.
- harness: setup.DBPool and the sync-test pool declare
  rls.SeedIdentity at SESSION scope via BeforeAcquire — the pool never
  serves a second identity, so no A3 bleed; setup.DB falls back to the
  seed identity (NewSeedDB) for ungoverned-context calls; filter tests
  use seedExec for raw governed-table statements.
- contract pin WIDENED (docs/contract_pins.md 2026-10-29): under RLS,
  item-scoped gates may answer 404 (row invisible — no existence leak)
  as well as 403 (Go-level checks on listings keep strict 403).
- TestWorker_JobStatusTracking — the pre-existing red from the Phase 0
  baseline — passes with the harness seed work; no product change.
This commit is contained in:
John O'Keefe committed 2026-10-29 10:14:08 -04:00
1 parent bb2cc26e9d
commit 4d697f5fcf
7 files changed
+84 -38

No files matched your search

+8 -1
View File
@@ -3,6 +3,7 @@ package main
import (
"bookhoard/internal/config"
"bookhoard/internal/database"
"bookhoard/internal/rls"
"context"
"net/http"
"net/http/httptest"
@@ -10,6 +11,7 @@ import (
"time"
"github.com/google/uuid"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgtype"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/stretchr/testify/assert"
@@ -26,11 +28,16 @@ func setupSyncTestDB(t *testing.T) *database.Queries {
dbConfig, err := pgxpool.ParseConfig(dbURL)
require.NoError(t, err, "Failed to parse database URL")
dbConfig.MaxConns = 1
// Harness-only session identity (plan §5): see setupTestServer.
dbConfig.BeforeAcquire = func(ctx context.Context, conn *pgx.Conn) bool {
_, err := conn.Exec(ctx, `SELECT set_config('app.user_id', $1, false)`, rls.SeedIdentity.String())
return err == nil
}
dbPool, err := pgxpool.NewWithConfig(ctx, dbConfig)
require.NoError(t, err, "Failed to connect to test database")
db := database.New(dbPool)
db := database.New(database.NewSeedDB(dbPool))
t.Cleanup(func() {
// Scoped wipes ONLY: reading_history now carries real captured
// sessions for the shared dev accounts, so a table-wide DELETE