Files
bookhoard/docker-compose.dev.yml
T
John O'Keefe cb258b6d20 feat(db): dedicated non-superuser runtime role for RLS
The app connected as 'postgres' — the bootstrap SUPERUSER — which
bypasses row-level security unconditionally (FORCE RLS does not apply
to superusers), making any future policy a silent no-op. This is the
prerequisite commit for the RLS visibility work (plan
~/.opencode/plan/server-rls-library-visibility.md REV 2, §4.0).

What changed:
- database/schema/z_rls_role.sh: creates the bookhoard_srv role
  (LOGIN, non-superuser, non-bypassrls) and transfers ownership of
  every public table/sequence/function + schema + database to it.
  Ownership (not mere grants) because executeSchema re-runs the whole
  schema.sql on EVERY boot and needs owner DDL. Idempotent, catalog-
  only — no user data is read or written.
- docker-compose.yml app service + docker-compose.dev.yml tests
  service: DATABASE_USER postgres -> bookhoard_srv, DATABASE_PASSWORD
  DBPASS -> DBSRVPASS (new .env key, generated locally).
- POSTGRES_USER: postgres stays as the container bootstrap account;
  on FRESH volumes z_rls_role.sh runs automatically via
  docker-entrypoint-initdb.d AFTER schema.sql (alphabetical: z > s).

Verified on the dev stack: role has rolsuper=f, rolbypassrls=f, owns
all 40 tables and every public function; single boot as bookhoard_srv
executed schema.sql cleanly (CREATE EXTENSION IF NOT EXISTS pg_trgm
skips fine as non-superuser when the extension exists); health +
authenticated smoke pass. Behavior otherwise unchanged — no policies
yet.
2026-10-29 08:02:34 -04:00

60 lines
1.9 KiB
YAML

# Development override — merged on top of docker-compose.yml (the base/prod file).
# Activated by all `make` targets via:
# COMPOSE = <runtime> compose -f docker-compose.yml -f docker-compose.dev.yml
#
# What this adds over prod:
# - Local image BUILDING (prod pulls a prebuilt image from the registry)
# - The integration-tests service (dev only, gated behind the "tests" profile)
# Everything else (env vars, volumes, ports, healthchecks) is inherited from the base file.
services:
# Build the app image locally instead of pulling from the registry
app:
build:
context: .
dockerfile: ./Dockerfile
# Integration Tests - runs against containerized app and db (dev only)
tests:
build:
context: .
dockerfile: ./Dockerfile
target: test-runner
container_name: bookhoard_tests
environment:
# Database Configuration
# Runtime role = bookhoard_srv (non-superuser OWNER, subject to RLS
# via FORCE) — same role the app service uses.
DATABASE_HOST: db
DATABASE_PORT: ${DB_PORT:-5432}
DATABASE_USER: bookhoard_srv
DATABASE_PASSWORD: ${DBSRVPASS}
DATABASE_NAME: bookhoard
COOKIE_SECURE: false
# Application Configuration
JWT_SECRET: ${JWT_SECRET}
SERVER_PORT: ${SERVER_PORT:-8765}
# Test Configuration
TEST_MODE: "true"
RATE_LIMIT_ENABLED: "false"
REQUESTS_PER_MINUTE: 1000
# Conversion Service Configuration
BOOKHOARD_CONVERSION_CACHE_DIR: /app/cache/kepub
BOOKHOARD_CONVERSION_TOOL: /usr/bin/kepubify
BOOKHOARD_CONVERSION_CACHE_TTL: 24h
# Test upload path (inside container)
TEST_UPLOAD_PATH: /app/uploads
depends_on:
db:
condition: service_healthy
app:
condition: service_healthy
volumes:
- ./uploads:/app/uploads
- bookhoard_conversion_cache:/app/cache/kepub
profiles:
- tests