-- Read-only DB role for vision-manager. -- -- The sidecar only needs to count pending analysis work; give it SELECT on -- crawler_jobs and nothing else. It must NOT reuse the backend's credentials. -- -- The Postgres service mounts no init dir and the data volume already exists, -- so this is applied ONCE by an operator (it is idempotent): -- -- docker compose exec -T postgres \ -- psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -v pw="" \ -- -f - < vision-manager/readonly-role.sql -- -- Then point the manager at it (VISION_MANAGER_DATABASE_URL in .env): -- postgres://vision_manager:@postgres:5432/ -- -- The password is passed via psql's -v pw=... ; psql substitutes :'pw' as a -- quoted literal and :"DBNAME" (psql's built-in) as the current db identifier. -- These substitutions only happen in plain statements, NOT inside a -- dollar-quoted DO block — hence the \gexec form below. -- Create the LOGIN role only if it is absent (idempotent). SELECT 'CREATE ROLE vision_manager LOGIN' WHERE NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'vision_manager') \gexec -- (Re)set the password every run so rotating it is just a re-apply. ALTER ROLE vision_manager LOGIN PASSWORD :'pw'; -- CONNECT to the current database, and read-only on the one table we poll. GRANT CONNECT ON DATABASE :"DBNAME" TO vision_manager; GRANT USAGE ON SCHEMA public TO vision_manager; GRANT SELECT ON crawler_jobs TO vision_manager;