ADR-021: Database Roles And Agent Isolation
Geliştirme · 0.0.0-dev
Yayın
- Doküman
- 0.0.0-dev
- Uygulama
- 0.0.0
Bu sayfa
- Uygulama
- 0.0.0
- Status: Accepted
- Date: 2026-08-18
- Roadmap task: F1-031
- Decision owners: database platform and execution security maintainers
Context
Bölüm başlığı “Context”Münderecat needs migration, runtime, curation, audit and legacy-reading capabilities with materially different privilege boundaries. A single local administrator credential would collapse those boundaries and would also let parallel agents mutate shared state. The bootstrap plan further forbids issuing write-agent credentials until F1-033 certifies the complete execution chain.
ADR-015 selected Supabase CLI as the canonical local topology, but recorded that Docker Desktop can ignore the bridge’s requested loopback binding and publish CLI-managed ports on wildcard interfaces. Real corpus data or writable credentials cannot be admitted while that condition is only a warning.
PostgreSQL references:
Decision
Bölüm başlığı “Decision”Capability roles
Bölüm başlığı “Capability roles”The migration creates eight idempotent, NOLOGIN, NOINHERIT capability
roles: legacy_reader, agent_local_owner, ci_migrator, app_runtime,
curation_executor, prod_migrator, auditor and break_glass_owner.
All are NOSUPERUSER, NOCREATEDB, NOCREATEROLE, NOREPLICATION and
NOBYPASSRLS. PostgreSQL 17 records the non-superuser role creator with
ADMIN TRUE, SET FALSE, INHERIT FALSE; the live gate permits only this
non-exercisable administrative edge and rejects every usable or external
membership. It also requires that no role can become the migration creator,
which closes transitive control of that administrative edge. The human-only
break-glass capability has no login or repository
issuance path; any incident-scoped elevation remains an external two-approval
operation. Read-only roles set
default_transaction_read_only=on.
Database and public-schema grants are explicit. app_runtime and
curation_executor receive no direct table privilege and no routine execute in
this foundation migration. Future core/RPC migrations must name their grants.
Default privileges for all migration-owner capabilities remove PUBLIC table,
sequence, routine and type access, preventing a newly created object from
silently widening the runtime surface.
config/db-access-policy.yml is the machine-readable intent. A static verifier
checks its closed schema and security invariants; a live verifier compares
pg_roles, role settings, database/schema capabilities, memberships and public
ACLs after migration replay.
Agent database isolation
Bölüm başlığı “Agent database isolation”Every write-capable packet gets a separate Supabase CLI project and Docker network, not merely another database in a shared mutable cluster. Its identity and three-port allocation are deterministic from packet ID; occupied ports fail before startup. Its 256-bit random password is not deterministic and is never placed in argv, stdout, Git or execution evidence.
The lifecycle order is fixed:
- Validate packet, registered worktree, active lease and holder identity.
- Validate the F1-033 trusted readiness receipt from Git common metadata.
- Reserve a packet-unique identity and free port set.
- Materialize canonical config and migrations outside the repository.
- Create the packet network and start its Supabase CLI stack.
- Discover every container carrying the packet’s Supabase project label, then verify all published bindings and non-loopback reachability.
- Create the packet login, grant only
agent_local_ownermembership and make that login owner of the disposable database/public schema. - Write a mode-
0600credential file as the final step.
Any failure before credential issuance stops the stack without backup, removes
its network and deletes generated state. If cleanup itself fails, state is kept
as cleanup_required; an active container is never hidden by deleting its
record.
Exposure boundary
Bölüm başlığı “Exposure boundary”Canonical and packet startup both discover the complete Supabase project by Docker label, require loopback-only bindings for every published port and run a negative TCP probe from each non-loopback IPv4 and IPv6 host address. The API gateway and PostgreSQL container must exist and publish their exact expected container-port/host-port mappings with no extra published mapping; internal containers may publish none. Wildcard publication anywhere in the project is a hard failure followed by cleanup. There is no warning-only or environment-variable bypass.
On Docker Desktop versions that cannot honor this boundary, local database startup remains unavailable. This is preferable to treating a known local credential and future corpus API as LAN-safe. Linux/CI hosts that honor the binding continue to use the pinned Supabase CLI topology.
Readiness boundary
Bölüm başlığı “Readiness boundary”F1-031 implements the provisioning mechanism but does not activate it. A real
start requires a hash-bound receipt in the existing protected trusted-receipt
store for the committed F1-033 readiness certificate on main. Candidate
worktree content and an ordinary file in Git metadata cannot substitute for
that receipt. F1-033 owns receipt issuance after its independent verification.
The local operating-system account and its filesystem permissions are the
operator trust boundary. MUNDERECAT_ACTOR_ID is an audit/lease identity, not
cryptographic authentication by itself. Credential issuance additionally
requires an operator-owned repository and Git common directory, the protected
F1-033 receipt, and the active registered worktree/lease checks. Multi-user or
remote-agent execution requires a separate authenticated broker and is outside
this local bootstrap contract.
Consequences
Bölüm başlığı “Consequences”Benefits
Bölüm başlığı “Benefits”- Runtime, curation, migration, audit and emergency capabilities are distinct and inspectable.
- New objects do not acquire accidental public write or execute grants.
- Parallel write packets cannot share project, network, ports, login, password or mutable database state.
- Credential material exists only after all authority and exposure gates pass.
- Deterministic tests exercise failure ordering without repeatedly starting Docker; CI performs one real migration replay and live ACL comparison.
- Each active write packet consumes a complete minimal Supabase stack.
- Docker Desktop installations with wildcard-only CLI publication fail closed until their runtime provides a verifiable loopback binding.
- Future schema migrations must explicitly grant each approved runtime read or RPC execute capability.
- A failed cleanup requires visible operator action instead of silently discarding state.
Alternatives Considered
Bölüm başlığı “Alternatives Considered”Shared cluster with one database per agent
Bölüm başlığı “Shared cluster with one database per agent”Global roles, extensions, server settings and resource pressure would remain shared. One privileged or faulty migration could affect every agent, so this does not satisfy the plan’s isolation contract.
Administrator credential for all tools
Bölüm başlığı “Administrator credential for all tools”This is simpler but makes policy names documentary only and lets application or curation paths bypass ownership, RLS and grant boundaries. It was rejected.
Warning on wildcard publication
Bölüm başlığı “Warning on wildcard publication”ADR-015’s initial empty-stack warning was sufficient only before real data and credentials. Continuing after detection would turn a known exposure into an accepted operating mode, so startup now fails closed.
Reviewer replay of deterministic commands
Bölüm başlığı “Reviewer replay of deterministic commands”Repeated test execution by an AI reviewer adds latency without independent judgment. The lead records deterministic evidence once. Reviewers inspect the final PostgreSQL privilege semantics and lifecycle security boundary only.
Revisit Conditions
Bölüm başlığı “Revisit Conditions”- Supabase CLI gains a supported host binding option that is verified on every target runtime.
- F1-033 changes the trusted receipt schema or integration authority.
- Application schema work identifies a smaller runtime or curation capability that should become a separate role.
- Production platform credential issuance or managed Supabase role constraints require a provider-specific adapter.