9.5 KiB
9.5 KiB
Scratchpad — KBN-101 DB runtime/migration role split (#771)
- Branch:
docs/771-kbn101-db-role-split - Base:
maine9c4aa3 - Scope: planning/documentation only; authorized files are PRD, Native Kanban task/shared/index docs, sitemap, this scratchpad, and the new KBN-101 contract.
- Explicit exclusions: source/runtime/config/deployment/secret/migration/compose/CI/lock/package/KBN-100 branch edits; no production mutation.
Objective
Freeze an implementation-ready PostgreSQL role/connection split so the Gateway uses a non-owner runtime identity and only a dedicated migration phase uses an owner/migrator identity. Make real deployed-role certification—not synthetic role tests—a serial prerequisite of KBN-100 and KBN-105.
Intake and current-state evidence
- Mission MVP is active; W3 Native Kanban/SOT is planning-complete. The task state shows KBN-010 as the predecessor and KBN-100 as the current schema slice.
- Current branch started at
e9c4aa3;.mosaic/orchestrator/{mission.json,session.lock}were already runtime-modified and remain untouched. packages/db/src/client.ts,migrate.ts, anddrizzle.config.tsresolve oneDATABASE_URL(with default fallback).packages/storage/src/adapters/postgres.tscallsrunMigrations(this.url).apps/gateway/src/database/database.module.tscallsstorageAdapter.migrate()at startup for PostgreSQL; this is the owner-runtime defect to remove in KBN-101 implementation.packages/config/src/mosaic-config.ts, installer wizard, local/federated compose, Portainer test stack, and.woodpecker/ci.ymlcurrently expose one URL. PGlite has an existing explicit local migration path.- Current KBN contract requires immutable events/checkpoints/artifacts/evidence,
RESTRICT, and KBN-100 generated Drizzle consistency. It did not establish a deployable runtime identity split.
Frozen decisions
DATABASE_URLis the non-owner runtime URL;DATABASE_MIGRATION_URLis migration-only. Both are required in their respective PostgreSQL phases; PGlite is the explicit local exception; migration never falls back to runtime/default/config URL.- PostgreSQL Gateway runtime never auto-runs migration/DDL. Dedicated migrator uses
pg_try_advisory_lock(hashtext('mosaic-schema-migration-v1')); replicas only check exact ordered Drizzle-ledger readiness and fail closed. - Roles are non-login
mosaic_platform_database_owner, non-loginmosaic_schema_owner, login/noinheritmosaic_migrator, non-loginmosaic_runtime_capability, and login/inheritmosaic_runtime. Runtime inherits only its capability role with SET/ADMIN denied, has no owner/migrator membership, no unsafe attributes/ownership/DDL authority, and an explicit trusted search path. - Runtime gets mutable DML only as needed, but INSERT/SELECT only on
task_events,artifacts,task_checkpoints,task_checkpoint_artifacts, andapproval_decision_artifacts. KBN-100 still enforces RESTRICT/no-cascade. - Startup verifies effective role/ownership/attributes/inherited capability/TEMP/function-execute/ledger grants/search path/immutable denials/schema fingerprint without DSN exposure. It also requires authenticated CA/hostname-verified TLS. Stable sanitized errors and redaction rules are required.
- N-1 retains single runtime URL only as a non-certified compatibility release; staged role provisioning/migration/runtime deployment then enforces the split. Rollback never injects migration URL into Gateway.
- Vault target paths, rotation, deployment injection, CI, installer, compose, Portainer, and observability are separate one-card/one-PR handoffs. The migration-only file manifest includes
packages/db/drizzle.config.ts; KBN-101 repairs the known PostgreSQL runner/journal ordering defect and proves a clean database applies every hash once before its foundation certificate. No application migration creates roles/passwords or hardcodes credentials. - KBN-101 foundation merges/certifies first. KBN-100 then rebases, restores Drizzle declaration/snapshot/journal consistency, and bounds procedural immutable-table grant/trigger/backfill work to its own slice. Because those immutable relations do not exist until KBN-100, KBN-101’s real deployed-role immutable-operation certificate follows KBN-100 and is the serial gate before KBN-105.
Assumptions
standaloneandfederatedare all current PostgreSQL production-like modes; a future PostgreSQL tier inherits this contract unless versioned otherwise.- Deployment will support a dedicated migration Job/one-shot command. A target that cannot run it cannot receive production/federated KBN certification.
- Canonical Vault target paths require deployment-owner verification before provisioning; the planning document does not claim they already exist.
Documentation produced
docs/PRD.md: bounded KBN-101 requirements and acceptance criteria.docs/native-kanban-sot/KBN-101-DB-ROLE-SPLIT.md: normative rc.5 implementation, threat, migration/rollback, evidence, and exact file DAG contract.docs/native-kanban-sot/SHARED-CONTRACT.md: rc.5 amendment preserving rc.4.docs/native-kanban-sot/TASKS.md: KBN-101 inserted before and blocks KBN-100; KBN-105 held.- Native Kanban index and root sitemap links.
Validation plan
- Prettier only for changed Markdown.
- Markdown link target/check checks scoped to modified docs.
- Strict contract check with
pnpm exec tsc --noEmit -p docs/native-kanban-sot/tsconfig.json(the frozen TypeScript contracts remain unchanged). - Diff allowlist proves only authorized documentation files changed, apart from pre-existing Mosaic runtime state.
- Independent documentation/security self-review: role escalation, fallback, startup DDL, schema readiness, grants/default privileges, immutable tables, secret leakage, deployment and KBN-100 boundaries.
Review corrections
Independent Codex review found two blockers and security review found two medium defects; all were remediated in the frozen contract:
- Split the KBN-101 certificate into a foundation role/schema-boundary certificate (before KBN-100) and real immutable-operation certificate (after KBN-100, before KBN-105). This preserves the requested KBN-100 block without requiring evidence for tables not yet created.
- Removed the legacy owner-runtime exception. N-1 compatibility preserves variable/config shape only; the KBN-101 runtime refuses owner/migrator identity and current single-URL installs remain on their previous release until role cutover.
- Introduced
mosaic_platform_database_owneras a separate non-login platform role.mosaic_schema_ownerowns application/ledger schemas only, not the database and has no database CREATE/ALTER/extension authority. - Replaced blocking
pg_advisory_lockwithpg_try_advisory_lockand the deterministicDATABASE_MIGRATION_LOCKEDfailure. - Review also flagged active
.mosaic/orchestratorstate. It was pre-existing launcher state and remains unstaged/uncommitted. - Second review added
packages/db/drizzle.config.tsto the migration-only slice, mandatesDATABASE_MIGRATION_URLwith a missing-variable negative, grants runtime onlyUSAGEplusSELECTondrizzle.__drizzle_migrations, and verifies/revokes its ledger writes. - Security review added
DATABASE_TLS_CA_CERT_PATH/DatabaseTlsConfigDtowith authenticated TLS and hostname/CA verification in production-like modes, explicit databaseTEMPORARYrevocation/catalog denial testing, and default-PUBLIC function EXECUTE revocation with SECURITY DEFINER prohibited by default. - Final review corrected the runtime login to inherit only its capability role with SET/ADMIN denied, and moved the known hash-complete migration-runner/journal repair into KBN-101-03 before the foundation certificate.
- Final manifest review added all live runtime DDL paths (
packages/storage/src/tier-detection.ts, Gateway startup, andfleet-backlog) to KBN-101-02, requiring read-only extension probes and no PostgreSQL runtime auto-migration. It also requires KBN-101-04 to stop persisting either DSN into generated.env/mosaic.config.json, using only Vault/deployment references and injected variables. - Provisioning review separated the external privileged platform bootstrap actor from the NOCREATEDB database-owner role and added KBN-101-00. That IaC/bootstrap card owns fresh/existing database role/ownership/grant/Vault transition evidence and is a foundation-certificate dependency.
Results
pnpm exec prettier --checkon every authorized Markdown file: PASS.- Markdown link and whitespace checker on all seven authorized Markdown files: PASS.
pnpm exec tsc --noEmit -p docs/native-kanban-sot/tsconfig.json: PASS (frozen strict contracts unchanged).- Codex code review iterated through role inheritability, hash-complete migration ordering, all reachable runtime DDL entrypoints, installer DSN persistence, and platform-bootstrap ownership; each finding was incorporated into the final frozen contract/DAG. The last security review found no new KBN-101 vulnerability; its sole low finding is the pre-existing unstaged Mosaic session-lock metadata, which is excluded from this commit.
- Commit:
82ce3252df38a687c50485f8d048b53ca8db5989(docs(#771): freeze database runtime role split). - Pre-push queue guard:
ci-queue-wait.sh --purpose push -B mainreturnedstate=unknownwithout failure. The push hook ran repositorypnpm typecheck,pnpm lint, andpnpm format:check: PASS. - Pushed branch
docs/771-kbn101-db-role-splitat the exact commit above; no PR was opened, merged, or closed.web1:mosaic-100received the handoff with head, decisions, DAG, and validation. - Awaiting independent security/Ultron review.