diff --git a/.github/workflows/application-acl-postgres16-proof.yml b/.github/workflows/application-acl-postgres16-proof.yml new file mode 100644 index 0000000000..a925a68566 --- /dev/null +++ b/.github/workflows/application-acl-postgres16-proof.yml @@ -0,0 +1,64 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT + +name: Application ACL PostgreSQL 16 Proof + +on: + pull_request: + branches: [main, dev, develop] + paths: + - ".github/workflows/application-acl-postgres16-proof.yml" + - "docker/application-acl-proof/**" + - "scripts/generate_application_database_acl.py" + - "scripts/ci/prove_application_database_acl.py" + - "src/omnibase_infra/validation/application_database_acl.py" + - "src/omnibase_infra/validation/enums/**" + - "src/omnibase_infra/validation/models/**" + - "src/omnibase_infra/validation/types/**" + - "tests/fixtures/application_database_acl/**" + - "tests/unit/validation/test_application_database_acl.py" + - "tests/ci/test_application_database_acl_contract.py" + - "tests/integration/test_application_acl_postgres16_proof.py" + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + rebuilt-postgres16-proof: + name: Rebuilt PostgreSQL 16 ACL and rollback proof + env: + COMPOSE_PROJECT_NAME: application-acl-proof-${{ github.run_id }}-${{ github.run_attempt }} + permissions: + contents: read + runs-on: >- + ${{ + (github.event_name == 'pull_request' && + github.event.pull_request.head.repo.full_name != github.repository) + && fromJSON(vars.OMNI_PUBLIC_PR_RUNS_ON_JSON || '["ubuntu-latest"]') + || fromJSON(vars.OMNI_DOCKER_CI_RUNS_ON_JSON || vars.OMNI_TRUSTED_CI_RUNS_ON_JSON || '["self-hosted","omnibase-ci"]') + }} + timeout-minutes: 30 + + steps: + - name: Checkout code + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false + + - name: Verify Docker engine + run: docker info + + - name: Rebuild and prove ACL matrix + run: >- + docker compose + -f docker/application-acl-proof/compose.yml + up --build --abort-on-container-exit --exit-code-from proof + + - name: Tear down synthetic proof + if: always() + run: >- + docker compose + -f docker/application-acl-proof/compose.yml + down --volumes --remove-orphans diff --git a/docker/application-acl-proof/Dockerfile b/docker/application-acl-proof/Dockerfile new file mode 100644 index 0000000000..9ea7a23252 --- /dev/null +++ b/docker/application-acl-proof/Dockerfile @@ -0,0 +1,34 @@ +# syntax=docker/dockerfile:1.7 +# SPDX-License-Identifier: MIT + +ARG UV_VERSION=0.11.8 + +FROM postgres:16-alpine AS postgres +COPY docker/application-acl-proof/seed.sql /docker-entrypoint-initdb.d/00-acl-seed.sql + +FROM ghcr.io/astral-sh/uv:${UV_VERSION} AS uv-bin + +FROM python:3.12-slim AS proof + +ENV PYTHONDONTWRITEBYTECODE=1 \ + PYTHONUNBUFFERED=1 \ + PYTHONPATH=/app/src \ + UV_PROJECT_ENVIRONMENT=/app/.venv \ + UV_HTTP_TIMEOUT=600 + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + build-essential git libpq-dev postgresql-client \ + && rm -rf /var/lib/apt/lists/* + +COPY --from=uv-bin /uv /uvx /usr/local/bin/ +WORKDIR /app +COPY pyproject.toml uv.lock README.md LICENSE ./ +RUN uv sync --frozen --no-dev --no-install-project + +COPY src/ ./src/ +COPY tests/fixtures/application_database_acl/ ./proof/fixtures/ +COPY scripts/ci/prove_application_database_acl.py ./proof/prove.py +COPY docker/application-acl-proof/generated/prechange-fixture-acl.json ./proof/prechange-fixture-acl.json + +CMD ["/app/.venv/bin/python", "/app/proof/prove.py"] diff --git a/docker/application-acl-proof/README.md b/docker/application-acl-proof/README.md new file mode 100644 index 0000000000..2855c23e97 --- /dev/null +++ b/docker/application-acl-proof/README.md @@ -0,0 +1,70 @@ +# Generated application ACL proof + +This rebuilt PostgreSQL 16 harness proves the generated one-database ACL and +default-privilege matrix without touching a deployed database. The seed is wholly +synthetic: it contains no dump-derived value, customer identifier, credential, secret, +or live catalog observation. + +Run it with rebuilt images: + +```bash +docker compose -f docker/application-acl-proof/compose.yml \ + up --build --abort-on-container-exit --exit-code-from proof +docker compose -f docker/application-acl-proof/compose.yml \ + down --volumes --remove-orphans +``` + +The same catalog comparator must detect seeded database/schema/object ownership, +`PUBLIC`, broad-object, per-column, grant-option, unsafe-default, PG16 membership, +undeclared-principal, and cross-domain defects before the matrix is +applied. A transient RED control also proves that an undeclared runtime-owned object +cannot hide outside the typed inventory. The harness covers tables, views, +materialized views, sequences, functions, procedures, +enum/domain/composite/range/multirange types, and the `public` schema. It then applies +the generated SQL twice, proves exact catalog +and behavioral access, restores the generated pre-change fixture snapshot including +grantors and membership options, proves a byte-for-byte semantic snapshot match, +reapplies twice, and proves the final state. Routine targets include their PostgreSQL +identity arguments so overloads cannot collapse or receive a name-wide grant. +The generated script has typed `scaffold` and `full` phases. A scaffold can become +`READY` while the full phase remains honestly `BLOCKED` on objects that have not yet +been materialized. Conversely, FULL can be `READY` while SCAFFOLD is `BLOCKED` when +the exact catalog census proves existing roles need attribute hardening; FULL checks +that observed pre-state and repairs it in its transaction, while the additive phase +refuses to conceal it. The scaffold creates absent-but-catalog-proven workload/owner +roles and the three empty target schemas, adds only grants for roles already proven +safe (or newly created safe), and establishes deny-by-default future-object ACLs +only for owner roles it creates. +It preserves existing role attributes, memberships, database ownership, legacy +`CONNECT`, and legacy `public` access; exact revocation and ownership hardening are +FULL-only after the activity/catalog gates pass. A disposable fresh-database lane +proves its wrong-database guard, atomic failure, idempotent apply, legacy +CONNECT/read/write preservation, zero object mutation, hostile collation/type +collision rejection, the later FULL denial, and exact non-cascading removal before +copy. Every script asserts +`current_database()` before its first mutation. + +Both phases run through the real `psql` path inside one explicit transaction; an +injected mid-apply error must leave the entire pre-change snapshot unchanged. The +rollback path is independently failure-injected and transactional. It restores +grantor chains topologically for database/schema/object/column ACLs and PG16 role +memberships, then removes only still-empty schemas and dependency-free roles—never +with `CASCADE`. Raw `pg_default_acl` row presence is part of the snapshot: rollback +normalizes PostgreSQL's implicit function/type `PUBLIC` defaults before replaying +captured deviations, and behavioral checks create future objects to prove those +built-ins return. An unrelated-schema default-ACL sentinel remains byte-for-byte and +behaviorally unchanged through scaffold, FULL, and rollback. The same run revokes +all database privileges before re-granting exact +`CONNECT` access and proves positive/negative connection isolation across the eight +approved non-system databases: `omnidash_analytics`, `omninode_cloud`, `keycloak`, +`omnibase_infra`, `omniintelligence`, `omniclaude`, `omnimemory`, and `umami`. + +`generated/prechange-fixture-acl.json` is explicitly a sanitized fixture rollback +artifact, not a live RDS ACL capture or a full-day `(datname, usename)` sample. The +locked real-source candidate remains `BLOCKED` and emits no production SQL until an +authorized exact principal census (including explicit cluster-global presence and +absence evidence), immutable source-locked catalog/activity query and result blobs, +a complete 24-hour-or-longer activity window, an +independent typed principal/domain policy, exact function signatures and object-kind +counts, materialized target-location evidence (source and target may coexist), and +the named catalog/activity/ownership blockers are resolved. diff --git a/docker/application-acl-proof/compose.yml b/docker/application-acl-proof/compose.yml new file mode 100644 index 0000000000..1eea0868bd --- /dev/null +++ b/docker/application-acl-proof/compose.yml @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: MIT +services: + postgres: + build: + context: ../.. + dockerfile: docker/application-acl-proof/Dockerfile + target: postgres + environment: + POSTGRES_DB: omnidash_analytics + POSTGRES_PASSWORD: acl-proof-admin-only # pragma: allowlist secret + tmpfs: + - /var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres -d omnidash_analytics"] + interval: 1s + timeout: 3s + retries: 30 + proof: + build: + context: ../.. + dockerfile: docker/application-acl-proof/Dockerfile + target: proof + depends_on: + postgres: + condition: service_healthy + environment: + ADMIN_DSN: postgresql://postgres:acl-proof-admin-only@postgres:5432/omnidash_analytics # pragma: allowlist secret + UPDATE_PRECHANGE: ${UPDATE_PRECHANGE:-false} + volumes: + - ./generated:/output diff --git a/docker/application-acl-proof/generated/candidate-matrix.yaml b/docker/application-acl-proof/generated/candidate-matrix.yaml new file mode 100644 index 0000000000..8b2d3bfebe --- /dev/null +++ b/docker/application-acl-proof/generated/candidate-matrix.yaml @@ -0,0 +1,6989 @@ +absent_connect_principals: {} +absent_owner_roles: [] +absent_principals: + application: [] +absent_schemas: + application: [] +allowed_connect_principals: {} +allowed_memberships: [] +authorization_scope: deployment +blockers: + - 'ACL policy violation: principal ''app_dashboard'' has cross-domain privileges on platform_catalog.None (PLATFORM_CATALOG)' + - 'ACL policy violation: principal ''app_dashboard'' has cross-domain privileges on tenant.None (TENANT)' + - 'ACL policy violation: principal ''omninode_runtime'' has cross-domain privileges on omninode_internal.None (OMNINODE_INTERNAL)' + - 'ACL policy violation: principal ''onex_api'' has cross-domain privileges on platform_catalog.None (PLATFORM_CATALOG)' + - 'ACL policy violation: principal ''onex_api'' has cross-domain privileges on tenant.None (TENANT)' + - 'ACL policy violation: principal ''tenant_projection_writer'' has cross-domain privileges on tenant.None (TENANT)' + - 'ACL policy violation: routine omninode_internal.refresh_baselines_quality_snapshots_projected_at lacks an exact signature' + - 'ACL policy violation: routine omninode_internal.refresh_baselines_roi_snapshots_projected_at lacks an exact signature' + - 'ACL policy violation: routine omninode_internal.refresh_capsule_store_updated_at lacks an exact signature' + - 'ACL policy violation: routine omninode_internal.refresh_context_roi_scores_updated_at lacks an exact signature' + - 'ACL policy violation: routine omninode_internal.refresh_intent_classification_events_updated_at lacks an exact signature' + - 'ACL policy violation: routine omninode_internal.refresh_session_outcomes_updated_at lacks an exact signature' + - 'ACL policy violation: routine omninode_internal.refresh_voice_sessions_updated_at lacks an exact signature' + - 'ACL policy violation: routine omninode_internal.update_cost_by_repo_snapshots_updated_at lacks an exact signature' + - 'ACL policy violation: routine omninode_internal.update_instruction_eval_aggregate_snapshots_updated_at lacks an exact signature' + - 'ACL policy violation: routine omninode_internal.update_llm_cost_aggregates_updated_at lacks an exact signature' + - 'ACL policy violation: routine omninode_internal.update_skill_execution_snapshots_updated_at lacks an exact signature' + - 'ACL policy violation: routine omninode_internal.update_traces_updated_at lacks an exact signature' + - 'ACL policy violation: routine tenant.refresh_delegation_budget_state_updated_at lacks an exact signature' + - 'ACL policy violation: routine tenant.refresh_savings_estimates_updated_at lacks an exact signature' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.agent_routing_decisions is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.baselines_breakdown is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.baselines_breakdown_id_seq is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.baselines_comparisons is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.baselines_comparisons_id_seq is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.baselines_quality_snapshots is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.baselines_roi_snapshots is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.baselines_snapshots is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.baselines_trend is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.baselines_trend_id_seq is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.capability_scores is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.capability_scores_id_seq is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.capsule_store is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.context_roi_scores is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.contract_registry is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.contract_registry_id_seq is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.cost_by_repo_snapshots is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.dep_health_findings is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.dep_health_findings_id_seq is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.deployment_evidence_projection is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.deployment_readiness_projection is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.event_chain is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.evidence_correlation_trace_projection is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.evidence_dashboard_projection is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.evidence_readiness_aggregate_projection is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.gate_activity is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.gate_activity_id_seq is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.gate_metrics is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.generation_events is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.instruction_eval_aggregate_snapshots is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.intent_classification_events is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.intent_classification_events_id_seq is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.live_events is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.llm_call_metrics is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.llm_cost_aggregates is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.llm_delegation_daily_projection is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.llm_routing_decisions is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.mcp_tools is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.merge_state_transitions is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.merge_state_transitions_projection_cursor_seq is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.migrations_log is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.migrations_log_id_seq is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.nightly_loop_decisions is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.nightly_loop_iterations is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.node_schema_migrations is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.node_service_registry is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.omnimarket_schema_migrations is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.omnimarket_schema_migrations_id_seq is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.overnight_session_phases is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.overnight_session_phases_id_seq is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.overnight_sessions is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.pattern_learning_artifacts is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.pr_lifecycle_ledger_entries is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.pr_lifecycle_ledger_entries_id_seq is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.pr_merged_events is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.pr_merged_events_projection_cursor_seq is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.projection_capsule_effectiveness is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.projection_overnight_readiness is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.projection_routing_decision is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.receipt_gate_rows is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.receipt_gate_rows_id_seq is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.refresh_baselines_quality_snapshots_projected_at is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.refresh_baselines_roi_snapshots_projected_at is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.refresh_capsule_store_updated_at is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.refresh_context_roi_scores_updated_at is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.refresh_intent_classification_events_updated_at is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.refresh_session_outcomes_updated_at is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.refresh_voice_sessions_updated_at is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.renderer_capability_projection is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.sandbox_decisions is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.schema_migrations is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.session_outcomes is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.session_replay_snapshots is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.skill_execution_snapshots is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.stripe_webhook_events is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.stripe_webhook_events_id_seq is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.swarm_runs is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.traces is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.update_cost_by_repo_snapshots_updated_at is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.update_instruction_eval_aggregate_snapshots_updated_at is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.update_llm_cost_aggregates_updated_at is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.update_skill_execution_snapshots_updated_at is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.update_traces_updated_at is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.omninode_internal.voice_sessions is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.platform_catalog.plan_entitlements is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.platform_catalog.plan_tiers is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.platform_catalog.usage_privileges is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.tenant.bootstrap_tokens is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.tenant.bootstrap_tokens_id_seq is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.tenant.delegation_budget_state is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.tenant.delegation_events is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.tenant.gateway_rate_limit_events is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.tenant.gateway_workflows is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.tenant.projection_cost_savings_overview is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.tenant.projection_delegation_inference_response_text is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.tenant.projection_delegation_model_routing is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.tenant.projection_delegation_quality_gate is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.tenant.projection_delegation_savings is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.tenant.projection_delegation_savings_series is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.tenant.projection_delegation_summary is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.tenant.projection_delegation_token_usage is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.tenant.refresh_delegation_budget_state_updated_at is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.tenant.refresh_savings_estimates_updated_at is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.tenant.savings_estimates is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.tenant.tenant_api_keys is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.tenant.tenant_billing is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.tenant.tenant_credentials is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.tenant.tenant_plans is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.tenant.tenants is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.tenant.usage_events is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.tenant.usage_events_id_seq is not materialized at the rendered location' + - 'ACL policy violation: target object omnidash_analytics.tenant.workflow_results is not materialized at the rendered location' + - 'ACL scaffold policy violation: allowed CONNECT database keys do not cover required CONNECT set' + - 'ACL scaffold policy violation: application: scaffold lacks exact target schema evidence' + - 'ACL scaffold policy violation: application: scaffold lacks presence/absence evidence for declared principals' + - 'ACL scaffold policy violation: keycloak: CONNECT allowlist is empty' + - 'ACL scaffold policy violation: observed CONNECT database keys do not cover required CONNECT set' + - 'ACL scaffold policy violation: observed CONNECT owner database keys do not cover required CONNECT set' + - 'ACL scaffold policy violation: omnibase_infra: CONNECT allowlist is empty' + - 'ACL scaffold policy violation: omniclaude: CONNECT allowlist is empty' + - 'ACL scaffold policy violation: omnidash_analytics: CONNECT allowlist is empty' + - 'ACL scaffold policy violation: omniintelligence: CONNECT allowlist is empty' + - 'ACL scaffold policy violation: omnimemory: CONNECT allowlist is empty' + - 'ACL scaffold policy violation: omninode_cloud: CONNECT allowlist is empty' + - 'ACL scaffold policy violation: principal ''app_dashboard'' has cross-domain scaffold access' + - 'ACL scaffold policy violation: principal ''omninode_runtime'' has cross-domain scaffold access' + - 'ACL scaffold policy violation: principal ''onex_api'' has cross-domain scaffold access' + - 'ACL scaffold policy violation: principal ''tenant_projection_writer'' has cross-domain scaffold access' + - 'ACL scaffold policy violation: scaffold database owner map is incomplete' + - 'ACL scaffold policy violation: scaffold managed owners lack governed owner-role state' + - 'ACL scaffold policy violation: scaffold managed owners lack presence/absence evidence' + - 'ACL scaffold policy violation: scaffold workloads lack governed LOGIN role state' + - 'ACL scaffold policy violation: umami: CONNECT allowlist is empty' + - 'application: requires exactly one independent ACL policy, got []' + - 'application: requires exactly one principal inventory, got []' + - 'keycloak: requires exactly one CONNECT policy, got []' + - 'live catalog object identities differ from the exact typed ownership projection: missing=[(''function'', ''omninode_internal'', ''refresh_baselines_quality_snapshots_projected_at'', ''''), (''function'', ''omninode_internal'', ''refresh_baselines_roi_snapshots_projected_at'', ''''), (''function'', ''omninode_internal'', ''refresh_capsule_store_updated_at'', ''''), (''function'', ''omninode_internal'', ''refresh_context_roi_scores_updated_at'', ''''), (''function'', ''omninode_internal'', ''refresh_intent_classification_events_updated_at'', ''''), (''function'', ''omninode_internal'', ''refresh_session_outcomes_updated_at'', ''''), (''function'', ''omninode_internal'', ''refresh_voice_sessions_updated_at'', ''''), (''function'', ''omninode_internal'', ''update_cost_by_repo_snapshots_updated_at'', ''''), (''function'', ''omninode_internal'', ''update_instruction_eval_aggregate_snapshots_updated_at'', ''''), (''function'', ''omninode_internal'', ''update_llm_cost_aggregates_updated_at'', ''''), (''function'', ''omninode_internal'', ''update_skill_execution_snapshots_updated_at'', ''''), (''function'', ''omninode_internal'', ''update_traces_updated_at'', ''''), (''function'', ''tenant'', ''refresh_delegation_budget_state_updated_at'', ''''), (''function'', ''tenant'', ''refresh_savings_estimates_updated_at'', ''''), (''sequence'', ''omninode_internal'', ''baselines_breakdown_id_seq'', ''''), (''sequence'', ''omninode_internal'', ''baselines_comparisons_id_seq'', ''''), (''sequence'', ''omninode_internal'', ''baselines_trend_id_seq'', ''''), (''sequence'', ''omninode_internal'', ''capability_scores_id_seq'', ''''), (''sequence'', ''omninode_internal'', ''contract_registry_id_seq'', ''''), (''sequence'', ''omninode_internal'', ''dep_health_findings_id_seq'', ''''), (''sequence'', ''omninode_internal'', ''gate_activity_id_seq'', ''''), (''sequence'', ''omninode_internal'', ''intent_classification_events_id_seq'', ''''), (''sequence'', ''omninode_internal'', ''merge_state_transitions_projection_cursor_seq'', ''''), (''sequence'', ''omninode_internal'', ''migrations_log_id_seq'', ''''), (''sequence'', ''omninode_internal'', ''omnimarket_schema_migrations_id_seq'', ''''), (''sequence'', ''omninode_internal'', ''overnight_session_phases_id_seq'', ''''), (''sequence'', ''omninode_internal'', ''pr_lifecycle_ledger_entries_id_seq'', ''''), (''sequence'', ''omninode_internal'', ''pr_merged_events_projection_cursor_seq'', ''''), (''sequence'', ''omninode_internal'', ''receipt_gate_rows_id_seq'', ''''), (''sequence'', ''omninode_internal'', ''stripe_webhook_events_id_seq'', ''''), (''sequence'', ''tenant'', ''bootstrap_tokens_id_seq'', ''''), (''sequence'', ''tenant'', ''usage_events_id_seq'', ''''), (''table'', ''omninode_internal'', ''agent_routing_decisions'', ''''), (''table'', ''omninode_internal'', ''baselines_breakdown'', ''''), (''table'', ''omninode_internal'', ''baselines_comparisons'', ''''), (''table'', ''omninode_internal'', ''baselines_quality_snapshots'', ''''), (''table'', ''omninode_internal'', ''baselines_roi_snapshots'', ''''), (''table'', ''omninode_internal'', ''baselines_snapshots'', ''''), (''table'', ''omninode_internal'', ''baselines_trend'', ''''), (''table'', ''omninode_internal'', ''capability_scores'', ''''), (''table'', ''omninode_internal'', ''capsule_store'', ''''), (''table'', ''omninode_internal'', ''context_roi_scores'', ''''), (''table'', ''omninode_internal'', ''contract_registry'', ''''), (''table'', ''omninode_internal'', ''cost_by_repo_snapshots'', ''''), (''table'', ''omninode_internal'', ''dep_health_findings'', ''''), (''table'', ''omninode_internal'', ''deployment_evidence_projection'', ''''), (''table'', ''omninode_internal'', ''deployment_readiness_projection'', ''''), (''table'', ''omninode_internal'', ''event_chain'', ''''), (''table'', ''omninode_internal'', ''evidence_correlation_trace_projection'', ''''), (''table'', ''omninode_internal'', ''evidence_dashboard_projection'', ''''), (''table'', ''omninode_internal'', ''evidence_readiness_aggregate_projection'', ''''), (''table'', ''omninode_internal'', ''gate_activity'', ''''), (''table'', ''omninode_internal'', ''gate_metrics'', ''''), (''table'', ''omninode_internal'', ''generation_events'', ''''), (''table'', ''omninode_internal'', ''instruction_eval_aggregate_snapshots'', ''''), (''table'', ''omninode_internal'', ''intent_classification_events'', ''''), (''table'', ''omninode_internal'', ''live_events'', ''''), (''table'', ''omninode_internal'', ''llm_call_metrics'', ''''), (''table'', ''omninode_internal'', ''llm_cost_aggregates'', ''''), (''table'', ''omninode_internal'', ''llm_delegation_daily_projection'', ''''), (''table'', ''omninode_internal'', ''llm_routing_decisions'', ''''), (''table'', ''omninode_internal'', ''mcp_tools'', ''''), (''table'', ''omninode_internal'', ''merge_state_transitions'', ''''), (''table'', ''omninode_internal'', ''migrations_log'', ''''), (''table'', ''omninode_internal'', ''nightly_loop_decisions'', ''''), (''table'', ''omninode_internal'', ''nightly_loop_iterations'', ''''), (''table'', ''omninode_internal'', ''node_schema_migrations'', ''''), (''table'', ''omninode_internal'', ''node_service_registry'', ''''), (''table'', ''omninode_internal'', ''omnimarket_schema_migrations'', ''''), (''table'', ''omninode_internal'', ''overnight_session_phases'', ''''), (''table'', ''omninode_internal'', ''overnight_sessions'', ''''), (''table'', ''omninode_internal'', ''pattern_learning_artifacts'', ''''), (''table'', ''omninode_internal'', ''pr_lifecycle_ledger_entries'', ''''), (''table'', ''omninode_internal'', ''pr_merged_events'', ''''), (''table'', ''omninode_internal'', ''receipt_gate_rows'', ''''), (''table'', ''omninode_internal'', ''renderer_capability_projection'', ''''), (''table'', ''omninode_internal'', ''sandbox_decisions'', ''''), (''table'', ''omninode_internal'', ''schema_migrations'', ''''), (''table'', ''omninode_internal'', ''session_outcomes'', ''''), (''table'', ''omninode_internal'', ''session_replay_snapshots'', ''''), (''table'', ''omninode_internal'', ''skill_execution_snapshots'', ''''), (''table'', ''omninode_internal'', ''stripe_webhook_events'', ''''), (''table'', ''omninode_internal'', ''swarm_runs'', ''''), (''table'', ''omninode_internal'', ''traces'', ''''), (''table'', ''omninode_internal'', ''voice_sessions'', ''''), (''table'', ''platform_catalog'', ''plan_entitlements'', ''''), (''table'', ''platform_catalog'', ''plan_tiers'', ''''), (''table'', ''platform_catalog'', ''usage_privileges'', ''''), (''table'', ''tenant'', ''bootstrap_tokens'', ''''), (''table'', ''tenant'', ''delegation_budget_state'', ''''), (''table'', ''tenant'', ''delegation_events'', ''''), (''table'', ''tenant'', ''gateway_rate_limit_events'', ''''), (''table'', ''tenant'', ''gateway_workflows'', ''''), (''table'', ''tenant'', ''projection_delegation_inference_response_text'', ''''), (''table'', ''tenant'', ''savings_estimates'', ''''), (''table'', ''tenant'', ''tenant_api_keys'', ''''), (''table'', ''tenant'', ''tenant_billing'', ''''), (''table'', ''tenant'', ''tenant_credentials'', ''''), (''table'', ''tenant'', ''tenant_plans'', ''''), (''table'', ''tenant'', ''tenants'', ''''), (''table'', ''tenant'', ''usage_events'', ''''), (''table'', ''tenant'', ''workflow_results'', ''''), (''view'', ''omninode_internal'', ''projection_capsule_effectiveness'', ''''), (''view'', ''omninode_internal'', ''projection_overnight_readiness'', ''''), (''view'', ''omninode_internal'', ''projection_routing_decision'', ''''), (''view'', ''tenant'', ''projection_cost_savings_overview'', ''''), (''view'', ''tenant'', ''projection_delegation_model_routing'', ''''), (''view'', ''tenant'', ''projection_delegation_quality_gate'', ''''), (''view'', ''tenant'', ''projection_delegation_savings'', ''''), (''view'', ''tenant'', ''projection_delegation_savings_series'', ''''), (''view'', ''tenant'', ''projection_delegation_summary'', ''''), (''view'', ''tenant'', ''projection_delegation_token_usage'', '''')] extra=[]' + - matrix requires a typed principal_inventory source for every database + - matrix requires an independent typed acl_policy source for every database + - 'node_migration_service_ownership: blocked table ''schema_migrations'': Retained live evidence identifies an omnidash-owned ledger shaped (filename TEXT PRIMARY KEY, applied_at TIMESTAMPTZ), but no authoritative repository DDL or current owner declaration was found. It must not be conflated with node_schema_migrations or another service''s incompatible schema_migrations shape.' + - 'node_migration_service_ownership: completion_status is missing' + - 'node_migration_service_ownership: object ''node_schema_migrations'' current_schemas=() do not prove target schema ''omninode_internal''; full object ACL rendering is gated' + - 'node_migration_service_ownership: retained_live_census is missing' + - 'node_migration_service_ownership: runtime_evidence.full_day_datname_usename_activity=''blocked'': live database access was outside this build lane''s authorization' + - 'node_migration_service_ownership: runtime_evidence.live_catalog_parity=''blocked'': a fresh authorized catalog read is required for current parity' + - 'node_migration_service_ownership: target physical database ''omnidash_analytics'' is absent from materialized_physical_databases; full object ACL rendering is gated until the additive target is inventoried' + - 'omnibase_infra: requires exactly one CONNECT policy, got []' + - 'omniclaude: requires exactly one CONNECT policy, got []' + - 'omnidash_analytics: requires exactly one CONNECT policy, got []' + - 'omniintelligence: requires exactly one CONNECT policy, got []' + - 'omnimarket_relation_inventory: blocked table ''delegation_judge_verdict_events'': schema ''unresolved'' does not resolve through deployment topology' + - 'omnimarket_relation_inventory: blocked table ''delegation_shadow_comparisons'': no authoritative CREATE TABLE migration found' + - 'omnimarket_relation_inventory: blocked table ''delegation_workflow_state'': producer, consumers, and customer-ownership semantics are unresolved' + - 'omnimarket_relation_inventory: blocked table ''event_bus_events'': observed in the retained live census but no authoritative repository DDL was found' + - 'omnimarket_relation_inventory: blocked table ''schema_migrations'': retained live evidence identifies the omnidash filename ledger, but no authoritative repository DDL or owner declaration was found' + - 'omnimarket_relation_inventory: completion_status=''blocked_pending_live_catalog_and_activity_evidence''' + - 'omnimarket_relation_inventory: object ''agent_routing_decisions'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''baselines_breakdown'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''baselines_breakdown_id_seq'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''baselines_comparisons'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''baselines_comparisons_id_seq'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''baselines_quality_snapshots'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''baselines_roi_snapshots'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''baselines_snapshots'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''baselines_trend'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''baselines_trend_id_seq'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''capability_scores'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''capability_scores_id_seq'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''capsule_store'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''context_roi_scores'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''contract_registry'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''contract_registry_id_seq'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''cost_by_repo_snapshots'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''delegation_budget_state'' is currently in schemas [''public''], not the target schema ''tenant''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''delegation_events'' is currently in schemas [''public''], not the target schema ''tenant''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''delegation_judge_verdict_events'' uses unknown schema ''unresolved''' + - 'omnimarket_relation_inventory: object ''delegation_shadow_comparisons'' blocked: no authoritative CREATE TABLE migration found' + - 'omnimarket_relation_inventory: object ''delegation_shadow_comparisons'' classification_status=''blocked''' + - 'omnimarket_relation_inventory: object ''delegation_shadow_comparisons'' is currently in schemas [''public''], not the target schema ''tenant''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''delegation_shadow_comparisons'' lacks an exact owner_declaration' + - 'omnimarket_relation_inventory: object ''dep_health_findings'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''dep_health_findings_id_seq'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''deployment_evidence_projection'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''deployment_readiness_projection'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''event_chain'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''evidence_correlation_trace_projection'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''evidence_dashboard_projection'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''evidence_readiness_aggregate_projection'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''gate_activity'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''gate_activity_id_seq'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''gate_metrics'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''generation_events'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''instruction_eval_aggregate_snapshots'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''intent_classification_events'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''intent_classification_events_id_seq'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''live_events'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''llm_call_metrics'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''llm_cost_aggregates'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''llm_delegation_daily_projection'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''llm_routing_decisions'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''mcp_tools'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''merge_state_transitions'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''merge_state_transitions_projection_cursor_seq'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''nightly_loop_decisions'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''nightly_loop_iterations'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''node_service_registry'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''omnimarket_schema_migrations'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''omnimarket_schema_migrations_id_seq'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''overnight_session_phases'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''overnight_session_phases_id_seq'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''overnight_sessions'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''pattern_learning_artifacts'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''pr_lifecycle_ledger_entries'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''pr_lifecycle_ledger_entries_id_seq'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''pr_merged_events'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''pr_merged_events_projection_cursor_seq'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''projection_capsule_effectiveness'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''projection_cost_savings_overview'' is currently in schemas [''public''], not the target schema ''tenant''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''projection_delegation_inference_response_text'' is currently in schemas [''public''], not the target schema ''tenant''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''projection_delegation_model_routing'' is currently in schemas [''public''], not the target schema ''tenant''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''projection_delegation_quality_gate'' is currently in schemas [''public''], not the target schema ''tenant''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''projection_delegation_savings'' is currently in schemas [''public''], not the target schema ''tenant''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''projection_delegation_savings_series'' is currently in schemas [''public''], not the target schema ''tenant''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''projection_delegation_summary'' is currently in schemas [''public''], not the target schema ''tenant''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''projection_delegation_token_usage'' is currently in schemas [''public''], not the target schema ''tenant''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''projection_overnight_readiness'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''projection_routing_decision'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''receipt_gate_rows'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''receipt_gate_rows_id_seq'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''refresh_baselines_quality_snapshots_projected_at'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''refresh_baselines_roi_snapshots_projected_at'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''refresh_capsule_store_updated_at'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''refresh_context_roi_scores_updated_at'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''refresh_delegation_budget_state_updated_at'' is currently in schemas [''public''], not the target schema ''tenant''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''refresh_intent_classification_events_updated_at'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''refresh_savings_estimates_updated_at'' is currently in schemas [''public''], not the target schema ''tenant''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''refresh_session_outcomes_updated_at'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''refresh_voice_sessions_updated_at'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''renderer_capability_projection'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''sandbox_decisions'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''savings_estimates'' is currently in schemas [''public''], not the target schema ''tenant''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''session_outcomes'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''session_replay_snapshots'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''skill_execution_snapshots'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''swarm_runs'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''traces'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''update_cost_by_repo_snapshots_updated_at'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''update_instruction_eval_aggregate_snapshots_updated_at'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''update_llm_cost_aggregates_updated_at'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''update_skill_execution_snapshots_updated_at'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''update_traces_updated_at'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: object ''voice_sessions'' is currently in schemas [''public''], not the target schema ''omninode_internal''; full object ACL rendering is gated until the additive target object is materialized and inventoried' + - 'omnimarket_relation_inventory: relation_counts.procedure is not inventoried; zero procedures cannot be inferred' + - 'omnimarket_relation_inventory: relation_counts.type is not inventoried; zero user-defined types cannot be inferred' + - 'omnimarket_relation_inventory: retained_live_census.observed_base_tables=86 does not match exact typed rows=55' + - 'omnimarket_relation_inventory: retained_live_census.observed_extensions is not inventoried' + - 'omnimarket_relation_inventory: retained_live_census.observed_functions is not inventoried' + - 'omnimarket_relation_inventory: retained_live_census.observed_procedures is not inventoried' + - 'omnimarket_relation_inventory: retained_live_census.observed_sequences is not inventoried' + - 'omnimarket_relation_inventory: retained_live_census.observed_types is not inventoried' + - 'omnimarket_relation_inventory: retained_live_census.observed_views_and_materialized_views=9 does not match exact typed rows=10' + - 'omnimarket_relation_inventory: retained_live_census=''blocked'': the retained census contains counts but not a complete object-name export; repository migrations therefore cannot prove name-for-name live parity without a fresh authorized catalog read' + - 'omnimarket_relation_inventory: runtime_evidence.full_day_datname_usename_activity=''blocked'': live database access was outside this build lane''s authorization' + - 'omnimarket_relation_inventory: runtime_evidence.live_catalog_parity=''blocked'': repository sources contain 54 CREATE TABLE objects while the retained live census reports 86 base tables; exact overlap and the at-least-32-table gap require an authorized catalog read' + - 'omnimemory: requires exactly one CONNECT policy, got []' + - 'omninode_cloud: requires exactly one CONNECT policy, got []' + - 'omninode_internal.refresh_baselines_quality_snapshots_projected_at: ownership and ACL rendering require an explicit function_signature to avoid overload widening' + - 'omninode_internal.refresh_baselines_roi_snapshots_projected_at: ownership and ACL rendering require an explicit function_signature to avoid overload widening' + - 'omninode_internal.refresh_capsule_store_updated_at: ownership and ACL rendering require an explicit function_signature to avoid overload widening' + - 'omninode_internal.refresh_context_roi_scores_updated_at: ownership and ACL rendering require an explicit function_signature to avoid overload widening' + - 'omninode_internal.refresh_intent_classification_events_updated_at: ownership and ACL rendering require an explicit function_signature to avoid overload widening' + - 'omninode_internal.refresh_session_outcomes_updated_at: ownership and ACL rendering require an explicit function_signature to avoid overload widening' + - 'omninode_internal.refresh_voice_sessions_updated_at: ownership and ACL rendering require an explicit function_signature to avoid overload widening' + - 'omninode_internal.update_cost_by_repo_snapshots_updated_at: ownership and ACL rendering require an explicit function_signature to avoid overload widening' + - 'omninode_internal.update_instruction_eval_aggregate_snapshots_updated_at: ownership and ACL rendering require an explicit function_signature to avoid overload widening' + - 'omninode_internal.update_llm_cost_aggregates_updated_at: ownership and ACL rendering require an explicit function_signature to avoid overload widening' + - 'omninode_internal.update_skill_execution_snapshots_updated_at: ownership and ACL rendering require an explicit function_signature to avoid overload widening' + - 'omninode_internal.update_traces_updated_at: ownership and ACL rendering require an explicit function_signature to avoid overload widening' + - 'onex_api_service_ownership: completion_status=''blocked_pending_live_catalog_and_activity_evidence''' + - 'onex_api_service_ownership: object ''bootstrap_tokens'' current_schemas=() do not prove target schema ''tenant''; full object ACL rendering is gated' + - 'onex_api_service_ownership: object ''bootstrap_tokens_id_seq'' current_schemas=() do not prove target schema ''tenant''; full object ACL rendering is gated' + - 'onex_api_service_ownership: object ''gateway_rate_limit_events'' current_schemas=() do not prove target schema ''tenant''; full object ACL rendering is gated' + - 'onex_api_service_ownership: object ''gateway_workflows'' current_schemas=() do not prove target schema ''tenant''; full object ACL rendering is gated' + - 'onex_api_service_ownership: object ''migrations_log'' current_schemas=() do not prove target schema ''omninode_internal''; full object ACL rendering is gated' + - 'onex_api_service_ownership: object ''migrations_log_id_seq'' current_schemas=() do not prove target schema ''omninode_internal''; full object ACL rendering is gated' + - 'onex_api_service_ownership: object ''plan_entitlements'' current_schemas=() do not prove target schema ''platform_catalog''; full object ACL rendering is gated' + - 'onex_api_service_ownership: object ''plan_tiers'' current_schemas=() do not prove target schema ''platform_catalog''; full object ACL rendering is gated' + - 'onex_api_service_ownership: object ''schema_migrations'' current_schemas=() do not prove target schema ''omninode_internal''; full object ACL rendering is gated' + - 'onex_api_service_ownership: object ''stripe_webhook_events'' current_schemas=() do not prove target schema ''omninode_internal''; full object ACL rendering is gated' + - 'onex_api_service_ownership: object ''stripe_webhook_events_id_seq'' current_schemas=() do not prove target schema ''omninode_internal''; full object ACL rendering is gated' + - 'onex_api_service_ownership: object ''tenant_api_keys'' current_schemas=() do not prove target schema ''tenant''; full object ACL rendering is gated' + - 'onex_api_service_ownership: object ''tenant_billing'' current_schemas=() do not prove target schema ''tenant''; full object ACL rendering is gated' + - 'onex_api_service_ownership: object ''tenant_credentials'' current_schemas=() do not prove target schema ''tenant''; full object ACL rendering is gated' + - 'onex_api_service_ownership: object ''tenant_plans'' current_schemas=() do not prove target schema ''tenant''; full object ACL rendering is gated' + - 'onex_api_service_ownership: object ''tenants'' current_schemas=() do not prove target schema ''tenant''; full object ACL rendering is gated' + - 'onex_api_service_ownership: object ''usage_events'' current_schemas=() do not prove target schema ''tenant''; full object ACL rendering is gated' + - 'onex_api_service_ownership: object ''usage_events_id_seq'' current_schemas=() do not prove target schema ''tenant''; full object ACL rendering is gated' + - 'onex_api_service_ownership: object ''usage_privileges'' current_schemas=() do not prove target schema ''platform_catalog''; full object ACL rendering is gated' + - 'onex_api_service_ownership: object ''workflow_results'' current_schemas=() do not prove target schema ''tenant''; full object ACL rendering is gated' + - 'onex_api_service_ownership: retained_live_census.observed_extensions is missing' + - 'onex_api_service_ownership: retained_live_census.observed_functions is missing' + - 'onex_api_service_ownership: retained_live_census.observed_procedures is missing' + - 'onex_api_service_ownership: retained_live_census.observed_sequences is missing' + - 'onex_api_service_ownership: retained_live_census.observed_types is missing' + - 'onex_api_service_ownership: retained_live_census=''blocked'': Source names match the retained 16-table list, but a fresh authorized catalog read is required to prove that the retained census is still current.' + - 'onex_api_service_ownership: runtime_evidence.full_day_datname_usename_activity=''blocked'': live database access was outside this build lane''s authorization' + - 'onex_api_service_ownership: runtime_evidence.live_catalog_parity=''blocked'': source inventory cannot prove the retained live 16-table census is current' + - 'onex_api_service_ownership: target physical database ''omnidash_analytics'' is absent from materialized_physical_databases; full object ACL rendering is gated until the additive target is inventoried' + - 'tenant.refresh_delegation_budget_state_updated_at: ownership and ACL rendering require an explicit function_signature to avoid overload widening' + - 'tenant.refresh_savings_estimates_updated_at: ownership and ACL rendering require an explicit function_signature to avoid overload widening' + - topology declares zero explicit object grants for 112 typed ownership objects + - 'umami: requires exactly one CONNECT policy, got []' +database_owners: {} +declared_principals: + application: + - app_dashboard + - omninode_runtime + - onex_api + - tenant_projection_writer +default_privileges: + - database_ref: application + grantee: PUBLIC + object_type: FUNCTION + owner: owner_omninode_internal + physical_database: omnidash_analytics + privileges: [] + schema_ref: omninode_internal + - database_ref: application + grantee: app_dashboard + object_type: FUNCTION + owner: owner_omninode_internal + physical_database: omnidash_analytics + privileges: [] + schema_ref: omninode_internal + - database_ref: application + grantee: omninode_runtime + object_type: FUNCTION + owner: owner_omninode_internal + physical_database: omnidash_analytics + privileges: [] + schema_ref: omninode_internal + - database_ref: application + grantee: onex_api + object_type: FUNCTION + owner: owner_omninode_internal + physical_database: omnidash_analytics + privileges: [] + schema_ref: omninode_internal + - database_ref: application + grantee: tenant_projection_writer + object_type: FUNCTION + owner: owner_omninode_internal + physical_database: omnidash_analytics + privileges: [] + schema_ref: omninode_internal + - database_ref: application + grantee: PUBLIC + object_type: SEQUENCE + owner: owner_omninode_internal + physical_database: omnidash_analytics + privileges: [] + schema_ref: omninode_internal + - database_ref: application + grantee: app_dashboard + object_type: SEQUENCE + owner: owner_omninode_internal + physical_database: omnidash_analytics + privileges: [] + schema_ref: omninode_internal + - database_ref: application + grantee: omninode_runtime + object_type: SEQUENCE + owner: owner_omninode_internal + physical_database: omnidash_analytics + privileges: [] + schema_ref: omninode_internal + - database_ref: application + grantee: onex_api + object_type: SEQUENCE + owner: owner_omninode_internal + physical_database: omnidash_analytics + privileges: [] + schema_ref: omninode_internal + - database_ref: application + grantee: tenant_projection_writer + object_type: SEQUENCE + owner: owner_omninode_internal + physical_database: omnidash_analytics + privileges: [] + schema_ref: omninode_internal + - database_ref: application + grantee: PUBLIC + object_type: TABLE + owner: owner_omninode_internal + physical_database: omnidash_analytics + privileges: [] + schema_ref: omninode_internal + - database_ref: application + grantee: app_dashboard + object_type: TABLE + owner: owner_omninode_internal + physical_database: omnidash_analytics + privileges: [] + schema_ref: omninode_internal + - database_ref: application + grantee: omninode_runtime + object_type: TABLE + owner: owner_omninode_internal + physical_database: omnidash_analytics + privileges: [] + schema_ref: omninode_internal + - database_ref: application + grantee: onex_api + object_type: TABLE + owner: owner_omninode_internal + physical_database: omnidash_analytics + privileges: [] + schema_ref: omninode_internal + - database_ref: application + grantee: tenant_projection_writer + object_type: TABLE + owner: owner_omninode_internal + physical_database: omnidash_analytics + privileges: [] + schema_ref: omninode_internal + - database_ref: application + grantee: PUBLIC + object_type: TYPE + owner: owner_omninode_internal + physical_database: omnidash_analytics + privileges: [] + schema_ref: omninode_internal + - database_ref: application + grantee: app_dashboard + object_type: TYPE + owner: owner_omninode_internal + physical_database: omnidash_analytics + privileges: [] + schema_ref: omninode_internal + - database_ref: application + grantee: omninode_runtime + object_type: TYPE + owner: owner_omninode_internal + physical_database: omnidash_analytics + privileges: [] + schema_ref: omninode_internal + - database_ref: application + grantee: onex_api + object_type: TYPE + owner: owner_omninode_internal + physical_database: omnidash_analytics + privileges: [] + schema_ref: omninode_internal + - database_ref: application + grantee: tenant_projection_writer + object_type: TYPE + owner: owner_omninode_internal + physical_database: omnidash_analytics + privileges: [] + schema_ref: omninode_internal + - database_ref: application + grantee: PUBLIC + object_type: FUNCTION + owner: owner_platform_catalog + physical_database: omnidash_analytics + privileges: [] + schema_ref: platform_catalog + - database_ref: application + grantee: app_dashboard + object_type: FUNCTION + owner: owner_platform_catalog + physical_database: omnidash_analytics + privileges: [] + schema_ref: platform_catalog + - database_ref: application + grantee: omninode_runtime + object_type: FUNCTION + owner: owner_platform_catalog + physical_database: omnidash_analytics + privileges: [] + schema_ref: platform_catalog + - database_ref: application + grantee: onex_api + object_type: FUNCTION + owner: owner_platform_catalog + physical_database: omnidash_analytics + privileges: [] + schema_ref: platform_catalog + - database_ref: application + grantee: tenant_projection_writer + object_type: FUNCTION + owner: owner_platform_catalog + physical_database: omnidash_analytics + privileges: [] + schema_ref: platform_catalog + - database_ref: application + grantee: PUBLIC + object_type: SEQUENCE + owner: owner_platform_catalog + physical_database: omnidash_analytics + privileges: [] + schema_ref: platform_catalog + - database_ref: application + grantee: app_dashboard + object_type: SEQUENCE + owner: owner_platform_catalog + physical_database: omnidash_analytics + privileges: [] + schema_ref: platform_catalog + - database_ref: application + grantee: omninode_runtime + object_type: SEQUENCE + owner: owner_platform_catalog + physical_database: omnidash_analytics + privileges: [] + schema_ref: platform_catalog + - database_ref: application + grantee: onex_api + object_type: SEQUENCE + owner: owner_platform_catalog + physical_database: omnidash_analytics + privileges: [] + schema_ref: platform_catalog + - database_ref: application + grantee: tenant_projection_writer + object_type: SEQUENCE + owner: owner_platform_catalog + physical_database: omnidash_analytics + privileges: [] + schema_ref: platform_catalog + - database_ref: application + grantee: PUBLIC + object_type: TABLE + owner: owner_platform_catalog + physical_database: omnidash_analytics + privileges: [] + schema_ref: platform_catalog + - database_ref: application + grantee: app_dashboard + object_type: TABLE + owner: owner_platform_catalog + physical_database: omnidash_analytics + privileges: [] + schema_ref: platform_catalog + - database_ref: application + grantee: omninode_runtime + object_type: TABLE + owner: owner_platform_catalog + physical_database: omnidash_analytics + privileges: [] + schema_ref: platform_catalog + - database_ref: application + grantee: onex_api + object_type: TABLE + owner: owner_platform_catalog + physical_database: omnidash_analytics + privileges: [] + schema_ref: platform_catalog + - database_ref: application + grantee: tenant_projection_writer + object_type: TABLE + owner: owner_platform_catalog + physical_database: omnidash_analytics + privileges: [] + schema_ref: platform_catalog + - database_ref: application + grantee: PUBLIC + object_type: TYPE + owner: owner_platform_catalog + physical_database: omnidash_analytics + privileges: [] + schema_ref: platform_catalog + - database_ref: application + grantee: app_dashboard + object_type: TYPE + owner: owner_platform_catalog + physical_database: omnidash_analytics + privileges: [] + schema_ref: platform_catalog + - database_ref: application + grantee: omninode_runtime + object_type: TYPE + owner: owner_platform_catalog + physical_database: omnidash_analytics + privileges: [] + schema_ref: platform_catalog + - database_ref: application + grantee: onex_api + object_type: TYPE + owner: owner_platform_catalog + physical_database: omnidash_analytics + privileges: [] + schema_ref: platform_catalog + - database_ref: application + grantee: tenant_projection_writer + object_type: TYPE + owner: owner_platform_catalog + physical_database: omnidash_analytics + privileges: [] + schema_ref: platform_catalog + - database_ref: application + grantee: PUBLIC + object_type: FUNCTION + owner: owner_onex_tenant + physical_database: omnidash_analytics + privileges: [] + schema_ref: tenant + - database_ref: application + grantee: app_dashboard + object_type: FUNCTION + owner: owner_onex_tenant + physical_database: omnidash_analytics + privileges: [] + schema_ref: tenant + - database_ref: application + grantee: omninode_runtime + object_type: FUNCTION + owner: owner_onex_tenant + physical_database: omnidash_analytics + privileges: [] + schema_ref: tenant + - database_ref: application + grantee: onex_api + object_type: FUNCTION + owner: owner_onex_tenant + physical_database: omnidash_analytics + privileges: [] + schema_ref: tenant + - database_ref: application + grantee: tenant_projection_writer + object_type: FUNCTION + owner: owner_onex_tenant + physical_database: omnidash_analytics + privileges: [] + schema_ref: tenant + - database_ref: application + grantee: PUBLIC + object_type: SEQUENCE + owner: owner_onex_tenant + physical_database: omnidash_analytics + privileges: [] + schema_ref: tenant + - database_ref: application + grantee: app_dashboard + object_type: SEQUENCE + owner: owner_onex_tenant + physical_database: omnidash_analytics + privileges: [] + schema_ref: tenant + - database_ref: application + grantee: omninode_runtime + object_type: SEQUENCE + owner: owner_onex_tenant + physical_database: omnidash_analytics + privileges: [] + schema_ref: tenant + - database_ref: application + grantee: onex_api + object_type: SEQUENCE + owner: owner_onex_tenant + physical_database: omnidash_analytics + privileges: [] + schema_ref: tenant + - database_ref: application + grantee: tenant_projection_writer + object_type: SEQUENCE + owner: owner_onex_tenant + physical_database: omnidash_analytics + privileges: [] + schema_ref: tenant + - database_ref: application + grantee: PUBLIC + object_type: TABLE + owner: owner_onex_tenant + physical_database: omnidash_analytics + privileges: [] + schema_ref: tenant + - database_ref: application + grantee: app_dashboard + object_type: TABLE + owner: owner_onex_tenant + physical_database: omnidash_analytics + privileges: [] + schema_ref: tenant + - database_ref: application + grantee: omninode_runtime + object_type: TABLE + owner: owner_onex_tenant + physical_database: omnidash_analytics + privileges: [] + schema_ref: tenant + - database_ref: application + grantee: onex_api + object_type: TABLE + owner: owner_onex_tenant + physical_database: omnidash_analytics + privileges: [] + schema_ref: tenant + - database_ref: application + grantee: tenant_projection_writer + object_type: TABLE + owner: owner_onex_tenant + physical_database: omnidash_analytics + privileges: [] + schema_ref: tenant + - database_ref: application + grantee: PUBLIC + object_type: TYPE + owner: owner_onex_tenant + physical_database: omnidash_analytics + privileges: [] + schema_ref: tenant + - database_ref: application + grantee: app_dashboard + object_type: TYPE + owner: owner_onex_tenant + physical_database: omnidash_analytics + privileges: [] + schema_ref: tenant + - database_ref: application + grantee: omninode_runtime + object_type: TYPE + owner: owner_onex_tenant + physical_database: omnidash_analytics + privileges: [] + schema_ref: tenant + - database_ref: application + grantee: onex_api + object_type: TYPE + owner: owner_onex_tenant + physical_database: omnidash_analytics + privileges: [] + schema_ref: tenant + - database_ref: application + grantee: tenant_projection_writer + object_type: TYPE + owner: owner_onex_tenant + physical_database: omnidash_analytics + privileges: [] + schema_ref: tenant +excluded_objects: + - omnimarket_relation_inventory:platform_catalog.pgcrypto:extension + - onex_api_service_ownership:pgcrypto:extension +governed_role_states: [] +objects: + - catalog_kind: function + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: refresh_baselines_quality_snapshots_projected_at + object_type: FUNCTION + owner: owner_omninode_internal + owner_declaration: node_projection_baselines_quality + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: function + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: refresh_baselines_roi_snapshots_projected_at + object_type: FUNCTION + owner: owner_omninode_internal + owner_declaration: node_projection_baselines_roi + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: function + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: refresh_capsule_store_updated_at + object_type: FUNCTION + owner: owner_omninode_internal + owner_declaration: node_projection_capsule_store + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: function + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: refresh_context_roi_scores_updated_at + object_type: FUNCTION + owner: owner_omninode_internal + owner_declaration: node_projection_context_roi + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: function + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: refresh_intent_classification_events_updated_at + object_type: FUNCTION + owner: owner_omninode_internal + owner_declaration: node_projection_intent_classification + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: function + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: refresh_session_outcomes_updated_at + object_type: FUNCTION + owner: owner_omninode_internal + owner_declaration: node_projection_session_outcome + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: function + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: refresh_voice_sessions_updated_at + object_type: FUNCTION + owner: owner_omninode_internal + owner_declaration: node_projection_voice_sessions + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: function + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: update_cost_by_repo_snapshots_updated_at + object_type: FUNCTION + owner: owner_omninode_internal + owner_declaration: node_projection_cost_by_repo + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: function + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: update_instruction_eval_aggregate_snapshots_updated_at + object_type: FUNCTION + owner: owner_omninode_internal + owner_declaration: node_projection_instruction_eval + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: function + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: update_llm_cost_aggregates_updated_at + object_type: FUNCTION + owner: owner_omninode_internal + owner_declaration: node_projection_cost_summary + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: function + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: update_skill_execution_snapshots_updated_at + object_type: FUNCTION + owner: owner_omninode_internal + owner_declaration: node_projection_skill_executions + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: function + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: update_traces_updated_at + object_type: FUNCTION + owner: owner_omninode_internal + owner_declaration: node_projection_traces + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: sequence + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: baselines_breakdown_id_seq + object_type: SEQUENCE + owner: owner_omninode_internal + owner_declaration: node_projection_baselines + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: sequence + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: baselines_comparisons_id_seq + object_type: SEQUENCE + owner: owner_omninode_internal + owner_declaration: node_projection_baselines + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: sequence + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: baselines_trend_id_seq + object_type: SEQUENCE + owner: owner_omninode_internal + owner_declaration: node_projection_baselines + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: sequence + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: capability_scores_id_seq + object_type: SEQUENCE + owner: owner_omninode_internal + owner_declaration: node_canary_score_reducer + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: sequence + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: contract_registry_id_seq + object_type: SEQUENCE + owner: owner_omninode_internal + owner_declaration: node_contract_registry + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: sequence + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: dep_health_findings_id_seq + object_type: SEQUENCE + owner: owner_omninode_internal + owner_declaration: node_projection_dep_health + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: sequence + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: gate_activity_id_seq + object_type: SEQUENCE + owner: owner_omninode_internal + owner_declaration: node_omnigate_projection + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: sequence + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: intent_classification_events_id_seq + object_type: SEQUENCE + owner: owner_omninode_internal + owner_declaration: node_projection_intent_classification + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: sequence + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: merge_state_transitions_projection_cursor_seq + object_type: SEQUENCE + owner: owner_omninode_internal + owner_declaration: node_merge_state_projection + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: sequence + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: migrations_log_id_seq + object_type: SEQUENCE + owner: owner_omninode_internal + owner_declaration: service:onex_api + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - onex_api_service_ownership + target_materialized: false + - catalog_kind: sequence + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: omnimarket_schema_migrations_id_seq + object_type: SEQUENCE + owner: owner_omninode_internal + owner_declaration: service:omnimarket_projection_migration_runner + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: sequence + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: overnight_session_phases_id_seq + object_type: SEQUENCE + owner: owner_omninode_internal + owner_declaration: node_projection_overnight + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: sequence + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: pr_lifecycle_ledger_entries_id_seq + object_type: SEQUENCE + owner: owner_omninode_internal + owner_declaration: node_pr_lifecycle_state_reducer + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: sequence + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: pr_merged_events_projection_cursor_seq + object_type: SEQUENCE + owner: owner_omninode_internal + owner_declaration: node_pr_merged_projection + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: sequence + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: receipt_gate_rows_id_seq + object_type: SEQUENCE + owner: owner_omninode_internal + owner_declaration: node_projection_receipt_gate + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: sequence + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: stripe_webhook_events_id_seq + object_type: SEQUENCE + owner: owner_omninode_internal + owner_declaration: service:onex_api + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - onex_api_service_ownership + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: agent_routing_decisions + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_projection_routing_decision + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: baselines_breakdown + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_projection_baselines + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: baselines_comparisons + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_projection_baselines + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: baselines_quality_snapshots + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_projection_baselines_quality + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: baselines_roi_snapshots + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_projection_baselines_roi + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: baselines_snapshots + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_projection_baselines + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: baselines_trend + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_projection_baselines + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: capability_scores + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_canary_score_reducer + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: capsule_store + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_projection_capsule_store + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: context_roi_scores + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_projection_context_roi + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: contract_registry + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_contract_registry + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: cost_by_repo_snapshots + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_projection_cost_by_repo + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: dep_health_findings + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_projection_dep_health + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: deployment_evidence_projection + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_deployment_evidence_reducer + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: deployment_readiness_projection + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_deployment_evidence_reducer + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: event_chain + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_projection_event_chain + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: evidence_correlation_trace_projection + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_evidence_dashboard_reducer + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: evidence_dashboard_projection + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_evidence_dashboard_reducer + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: evidence_readiness_aggregate_projection + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_evidence_dashboard_reducer + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: gate_activity + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_omnigate_projection + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: gate_metrics + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_omnigate_projection + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: generation_events + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_projection_delegation + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: instruction_eval_aggregate_snapshots + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_projection_instruction_eval + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: intent_classification_events + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_projection_intent_classification + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: live_events + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_projection_live_events + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: llm_call_metrics + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_projection_llm_cost + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: llm_cost_aggregates + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_projection_cost_summary + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: llm_delegation_daily_projection + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_llm_delegation_projection + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: llm_routing_decisions + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_projection_llm_routing + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: mcp_tools + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_projection_mcp_tools + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: merge_state_transitions + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_merge_state_projection + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: migrations_log + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: service:onex_api + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - onex_api_service_ownership + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: nightly_loop_decisions + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_nightly_loop_controller + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: nightly_loop_iterations + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_nightly_loop_controller + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: node_schema_migrations + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: service:omnibase_infra_node_migration_runner + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - node_migration_service_ownership + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: node_service_registry + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_projection_registration + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: omnimarket_schema_migrations + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: service:omnimarket_projection_migration_runner + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: overnight_session_phases + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_projection_overnight + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: overnight_sessions + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_projection_overnight + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: pattern_learning_artifacts + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_projection_pattern_learning + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: pr_lifecycle_ledger_entries + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_pr_lifecycle_state_reducer + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: pr_merged_events + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_pr_merged_projection + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: view + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: projection_capsule_effectiveness + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_projection_capsule_store + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: view + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: projection_overnight_readiness + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_projection_overnight + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: view + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: projection_routing_decision + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_projection_llm_routing + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: receipt_gate_rows + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_projection_receipt_gate + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: renderer_capability_projection + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_renderer_capability_projection + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: sandbox_decisions + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_projection_sandbox_decisions + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: schema_migrations + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: service:onex_api + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - onex_api_service_ownership + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: session_outcomes + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_projection_session_outcome + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: session_replay_snapshots + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_projection_session_replay + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: skill_execution_snapshots + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_projection_skill_executions + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: stripe_webhook_events + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: service:onex_api + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - onex_api_service_ownership + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: swarm_runs + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_projection_swarm + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: traces + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_projection_traces + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: OMNINODE_INTERNAL + function_signature: null + object_ref: voice_sessions + object_type: TABLE + owner: owner_omninode_internal + owner_declaration: node_projection_voice_sessions + physical_database: omnidash_analytics + schema_ref: omninode_internal + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: PLATFORM_CATALOG + function_signature: null + object_ref: plan_entitlements + object_type: TABLE + owner: owner_platform_catalog + owner_declaration: service:onex_api + physical_database: omnidash_analytics + schema_ref: platform_catalog + source_keys: + - onex_api_service_ownership + target_materialized: false + - catalog_kind: table + database_ref: application + domain: PLATFORM_CATALOG + function_signature: null + object_ref: plan_tiers + object_type: TABLE + owner: owner_platform_catalog + owner_declaration: service:onex_api + physical_database: omnidash_analytics + schema_ref: platform_catalog + source_keys: + - onex_api_service_ownership + target_materialized: false + - catalog_kind: table + database_ref: application + domain: PLATFORM_CATALOG + function_signature: null + object_ref: usage_privileges + object_type: TABLE + owner: owner_platform_catalog + owner_declaration: service:onex_api + physical_database: omnidash_analytics + schema_ref: platform_catalog + source_keys: + - onex_api_service_ownership + target_materialized: false + - catalog_kind: function + database_ref: application + domain: TENANT + function_signature: null + object_ref: refresh_delegation_budget_state_updated_at + object_type: FUNCTION + owner: owner_onex_tenant + owner_declaration: node_projection_delegation + physical_database: omnidash_analytics + schema_ref: tenant + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: function + database_ref: application + domain: TENANT + function_signature: null + object_ref: refresh_savings_estimates_updated_at + object_type: FUNCTION + owner: owner_onex_tenant + owner_declaration: node_projection_savings + physical_database: omnidash_analytics + schema_ref: tenant + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: sequence + database_ref: application + domain: TENANT + function_signature: null + object_ref: bootstrap_tokens_id_seq + object_type: SEQUENCE + owner: owner_onex_tenant + owner_declaration: service:onex_api + physical_database: omnidash_analytics + schema_ref: tenant + source_keys: + - onex_api_service_ownership + target_materialized: false + - catalog_kind: sequence + database_ref: application + domain: TENANT + function_signature: null + object_ref: usage_events_id_seq + object_type: SEQUENCE + owner: owner_onex_tenant + owner_declaration: service:onex_api + physical_database: omnidash_analytics + schema_ref: tenant + source_keys: + - onex_api_service_ownership + target_materialized: false + - catalog_kind: table + database_ref: application + domain: TENANT + function_signature: null + object_ref: bootstrap_tokens + object_type: TABLE + owner: owner_onex_tenant + owner_declaration: service:onex_api + physical_database: omnidash_analytics + schema_ref: tenant + source_keys: + - onex_api_service_ownership + target_materialized: false + - catalog_kind: table + database_ref: application + domain: TENANT + function_signature: null + object_ref: delegation_budget_state + object_type: TABLE + owner: owner_onex_tenant + owner_declaration: node_projection_delegation + physical_database: omnidash_analytics + schema_ref: tenant + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: TENANT + function_signature: null + object_ref: delegation_events + object_type: TABLE + owner: owner_onex_tenant + owner_declaration: node_projection_delegation + physical_database: omnidash_analytics + schema_ref: tenant + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: TENANT + function_signature: null + object_ref: gateway_rate_limit_events + object_type: TABLE + owner: owner_onex_tenant + owner_declaration: service:onex_api + physical_database: omnidash_analytics + schema_ref: tenant + source_keys: + - onex_api_service_ownership + target_materialized: false + - catalog_kind: table + database_ref: application + domain: TENANT + function_signature: null + object_ref: gateway_workflows + object_type: TABLE + owner: owner_onex_tenant + owner_declaration: service:onex_api + physical_database: omnidash_analytics + schema_ref: tenant + source_keys: + - onex_api_service_ownership + target_materialized: false + - catalog_kind: view + database_ref: application + domain: TENANT + function_signature: null + object_ref: projection_cost_savings_overview + object_type: TABLE + owner: owner_onex_tenant + owner_declaration: node_projection_savings + physical_database: omnidash_analytics + schema_ref: tenant + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: TENANT + function_signature: null + object_ref: projection_delegation_inference_response_text + object_type: TABLE + owner: owner_onex_tenant + owner_declaration: node_projection_delegation_inference_response + physical_database: omnidash_analytics + schema_ref: tenant + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: view + database_ref: application + domain: TENANT + function_signature: null + object_ref: projection_delegation_model_routing + object_type: TABLE + owner: owner_onex_tenant + owner_declaration: node_projection_delegation + physical_database: omnidash_analytics + schema_ref: tenant + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: view + database_ref: application + domain: TENANT + function_signature: null + object_ref: projection_delegation_quality_gate + object_type: TABLE + owner: owner_onex_tenant + owner_declaration: node_projection_delegation + physical_database: omnidash_analytics + schema_ref: tenant + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: view + database_ref: application + domain: TENANT + function_signature: null + object_ref: projection_delegation_savings + object_type: TABLE + owner: owner_onex_tenant + owner_declaration: node_projection_savings + physical_database: omnidash_analytics + schema_ref: tenant + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: view + database_ref: application + domain: TENANT + function_signature: null + object_ref: projection_delegation_savings_series + object_type: TABLE + owner: owner_onex_tenant + owner_declaration: node_projection_savings + physical_database: omnidash_analytics + schema_ref: tenant + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: view + database_ref: application + domain: TENANT + function_signature: null + object_ref: projection_delegation_summary + object_type: TABLE + owner: owner_onex_tenant + owner_declaration: node_projection_delegation + physical_database: omnidash_analytics + schema_ref: tenant + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: view + database_ref: application + domain: TENANT + function_signature: null + object_ref: projection_delegation_token_usage + object_type: TABLE + owner: owner_onex_tenant + owner_declaration: node_projection_delegation + physical_database: omnidash_analytics + schema_ref: tenant + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: TENANT + function_signature: null + object_ref: savings_estimates + object_type: TABLE + owner: owner_onex_tenant + owner_declaration: node_projection_savings + physical_database: omnidash_analytics + schema_ref: tenant + source_keys: + - omnimarket_relation_inventory + target_materialized: false + - catalog_kind: table + database_ref: application + domain: TENANT + function_signature: null + object_ref: tenant_api_keys + object_type: TABLE + owner: owner_onex_tenant + owner_declaration: service:onex_api + physical_database: omnidash_analytics + schema_ref: tenant + source_keys: + - onex_api_service_ownership + target_materialized: false + - catalog_kind: table + database_ref: application + domain: TENANT + function_signature: null + object_ref: tenant_billing + object_type: TABLE + owner: owner_onex_tenant + owner_declaration: service:onex_api + physical_database: omnidash_analytics + schema_ref: tenant + source_keys: + - onex_api_service_ownership + target_materialized: false + - catalog_kind: table + database_ref: application + domain: TENANT + function_signature: null + object_ref: tenant_credentials + object_type: TABLE + owner: owner_onex_tenant + owner_declaration: service:onex_api + physical_database: omnidash_analytics + schema_ref: tenant + source_keys: + - onex_api_service_ownership + target_materialized: false + - catalog_kind: table + database_ref: application + domain: TENANT + function_signature: null + object_ref: tenant_plans + object_type: TABLE + owner: owner_onex_tenant + owner_declaration: service:onex_api + physical_database: omnidash_analytics + schema_ref: tenant + source_keys: + - onex_api_service_ownership + target_materialized: false + - catalog_kind: table + database_ref: application + domain: TENANT + function_signature: null + object_ref: tenants + object_type: TABLE + owner: owner_onex_tenant + owner_declaration: service:onex_api + physical_database: omnidash_analytics + schema_ref: tenant + source_keys: + - onex_api_service_ownership + target_materialized: false + - catalog_kind: table + database_ref: application + domain: TENANT + function_signature: null + object_ref: usage_events + object_type: TABLE + owner: owner_onex_tenant + owner_declaration: service:onex_api + physical_database: omnidash_analytics + schema_ref: tenant + source_keys: + - onex_api_service_ownership + target_materialized: false + - catalog_kind: table + database_ref: application + domain: TENANT + function_signature: null + object_ref: workflow_results + object_type: TABLE + owner: owner_onex_tenant + owner_declaration: service:onex_api + physical_database: omnidash_analytics + schema_ref: tenant + source_keys: + - onex_api_service_ownership + target_materialized: false +observed_connect_database_owners: {} +observed_connect_principals: {} +observed_objects: [] +observed_owner_roles: [] +observed_principals: + application: [] +observed_role_states: [] +observed_schema_owners: + application: {} +principal_domains: {} +required_connect_databases: + - keycloak + - omnibase_infra + - omniclaude + - omnidash_analytics + - omniintelligence + - omnimemory + - omninode_cloud + - umami +retained_administrative_principals: [] +rows: + - database_ref: application + function_signature: null + object_ref: null + object_type: DATABASE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: null + - database_ref: application + function_signature: null + object_ref: refresh_baselines_quality_snapshots_projected_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: refresh_baselines_roi_snapshots_projected_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: refresh_capsule_store_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: refresh_context_roi_scores_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: refresh_intent_classification_events_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: refresh_session_outcomes_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: refresh_voice_sessions_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: update_cost_by_repo_snapshots_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: update_instruction_eval_aggregate_snapshots_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: update_llm_cost_aggregates_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: update_skill_execution_snapshots_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: update_traces_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: refresh_delegation_budget_state_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: refresh_savings_estimates_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: null + object_type: SCHEMA + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: null + object_type: SCHEMA + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: platform_catalog + - database_ref: application + function_signature: null + object_ref: null + object_type: SCHEMA + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: baselines_breakdown_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_comparisons_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_trend_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: capability_scores_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: contract_registry_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: dep_health_findings_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: gate_activity_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: intent_classification_events_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: merge_state_transitions_projection_cursor_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: migrations_log_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: omnimarket_schema_migrations_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: overnight_session_phases_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: pr_lifecycle_ledger_entries_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: pr_merged_events_projection_cursor_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: receipt_gate_rows_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: stripe_webhook_events_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: bootstrap_tokens_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: usage_events_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: agent_routing_decisions + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_breakdown + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_comparisons + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_quality_snapshots + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_roi_snapshots + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_snapshots + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_trend + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: capability_scores + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: capsule_store + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: context_roi_scores + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: contract_registry + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: cost_by_repo_snapshots + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: dep_health_findings + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: deployment_evidence_projection + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: deployment_readiness_projection + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: event_chain + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: evidence_correlation_trace_projection + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: evidence_dashboard_projection + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: evidence_readiness_aggregate_projection + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: gate_activity + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: gate_metrics + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: generation_events + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: instruction_eval_aggregate_snapshots + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: intent_classification_events + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: live_events + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: llm_call_metrics + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: llm_cost_aggregates + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: llm_delegation_daily_projection + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: llm_routing_decisions + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: mcp_tools + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: merge_state_transitions + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: migrations_log + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: nightly_loop_decisions + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: nightly_loop_iterations + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: node_schema_migrations + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: node_service_registry + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: omnimarket_schema_migrations + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: overnight_session_phases + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: overnight_sessions + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: pattern_learning_artifacts + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: pr_lifecycle_ledger_entries + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: pr_merged_events + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: projection_capsule_effectiveness + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: projection_overnight_readiness + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: projection_routing_decision + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: receipt_gate_rows + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: renderer_capability_projection + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: sandbox_decisions + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: schema_migrations + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: session_outcomes + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: session_replay_snapshots + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: skill_execution_snapshots + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: stripe_webhook_events + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: swarm_runs + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: traces + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: voice_sessions + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: plan_entitlements + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: platform_catalog + - database_ref: application + function_signature: null + object_ref: plan_tiers + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: platform_catalog + - database_ref: application + function_signature: null + object_ref: usage_privileges + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: platform_catalog + - database_ref: application + function_signature: null + object_ref: bootstrap_tokens + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: delegation_budget_state + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: delegation_events + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: gateway_rate_limit_events + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: gateway_workflows + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_cost_savings_overview + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_delegation_inference_response_text + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_delegation_model_routing + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_delegation_quality_gate + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_delegation_savings + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_delegation_savings_series + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_delegation_summary + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_delegation_token_usage + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: savings_estimates + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: tenant_api_keys + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: tenant_billing + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: tenant_credentials + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: tenant_plans + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: tenants + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: usage_events + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: workflow_results + object_type: TABLE + physical_database: omnidash_analytics + principal: PUBLIC + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: null + object_type: DATABASE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: + - CONNECT + schema_ref: null + - database_ref: application + function_signature: null + object_ref: refresh_baselines_quality_snapshots_projected_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: refresh_baselines_roi_snapshots_projected_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: refresh_capsule_store_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: refresh_context_roi_scores_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: refresh_intent_classification_events_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: refresh_session_outcomes_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: refresh_voice_sessions_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: update_cost_by_repo_snapshots_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: update_instruction_eval_aggregate_snapshots_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: update_llm_cost_aggregates_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: update_skill_execution_snapshots_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: update_traces_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: refresh_delegation_budget_state_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: refresh_savings_estimates_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: null + object_type: SCHEMA + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: null + object_type: SCHEMA + physical_database: omnidash_analytics + principal: app_dashboard + privileges: + - USAGE + schema_ref: platform_catalog + - database_ref: application + function_signature: null + object_ref: null + object_type: SCHEMA + physical_database: omnidash_analytics + principal: app_dashboard + privileges: + - USAGE + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: baselines_breakdown_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_comparisons_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_trend_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: capability_scores_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: contract_registry_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: dep_health_findings_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: gate_activity_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: intent_classification_events_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: merge_state_transitions_projection_cursor_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: migrations_log_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: omnimarket_schema_migrations_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: overnight_session_phases_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: pr_lifecycle_ledger_entries_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: pr_merged_events_projection_cursor_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: receipt_gate_rows_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: stripe_webhook_events_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: bootstrap_tokens_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: usage_events_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: agent_routing_decisions + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_breakdown + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_comparisons + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_quality_snapshots + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_roi_snapshots + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_snapshots + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_trend + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: capability_scores + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: capsule_store + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: context_roi_scores + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: contract_registry + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: cost_by_repo_snapshots + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: dep_health_findings + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: deployment_evidence_projection + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: deployment_readiness_projection + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: event_chain + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: evidence_correlation_trace_projection + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: evidence_dashboard_projection + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: evidence_readiness_aggregate_projection + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: gate_activity + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: gate_metrics + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: generation_events + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: instruction_eval_aggregate_snapshots + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: intent_classification_events + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: live_events + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: llm_call_metrics + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: llm_cost_aggregates + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: llm_delegation_daily_projection + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: llm_routing_decisions + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: mcp_tools + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: merge_state_transitions + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: migrations_log + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: nightly_loop_decisions + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: nightly_loop_iterations + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: node_schema_migrations + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: node_service_registry + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: omnimarket_schema_migrations + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: overnight_session_phases + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: overnight_sessions + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: pattern_learning_artifacts + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: pr_lifecycle_ledger_entries + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: pr_merged_events + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: projection_capsule_effectiveness + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: projection_overnight_readiness + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: projection_routing_decision + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: receipt_gate_rows + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: renderer_capability_projection + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: sandbox_decisions + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: schema_migrations + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: session_outcomes + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: session_replay_snapshots + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: skill_execution_snapshots + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: stripe_webhook_events + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: swarm_runs + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: traces + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: voice_sessions + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: plan_entitlements + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: platform_catalog + - database_ref: application + function_signature: null + object_ref: plan_tiers + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: platform_catalog + - database_ref: application + function_signature: null + object_ref: usage_privileges + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: platform_catalog + - database_ref: application + function_signature: null + object_ref: bootstrap_tokens + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: delegation_budget_state + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: delegation_events + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: gateway_rate_limit_events + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: gateway_workflows + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_cost_savings_overview + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_delegation_inference_response_text + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_delegation_model_routing + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_delegation_quality_gate + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_delegation_savings + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_delegation_savings_series + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_delegation_summary + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_delegation_token_usage + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: savings_estimates + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: tenant_api_keys + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: tenant_billing + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: tenant_credentials + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: tenant_plans + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: tenants + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: usage_events + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: workflow_results + object_type: TABLE + physical_database: omnidash_analytics + principal: app_dashboard + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: null + object_type: DATABASE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: + - CONNECT + schema_ref: null + - database_ref: application + function_signature: null + object_ref: refresh_baselines_quality_snapshots_projected_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: refresh_baselines_roi_snapshots_projected_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: refresh_capsule_store_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: refresh_context_roi_scores_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: refresh_intent_classification_events_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: refresh_session_outcomes_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: refresh_voice_sessions_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: update_cost_by_repo_snapshots_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: update_instruction_eval_aggregate_snapshots_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: update_llm_cost_aggregates_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: update_skill_execution_snapshots_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: update_traces_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: refresh_delegation_budget_state_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: refresh_savings_estimates_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: null + object_type: SCHEMA + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: + - USAGE + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: null + object_type: SCHEMA + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: platform_catalog + - database_ref: application + function_signature: null + object_ref: null + object_type: SCHEMA + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: baselines_breakdown_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_comparisons_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_trend_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: capability_scores_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: contract_registry_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: dep_health_findings_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: gate_activity_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: intent_classification_events_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: merge_state_transitions_projection_cursor_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: migrations_log_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: omnimarket_schema_migrations_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: overnight_session_phases_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: pr_lifecycle_ledger_entries_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: pr_merged_events_projection_cursor_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: receipt_gate_rows_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: stripe_webhook_events_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: bootstrap_tokens_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: usage_events_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: agent_routing_decisions + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_breakdown + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_comparisons + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_quality_snapshots + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_roi_snapshots + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_snapshots + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_trend + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: capability_scores + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: capsule_store + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: context_roi_scores + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: contract_registry + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: cost_by_repo_snapshots + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: dep_health_findings + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: deployment_evidence_projection + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: deployment_readiness_projection + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: event_chain + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: evidence_correlation_trace_projection + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: evidence_dashboard_projection + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: evidence_readiness_aggregate_projection + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: gate_activity + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: gate_metrics + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: generation_events + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: instruction_eval_aggregate_snapshots + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: intent_classification_events + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: live_events + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: llm_call_metrics + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: llm_cost_aggregates + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: llm_delegation_daily_projection + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: llm_routing_decisions + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: mcp_tools + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: merge_state_transitions + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: migrations_log + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: nightly_loop_decisions + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: nightly_loop_iterations + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: node_schema_migrations + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: node_service_registry + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: omnimarket_schema_migrations + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: overnight_session_phases + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: overnight_sessions + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: pattern_learning_artifacts + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: pr_lifecycle_ledger_entries + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: pr_merged_events + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: projection_capsule_effectiveness + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: projection_overnight_readiness + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: projection_routing_decision + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: receipt_gate_rows + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: renderer_capability_projection + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: sandbox_decisions + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: schema_migrations + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: session_outcomes + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: session_replay_snapshots + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: skill_execution_snapshots + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: stripe_webhook_events + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: swarm_runs + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: traces + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: voice_sessions + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: plan_entitlements + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: platform_catalog + - database_ref: application + function_signature: null + object_ref: plan_tiers + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: platform_catalog + - database_ref: application + function_signature: null + object_ref: usage_privileges + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: platform_catalog + - database_ref: application + function_signature: null + object_ref: bootstrap_tokens + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: delegation_budget_state + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: delegation_events + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: gateway_rate_limit_events + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: gateway_workflows + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_cost_savings_overview + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_delegation_inference_response_text + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_delegation_model_routing + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_delegation_quality_gate + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_delegation_savings + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_delegation_savings_series + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_delegation_summary + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_delegation_token_usage + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: savings_estimates + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: tenant_api_keys + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: tenant_billing + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: tenant_credentials + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: tenant_plans + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: tenants + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: usage_events + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: workflow_results + object_type: TABLE + physical_database: omnidash_analytics + principal: omninode_runtime + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: null + object_type: DATABASE + physical_database: omnidash_analytics + principal: onex_api + privileges: + - CONNECT + schema_ref: null + - database_ref: application + function_signature: null + object_ref: refresh_baselines_quality_snapshots_projected_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: refresh_baselines_roi_snapshots_projected_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: refresh_capsule_store_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: refresh_context_roi_scores_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: refresh_intent_classification_events_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: refresh_session_outcomes_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: refresh_voice_sessions_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: update_cost_by_repo_snapshots_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: update_instruction_eval_aggregate_snapshots_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: update_llm_cost_aggregates_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: update_skill_execution_snapshots_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: update_traces_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: refresh_delegation_budget_state_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: refresh_savings_estimates_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: null + object_type: SCHEMA + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: null + object_type: SCHEMA + physical_database: omnidash_analytics + principal: onex_api + privileges: + - USAGE + schema_ref: platform_catalog + - database_ref: application + function_signature: null + object_ref: null + object_type: SCHEMA + physical_database: omnidash_analytics + principal: onex_api + privileges: + - USAGE + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: baselines_breakdown_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_comparisons_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_trend_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: capability_scores_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: contract_registry_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: dep_health_findings_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: gate_activity_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: intent_classification_events_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: merge_state_transitions_projection_cursor_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: migrations_log_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: omnimarket_schema_migrations_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: overnight_session_phases_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: pr_lifecycle_ledger_entries_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: pr_merged_events_projection_cursor_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: receipt_gate_rows_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: stripe_webhook_events_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: bootstrap_tokens_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: usage_events_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: agent_routing_decisions + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_breakdown + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_comparisons + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_quality_snapshots + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_roi_snapshots + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_snapshots + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_trend + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: capability_scores + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: capsule_store + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: context_roi_scores + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: contract_registry + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: cost_by_repo_snapshots + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: dep_health_findings + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: deployment_evidence_projection + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: deployment_readiness_projection + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: event_chain + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: evidence_correlation_trace_projection + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: evidence_dashboard_projection + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: evidence_readiness_aggregate_projection + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: gate_activity + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: gate_metrics + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: generation_events + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: instruction_eval_aggregate_snapshots + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: intent_classification_events + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: live_events + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: llm_call_metrics + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: llm_cost_aggregates + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: llm_delegation_daily_projection + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: llm_routing_decisions + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: mcp_tools + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: merge_state_transitions + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: migrations_log + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: nightly_loop_decisions + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: nightly_loop_iterations + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: node_schema_migrations + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: node_service_registry + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: omnimarket_schema_migrations + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: overnight_session_phases + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: overnight_sessions + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: pattern_learning_artifacts + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: pr_lifecycle_ledger_entries + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: pr_merged_events + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: projection_capsule_effectiveness + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: projection_overnight_readiness + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: projection_routing_decision + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: receipt_gate_rows + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: renderer_capability_projection + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: sandbox_decisions + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: schema_migrations + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: session_outcomes + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: session_replay_snapshots + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: skill_execution_snapshots + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: stripe_webhook_events + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: swarm_runs + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: traces + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: voice_sessions + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: plan_entitlements + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: platform_catalog + - database_ref: application + function_signature: null + object_ref: plan_tiers + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: platform_catalog + - database_ref: application + function_signature: null + object_ref: usage_privileges + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: platform_catalog + - database_ref: application + function_signature: null + object_ref: bootstrap_tokens + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: delegation_budget_state + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: delegation_events + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: gateway_rate_limit_events + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: gateway_workflows + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_cost_savings_overview + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_delegation_inference_response_text + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_delegation_model_routing + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_delegation_quality_gate + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_delegation_savings + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_delegation_savings_series + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_delegation_summary + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_delegation_token_usage + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: savings_estimates + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: tenant_api_keys + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: tenant_billing + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: tenant_credentials + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: tenant_plans + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: tenants + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: usage_events + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: workflow_results + object_type: TABLE + physical_database: omnidash_analytics + principal: onex_api + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: null + object_type: DATABASE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: + - CONNECT + schema_ref: null + - database_ref: application + function_signature: null + object_ref: refresh_baselines_quality_snapshots_projected_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: refresh_baselines_roi_snapshots_projected_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: refresh_capsule_store_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: refresh_context_roi_scores_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: refresh_intent_classification_events_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: refresh_session_outcomes_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: refresh_voice_sessions_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: update_cost_by_repo_snapshots_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: update_instruction_eval_aggregate_snapshots_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: update_llm_cost_aggregates_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: update_skill_execution_snapshots_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: update_traces_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: refresh_delegation_budget_state_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: refresh_savings_estimates_updated_at + object_type: FUNCTION + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: null + object_type: SCHEMA + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: null + object_type: SCHEMA + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: platform_catalog + - database_ref: application + function_signature: null + object_ref: null + object_type: SCHEMA + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: + - USAGE + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: baselines_breakdown_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_comparisons_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_trend_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: capability_scores_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: contract_registry_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: dep_health_findings_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: gate_activity_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: intent_classification_events_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: merge_state_transitions_projection_cursor_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: migrations_log_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: omnimarket_schema_migrations_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: overnight_session_phases_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: pr_lifecycle_ledger_entries_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: pr_merged_events_projection_cursor_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: receipt_gate_rows_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: stripe_webhook_events_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: bootstrap_tokens_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: usage_events_id_seq + object_type: SEQUENCE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: agent_routing_decisions + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_breakdown + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_comparisons + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_quality_snapshots + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_roi_snapshots + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_snapshots + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: baselines_trend + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: capability_scores + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: capsule_store + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: context_roi_scores + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: contract_registry + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: cost_by_repo_snapshots + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: dep_health_findings + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: deployment_evidence_projection + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: deployment_readiness_projection + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: event_chain + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: evidence_correlation_trace_projection + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: evidence_dashboard_projection + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: evidence_readiness_aggregate_projection + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: gate_activity + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: gate_metrics + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: generation_events + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: instruction_eval_aggregate_snapshots + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: intent_classification_events + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: live_events + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: llm_call_metrics + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: llm_cost_aggregates + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: llm_delegation_daily_projection + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: llm_routing_decisions + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: mcp_tools + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: merge_state_transitions + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: migrations_log + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: nightly_loop_decisions + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: nightly_loop_iterations + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: node_schema_migrations + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: node_service_registry + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: omnimarket_schema_migrations + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: overnight_session_phases + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: overnight_sessions + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: pattern_learning_artifacts + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: pr_lifecycle_ledger_entries + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: pr_merged_events + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: projection_capsule_effectiveness + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: projection_overnight_readiness + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: projection_routing_decision + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: receipt_gate_rows + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: renderer_capability_projection + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: sandbox_decisions + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: schema_migrations + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: session_outcomes + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: session_replay_snapshots + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: skill_execution_snapshots + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: stripe_webhook_events + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: swarm_runs + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: traces + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: voice_sessions + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: omninode_internal + - database_ref: application + function_signature: null + object_ref: plan_entitlements + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: platform_catalog + - database_ref: application + function_signature: null + object_ref: plan_tiers + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: platform_catalog + - database_ref: application + function_signature: null + object_ref: usage_privileges + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: platform_catalog + - database_ref: application + function_signature: null + object_ref: bootstrap_tokens + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: delegation_budget_state + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: delegation_events + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: gateway_rate_limit_events + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: gateway_workflows + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_cost_savings_overview + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_delegation_inference_response_text + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_delegation_model_routing + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_delegation_quality_gate + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_delegation_savings + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_delegation_savings_series + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_delegation_summary + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: projection_delegation_token_usage + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: savings_estimates + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: tenant_api_keys + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: tenant_billing + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: tenant_credentials + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: tenant_plans + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: tenants + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: usage_events + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: tenant + - database_ref: application + function_signature: null + object_ref: workflow_results + object_type: TABLE + physical_database: omnidash_analytics + principal: tenant_projection_writer + privileges: [] + schema_ref: tenant +scaffold_blockers: + - 'ACL scaffold policy violation: additive scaffold intended roles are not already safe or proven absent: [''app_dashboard'', ''omninode_runtime'', ''onex_api'', ''owner_omninode_internal'', ''owner_onex_tenant'', ''owner_platform_catalog'', ''tenant_projection_writer'']' + - 'ACL scaffold policy violation: allowed CONNECT database keys do not cover required CONNECT set' + - 'ACL scaffold policy violation: application: scaffold lacks exact target schema evidence' + - 'ACL scaffold policy violation: application: scaffold lacks presence/absence evidence for declared principals' + - 'ACL scaffold policy violation: keycloak: CONNECT allowlist is empty' + - 'ACL scaffold policy violation: observed CONNECT database keys do not cover required CONNECT set' + - 'ACL scaffold policy violation: observed CONNECT owner database keys do not cover required CONNECT set' + - 'ACL scaffold policy violation: omnibase_infra: CONNECT allowlist is empty' + - 'ACL scaffold policy violation: omniclaude: CONNECT allowlist is empty' + - 'ACL scaffold policy violation: omnidash_analytics: CONNECT allowlist is empty' + - 'ACL scaffold policy violation: omniintelligence: CONNECT allowlist is empty' + - 'ACL scaffold policy violation: omnimemory: CONNECT allowlist is empty' + - 'ACL scaffold policy violation: omninode_cloud: CONNECT allowlist is empty' + - 'ACL scaffold policy violation: principal ''app_dashboard'' has cross-domain scaffold access' + - 'ACL scaffold policy violation: principal ''omninode_runtime'' has cross-domain scaffold access' + - 'ACL scaffold policy violation: principal ''onex_api'' has cross-domain scaffold access' + - 'ACL scaffold policy violation: principal ''tenant_projection_writer'' has cross-domain scaffold access' + - 'ACL scaffold policy violation: scaffold database owner map is incomplete' + - 'ACL scaffold policy violation: scaffold managed owners lack governed owner-role state' + - 'ACL scaffold policy violation: scaffold managed owners lack presence/absence evidence' + - 'ACL scaffold policy violation: scaffold workloads lack governed LOGIN role state' + - 'ACL scaffold policy violation: umami: CONNECT allowlist is empty' + - 'application: requires exactly one independent ACL policy, got []' + - 'application: requires exactly one principal inventory, got []' + - 'keycloak: requires exactly one CONNECT policy, got []' + - matrix requires a typed principal_inventory source for every database + - matrix requires an independent typed acl_policy source for every database + - 'omnibase_infra: requires exactly one CONNECT policy, got []' + - 'omniclaude: requires exactly one CONNECT policy, got []' + - 'omnidash_analytics: requires exactly one CONNECT policy, got []' + - 'omniintelligence: requires exactly one CONNECT policy, got []' + - 'omnimemory: requires exactly one CONNECT policy, got []' + - 'omninode_cloud: requires exactly one CONNECT policy, got []' + - 'umami: requires exactly one CONNECT policy, got []' +scaffold_status: BLOCKED +schema_domains: + application: + omninode_internal: OMNINODE_INTERNAL + platform_catalog: PLATFORM_CATALOG + tenant: TENANT +schema_version: '1.0' +sources: + - path: topology/kubernetes/source-lock.yaml + purpose: rendered_topology + repository: OmniNode-ai/omninode_infra + revision: 1a1fff92cbf8e02e488ac6e6e89b1087ca396657 + sha256: aa6b4502f79244160f07769da788f1826f2b9d5e756b477508eddf5af929226f + source_key: kubernetes_topology_projection + - path: k8s/migrations/application-relation-ownership.yaml + purpose: service_ownership + repository: OmniNode-ai/omninode_infra + revision: 39033d55147ef22a061b665345b506246d3aa543 + sha256: 8ca701c4804d2f7d749dc1ef2a26fc383dcd3806bc42c004ed8851a5ff5d25e0 + source_key: node_migration_service_ownership + - path: docs/evidence/OMN-15423-relation-inventory.json + purpose: relation_inventory + repository: OmniNode-ai/omnimarket + revision: a0f65e9471da06b88eecb91bbc1c847989cb10d8 + sha256: c7ff16080dc553ae204da405519f51b5b631847b129f5876db136c048a4c63da + source_key: omnimarket_relation_inventory + - path: db/migrations/application-relation-ownership.yaml + purpose: service_ownership + repository: OmniNode-ai/omninode_infra + revision: 39033d55147ef22a061b665345b506246d3aa543 + sha256: 4a47bb42a8e724ffc44453cb649b754568f3ffa83dabaf831ccfaebaa0723712 + source_key: onex_api_service_ownership + - path: docker/legacy-rds-fixture/fixture-manifest.json + purpose: legacy_fixture + repository: OmniNode-ai/omnibase_infra + revision: 18df1728bdbcc7a773c790f64b6569f58b524841 + sha256: 1cdc1db7d707bc2daa72ad8f1521bb589cf87594e5b48f6480893b08875e3f26 + source_key: sanitized_legacy_fixture + - path: src/omnibase_infra/topology/instances/local.yaml + purpose: topology + repository: OmniNode-ai/omnibase_infra + revision: d7f1ac464a54696ac9ed05fd8f3766463a0a7eea + sha256: e4170e97e26fb9c63a53f5f660cedacd15bf7e99609309c54bff15c3d026ac8d + source_key: topology_owner + - path: src/omnibase_infra/validation/application_relation_ownership.py + purpose: typed_loader + repository: OmniNode-ai/omnibase_infra + revision: 9e9e62c3177f568b7e5110f653ee4be6dcda965c + sha256: be712ed5d6372dc9bc0720742291b2739f7b815c61abbab3d87157dfb80216c4 + source_key: typed_ownership_loader +status: BLOCKED +verified_evidence_source_keys: [] diff --git a/docker/application-acl-proof/generated/prechange-fixture-acl.json b/docker/application-acl-proof/generated/prechange-fixture-acl.json new file mode 100644 index 0000000000..84a853e2f4 --- /dev/null +++ b/docker/application-acl-proof/generated/prechange-fixture-acl.json @@ -0,0 +1,1361 @@ +{ + "column_acl": [ + { + "catalog_kind": "table", + "column_name": "display_name", + "grantee": "rls_admin", + "grantor": "onex_api", + "is_grantable": true, + "object_name": "tenant_accounts", + "privilege_type": "UPDATE", + "schema_name": "tenant" + }, + { + "catalog_kind": "table", + "column_name": "display_name", + "grantee": "untrusted_login", + "grantor": "onex_api", + "is_grantable": true, + "object_name": "tenant_accounts", + "privilege_type": "SELECT", + "schema_name": "tenant" + }, + { + "catalog_kind": "table", + "column_name": "display_name", + "grantee": "untrusted_login", + "grantor": "rls_admin", + "is_grantable": false, + "object_name": "tenant_accounts", + "privilege_type": "UPDATE", + "schema_name": "tenant" + } + ], + "database_acl": [ + { + "database_name": "keycloak", + "grantee": "PUBLIC", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "CONNECT" + }, + { + "database_name": "keycloak", + "grantee": "PUBLIC", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "TEMPORARY" + }, + { + "database_name": "keycloak", + "grantee": "app_dashboard", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "CREATE" + }, + { + "database_name": "keycloak", + "grantee": "external_connect_parent", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "CONNECT" + }, + { + "database_name": "omnibase_infra", + "grantee": "PUBLIC", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "CONNECT" + }, + { + "database_name": "omnibase_infra", + "grantee": "PUBLIC", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "TEMPORARY" + }, + { + "database_name": "omnibase_infra", + "grantee": "keycloak_service", + "grantor": "rls_admin", + "is_grantable": false, + "privilege_type": "CONNECT" + }, + { + "database_name": "omnibase_infra", + "grantee": "onex_api", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "CREATE" + }, + { + "database_name": "omnibase_infra", + "grantee": "onex_api", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "TEMPORARY" + }, + { + "database_name": "omnibase_infra", + "grantee": "rls_admin", + "grantor": "postgres", + "is_grantable": true, + "privilege_type": "CONNECT" + }, + { + "database_name": "omnibase_infra", + "grantee": "rls_admin", + "grantor": "postgres", + "is_grantable": true, + "privilege_type": "CREATE" + }, + { + "database_name": "omniclaude", + "grantee": "PUBLIC", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "CONNECT" + }, + { + "database_name": "omniclaude", + "grantee": "PUBLIC", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "TEMPORARY" + }, + { + "database_name": "omnidash_analytics", + "grantee": "PUBLIC", + "grantor": "app_dashboard", + "is_grantable": false, + "privilege_type": "CONNECT" + }, + { + "database_name": "omnidash_analytics", + "grantee": "PUBLIC", + "grantor": "app_dashboard", + "is_grantable": false, + "privilege_type": "TEMPORARY" + }, + { + "database_name": "omnidash_analytics", + "grantee": "untrusted_login", + "grantor": "app_dashboard", + "is_grantable": false, + "privilege_type": "CONNECT" + }, + { + "database_name": "omnidash_analytics", + "grantee": "untrusted_login", + "grantor": "app_dashboard", + "is_grantable": false, + "privilege_type": "TEMPORARY" + }, + { + "database_name": "omniintelligence", + "grantee": "PUBLIC", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "CONNECT" + }, + { + "database_name": "omniintelligence", + "grantee": "PUBLIC", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "TEMPORARY" + }, + { + "database_name": "omnimemory", + "grantee": "PUBLIC", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "CONNECT" + }, + { + "database_name": "omnimemory", + "grantee": "PUBLIC", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "TEMPORARY" + }, + { + "database_name": "omninode_cloud", + "grantee": "PUBLIC", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "CONNECT" + }, + { + "database_name": "omninode_cloud", + "grantee": "PUBLIC", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "TEMPORARY" + }, + { + "database_name": "umami", + "grantee": "PUBLIC", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "CONNECT" + }, + { + "database_name": "umami", + "grantee": "PUBLIC", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "TEMPORARY" + } + ], + "database_owner": [ + { + "database_name": "keycloak", + "owner": "postgres" + }, + { + "database_name": "omnibase_infra", + "owner": "postgres" + }, + { + "database_name": "omniclaude", + "owner": "postgres" + }, + { + "database_name": "omnidash_analytics", + "owner": "app_dashboard" + }, + { + "database_name": "omniintelligence", + "owner": "postgres" + }, + { + "database_name": "omnimemory", + "owner": "postgres" + }, + { + "database_name": "omninode_cloud", + "owner": "postgres" + }, + { + "database_name": "umami", + "owner": "postgres" + } + ], + "default_acl": [ + { + "grantee": "PUBLIC", + "grantor": "owner_onex_tenant", + "is_grantable": false, + "object_type": "FUNCTION", + "owner": "owner_onex_tenant", + "privilege_type": "EXECUTE", + "schema_name": "tenant" + }, + { + "grantee": "app_dashboard", + "grantor": "owner_onex_tenant", + "is_grantable": false, + "object_type": "TABLE", + "owner": "owner_onex_tenant", + "privilege_type": "SELECT", + "schema_name": null + }, + { + "grantee": "app_dashboard", + "grantor": "owner_onex_tenant", + "is_grantable": true, + "object_type": "TABLE", + "owner": "owner_onex_tenant", + "privilege_type": "SELECT", + "schema_name": "tenant" + }, + { + "grantee": "keycloak_service", + "grantor": "owner_onex_tenant", + "is_grantable": true, + "object_type": "TABLE", + "owner": "owner_onex_tenant", + "privilege_type": "SELECT", + "schema_name": "tenant" + }, + { + "grantee": "untrusted_login", + "grantor": "owner_onex_tenant", + "is_grantable": false, + "object_type": "TABLE", + "owner": "owner_onex_tenant", + "privilege_type": "SELECT", + "schema_name": null + } + ], + "default_acl_catalog_rows": [ + { + "object_type": "FUNCTION", + "owner": "owner_onex_tenant", + "raw_acl": "=X/owner_onex_tenant", + "schema_name": "tenant" + }, + { + "object_type": "TABLE", + "owner": "owner_onex_tenant", + "raw_acl": "app_dashboard=r*/owner_onex_tenant,keycloak_service=r*/owner_onex_tenant", + "schema_name": "tenant" + }, + { + "object_type": "TABLE", + "owner": "owner_onex_tenant", + "raw_acl": "app_dashboard=r/owner_onex_tenant,owner_onex_tenant=arwdDxt/owner_onex_tenant,untrusted_login=r/owner_onex_tenant", + "schema_name": null + } + ], + "memberships": [ + { + "admin_option": false, + "grantor": "postgres", + "inherit_option": false, + "member_role": "owner_onex_tenant", + "parent_role": "rls_admin", + "set_option": true + }, + { + "admin_option": false, + "grantor": "postgres", + "inherit_option": true, + "member_role": "omninode_runtime", + "parent_role": "owner_omninode_internal", + "set_option": true + }, + { + "admin_option": false, + "grantor": "postgres", + "inherit_option": true, + "member_role": "shadow_login", + "parent_role": "keycloak_service", + "set_option": true + }, + { + "admin_option": false, + "grantor": "postgres", + "inherit_option": true, + "member_role": "tenant_projection_writer", + "parent_role": "owner_onex_tenant", + "set_option": true + }, + { + "admin_option": false, + "grantor": "rls_admin", + "inherit_option": false, + "member_role": "keycloak_service", + "parent_role": "external_connect_parent", + "set_option": true + }, + { + "admin_option": true, + "grantor": "postgres", + "inherit_option": true, + "member_role": "app_dashboard", + "parent_role": "rls_admin", + "set_option": true + }, + { + "admin_option": true, + "grantor": "postgres", + "inherit_option": true, + "member_role": "db_migrator", + "parent_role": "owner_onex_tenant", + "set_option": false + } + ], + "object_acl": [ + { + "catalog_kind": "function", + "function_signature": "()", + "grantee": "PUBLIC", + "grantor": "app_dashboard", + "is_grantable": false, + "object_name": "delegation_event_count", + "object_type": "FUNCTION", + "privilege_type": "EXECUTE", + "schema_name": "tenant" + }, + { + "catalog_kind": "function", + "function_signature": "()", + "grantee": "PUBLIC", + "grantor": "onex_api", + "is_grantable": false, + "object_name": "account_id_span_set", + "object_type": "FUNCTION", + "privilege_type": "EXECUTE", + "schema_name": "tenant" + }, + { + "catalog_kind": "function", + "function_signature": "(VARIADIC tenant.account_id_span[])", + "grantee": "PUBLIC", + "grantor": "onex_api", + "is_grantable": false, + "object_name": "account_id_span_set", + "object_type": "FUNCTION", + "privilege_type": "EXECUTE", + "schema_name": "tenant" + }, + { + "catalog_kind": "function", + "function_signature": "(\"arg'name%\" integer)", + "grantee": "PUBLIC", + "grantor": "app_dashboard", + "is_grantable": false, + "object_name": "hostile_signature", + "object_type": "FUNCTION", + "privilege_type": "EXECUTE", + "schema_name": "tenant" + }, + { + "catalog_kind": "function", + "function_signature": "(bigint, bigint)", + "grantee": "PUBLIC", + "grantor": "onex_api", + "is_grantable": false, + "object_name": "account_id_span", + "object_type": "FUNCTION", + "privilege_type": "EXECUTE", + "schema_name": "tenant" + }, + { + "catalog_kind": "function", + "function_signature": "(bigint, bigint, text)", + "grantee": "PUBLIC", + "grantor": "onex_api", + "is_grantable": false, + "object_name": "account_id_span", + "object_type": "FUNCTION", + "privilege_type": "EXECUTE", + "schema_name": "tenant" + }, + { + "catalog_kind": "function", + "function_signature": "(tenant.account_id_span)", + "grantee": "PUBLIC", + "grantor": "onex_api", + "is_grantable": false, + "object_name": "account_id_span_set", + "object_type": "FUNCTION", + "privilege_type": "EXECUTE", + "schema_name": "tenant" + }, + { + "catalog_kind": "materialized_view", + "grantee": "app_dashboard", + "grantor": "onex_api", + "is_grantable": false, + "object_name": "plan_tier_snapshot", + "object_type": "TABLE", + "privilege_type": "DELETE", + "schema_name": "platform_catalog" + }, + { + "catalog_kind": "materialized_view", + "grantee": "app_dashboard", + "grantor": "onex_api", + "is_grantable": false, + "object_name": "plan_tier_snapshot", + "object_type": "TABLE", + "privilege_type": "INSERT", + "schema_name": "platform_catalog" + }, + { + "catalog_kind": "materialized_view", + "grantee": "app_dashboard", + "grantor": "onex_api", + "is_grantable": false, + "object_name": "plan_tier_snapshot", + "object_type": "TABLE", + "privilege_type": "REFERENCES", + "schema_name": "platform_catalog" + }, + { + "catalog_kind": "materialized_view", + "grantee": "app_dashboard", + "grantor": "onex_api", + "is_grantable": false, + "object_name": "plan_tier_snapshot", + "object_type": "TABLE", + "privilege_type": "SELECT", + "schema_name": "platform_catalog" + }, + { + "catalog_kind": "materialized_view", + "grantee": "app_dashboard", + "grantor": "onex_api", + "is_grantable": false, + "object_name": "plan_tier_snapshot", + "object_type": "TABLE", + "privilege_type": "TRIGGER", + "schema_name": "platform_catalog" + }, + { + "catalog_kind": "materialized_view", + "grantee": "app_dashboard", + "grantor": "onex_api", + "is_grantable": false, + "object_name": "plan_tier_snapshot", + "object_type": "TABLE", + "privilege_type": "TRUNCATE", + "schema_name": "platform_catalog" + }, + { + "catalog_kind": "materialized_view", + "grantee": "app_dashboard", + "grantor": "onex_api", + "is_grantable": false, + "object_name": "plan_tier_snapshot", + "object_type": "TABLE", + "privilege_type": "UPDATE", + "schema_name": "platform_catalog" + }, + { + "catalog_kind": "procedure", + "function_signature": "(IN p_payload text)", + "grantee": "PUBLIC", + "grantor": "app_dashboard", + "is_grantable": false, + "object_name": "record_delegation", + "object_type": "PROCEDURE", + "privilege_type": "EXECUTE", + "schema_name": "tenant" + }, + { + "catalog_kind": "table", + "grantee": "app_dashboard", + "grantor": "onex_api", + "is_grantable": false, + "object_name": "partitioned_events", + "object_type": "TABLE", + "privilege_type": "DELETE", + "schema_name": "tenant" + }, + { + "catalog_kind": "table", + "grantee": "app_dashboard", + "grantor": "onex_api", + "is_grantable": false, + "object_name": "partitioned_events", + "object_type": "TABLE", + "privilege_type": "INSERT", + "schema_name": "tenant" + }, + { + "catalog_kind": "table", + "grantee": "app_dashboard", + "grantor": "onex_api", + "is_grantable": false, + "object_name": "partitioned_events", + "object_type": "TABLE", + "privilege_type": "REFERENCES", + "schema_name": "tenant" + }, + { + "catalog_kind": "table", + "grantee": "app_dashboard", + "grantor": "onex_api", + "is_grantable": false, + "object_name": "partitioned_events", + "object_type": "TABLE", + "privilege_type": "SELECT", + "schema_name": "tenant" + }, + { + "catalog_kind": "table", + "grantee": "app_dashboard", + "grantor": "onex_api", + "is_grantable": false, + "object_name": "partitioned_events", + "object_type": "TABLE", + "privilege_type": "TRIGGER", + "schema_name": "tenant" + }, + { + "catalog_kind": "table", + "grantee": "app_dashboard", + "grantor": "onex_api", + "is_grantable": false, + "object_name": "partitioned_events", + "object_type": "TABLE", + "privilege_type": "TRUNCATE", + "schema_name": "tenant" + }, + { + "catalog_kind": "table", + "grantee": "app_dashboard", + "grantor": "onex_api", + "is_grantable": false, + "object_name": "partitioned_events", + "object_type": "TABLE", + "privilege_type": "UPDATE", + "schema_name": "tenant" + }, + { + "catalog_kind": "table", + "grantee": "app_dashboard", + "grantor": "onex_api", + "is_grantable": false, + "object_name": "plan_tiers", + "object_type": "TABLE", + "privilege_type": "DELETE", + "schema_name": "platform_catalog" + }, + { + "catalog_kind": "table", + "grantee": "app_dashboard", + "grantor": "onex_api", + "is_grantable": false, + "object_name": "plan_tiers", + "object_type": "TABLE", + "privilege_type": "INSERT", + "schema_name": "platform_catalog" + }, + { + "catalog_kind": "table", + "grantee": "app_dashboard", + "grantor": "onex_api", + "is_grantable": false, + "object_name": "plan_tiers", + "object_type": "TABLE", + "privilege_type": "REFERENCES", + "schema_name": "platform_catalog" + }, + { + "catalog_kind": "table", + "grantee": "app_dashboard", + "grantor": "onex_api", + "is_grantable": false, + "object_name": "plan_tiers", + "object_type": "TABLE", + "privilege_type": "SELECT", + "schema_name": "platform_catalog" + }, + { + "catalog_kind": "table", + "grantee": "app_dashboard", + "grantor": "onex_api", + "is_grantable": false, + "object_name": "plan_tiers", + "object_type": "TABLE", + "privilege_type": "TRIGGER", + "schema_name": "platform_catalog" + }, + { + "catalog_kind": "table", + "grantee": "app_dashboard", + "grantor": "onex_api", + "is_grantable": false, + "object_name": "plan_tiers", + "object_type": "TABLE", + "privilege_type": "TRUNCATE", + "schema_name": "platform_catalog" + }, + { + "catalog_kind": "table", + "grantee": "app_dashboard", + "grantor": "onex_api", + "is_grantable": false, + "object_name": "plan_tiers", + "object_type": "TABLE", + "privilege_type": "UPDATE", + "schema_name": "platform_catalog" + }, + { + "catalog_kind": "table", + "grantee": "app_dashboard", + "grantor": "onex_api", + "is_grantable": false, + "object_name": "tenant_accounts", + "object_type": "TABLE", + "privilege_type": "DELETE", + "schema_name": "tenant" + }, + { + "catalog_kind": "table", + "grantee": "app_dashboard", + "grantor": "onex_api", + "is_grantable": false, + "object_name": "tenant_accounts", + "object_type": "TABLE", + "privilege_type": "INSERT", + "schema_name": "tenant" + }, + { + "catalog_kind": "table", + "grantee": "app_dashboard", + "grantor": "onex_api", + "is_grantable": false, + "object_name": "tenant_accounts", + "object_type": "TABLE", + "privilege_type": "REFERENCES", + "schema_name": "tenant" + }, + { + "catalog_kind": "table", + "grantee": "app_dashboard", + "grantor": "onex_api", + "is_grantable": false, + "object_name": "tenant_accounts", + "object_type": "TABLE", + "privilege_type": "TRIGGER", + "schema_name": "tenant" + }, + { + "catalog_kind": "table", + "grantee": "app_dashboard", + "grantor": "onex_api", + "is_grantable": false, + "object_name": "tenant_accounts", + "object_type": "TABLE", + "privilege_type": "TRUNCATE", + "schema_name": "tenant" + }, + { + "catalog_kind": "table", + "grantee": "app_dashboard", + "grantor": "onex_api", + "is_grantable": false, + "object_name": "tenant_accounts", + "object_type": "TABLE", + "privilege_type": "UPDATE", + "schema_name": "tenant" + }, + { + "catalog_kind": "table", + "grantee": "app_dashboard", + "grantor": "onex_api", + "is_grantable": true, + "object_name": "tenant_accounts", + "object_type": "TABLE", + "privilege_type": "SELECT", + "schema_name": "tenant" + }, + { + "catalog_kind": "table", + "grantee": "app_dashboard", + "grantor": "tenant_projection_writer", + "is_grantable": false, + "object_name": "runtime_state", + "object_type": "TABLE", + "privilege_type": "DELETE", + "schema_name": "omninode_internal" + }, + { + "catalog_kind": "table", + "grantee": "app_dashboard", + "grantor": "tenant_projection_writer", + "is_grantable": false, + "object_name": "runtime_state", + "object_type": "TABLE", + "privilege_type": "INSERT", + "schema_name": "omninode_internal" + }, + { + "catalog_kind": "table", + "grantee": "app_dashboard", + "grantor": "tenant_projection_writer", + "is_grantable": false, + "object_name": "runtime_state", + "object_type": "TABLE", + "privilege_type": "REFERENCES", + "schema_name": "omninode_internal" + }, + { + "catalog_kind": "table", + "grantee": "app_dashboard", + "grantor": "tenant_projection_writer", + "is_grantable": false, + "object_name": "runtime_state", + "object_type": "TABLE", + "privilege_type": "SELECT", + "schema_name": "omninode_internal" + }, + { + "catalog_kind": "table", + "grantee": "app_dashboard", + "grantor": "tenant_projection_writer", + "is_grantable": false, + "object_name": "runtime_state", + "object_type": "TABLE", + "privilege_type": "TRIGGER", + "schema_name": "omninode_internal" + }, + { + "catalog_kind": "table", + "grantee": "app_dashboard", + "grantor": "tenant_projection_writer", + "is_grantable": false, + "object_name": "runtime_state", + "object_type": "TABLE", + "privilege_type": "TRUNCATE", + "schema_name": "omninode_internal" + }, + { + "catalog_kind": "table", + "grantee": "app_dashboard", + "grantor": "tenant_projection_writer", + "is_grantable": false, + "object_name": "runtime_state", + "object_type": "TABLE", + "privilege_type": "UPDATE", + "schema_name": "omninode_internal" + }, + { + "catalog_kind": "table", + "grantee": "rls_admin", + "grantor": "onex_api", + "is_grantable": true, + "object_name": "partitioned_events", + "object_type": "TABLE", + "privilege_type": "SELECT", + "schema_name": "tenant" + }, + { + "catalog_kind": "table", + "grantee": "rls_admin", + "grantor": "onex_api", + "is_grantable": true, + "object_name": "tenant_accounts", + "object_type": "TABLE", + "privilege_type": "SELECT", + "schema_name": "tenant" + }, + { + "catalog_kind": "table", + "grantee": "untrusted_login", + "grantor": "onex_api", + "is_grantable": false, + "object_name": "tenant_accounts", + "object_type": "TABLE", + "privilege_type": "SELECT", + "schema_name": "tenant" + }, + { + "catalog_kind": "table", + "grantee": "untrusted_login", + "grantor": "rls_admin", + "is_grantable": false, + "object_name": "partitioned_events", + "object_type": "TABLE", + "privilege_type": "SELECT", + "schema_name": "tenant" + }, + { + "catalog_kind": "table", + "grantee": "untrusted_login", + "grantor": "rls_admin", + "is_grantable": false, + "object_name": "tenant_accounts", + "object_type": "TABLE", + "privilege_type": "SELECT", + "schema_name": "tenant" + }, + { + "catalog_kind": "type", + "grantee": "PUBLIC", + "grantor": "omninode_runtime", + "is_grantable": false, + "object_name": "runtime_code", + "object_type": "TYPE", + "privilege_type": "USAGE", + "schema_name": "omninode_internal" + }, + { + "catalog_kind": "type", + "grantee": "PUBLIC", + "grantor": "omninode_runtime", + "is_grantable": false, + "object_name": "runtime_status", + "object_type": "TYPE", + "privilege_type": "USAGE", + "schema_name": "omninode_internal" + }, + { + "catalog_kind": "type", + "grantee": "PUBLIC", + "grantor": "onex_api", + "is_grantable": false, + "object_name": "account_id_span", + "object_type": "TYPE", + "privilege_type": "USAGE", + "schema_name": "tenant" + }, + { + "catalog_kind": "type", + "grantee": "PUBLIC", + "grantor": "onex_api", + "is_grantable": false, + "object_name": "account_id_span_set", + "object_type": "TYPE", + "privilege_type": "USAGE", + "schema_name": "tenant" + }, + { + "catalog_kind": "type", + "grantee": "PUBLIC", + "grantor": "onex_api", + "is_grantable": false, + "object_name": "account_ref", + "object_type": "TYPE", + "privilege_type": "USAGE", + "schema_name": "tenant" + } + ], + "object_owners": [ + { + "catalog_kind": "function", + "function_signature": "()", + "object_name": "account_id_span_set", + "object_type": "FUNCTION", + "owner": "onex_api", + "owner_keyword": "FUNCTION", + "schema_name": "tenant" + }, + { + "catalog_kind": "function", + "function_signature": "()", + "object_name": "delegation_event_count", + "object_type": "FUNCTION", + "owner": "app_dashboard", + "owner_keyword": "FUNCTION", + "schema_name": "tenant" + }, + { + "catalog_kind": "function", + "function_signature": "(VARIADIC tenant.account_id_span[])", + "object_name": "account_id_span_set", + "object_type": "FUNCTION", + "owner": "onex_api", + "owner_keyword": "FUNCTION", + "schema_name": "tenant" + }, + { + "catalog_kind": "function", + "function_signature": "(\"arg'name%\" integer)", + "object_name": "hostile_signature", + "object_type": "FUNCTION", + "owner": "app_dashboard", + "owner_keyword": "FUNCTION", + "schema_name": "tenant" + }, + { + "catalog_kind": "function", + "function_signature": "(bigint, bigint)", + "object_name": "account_id_span", + "object_type": "FUNCTION", + "owner": "onex_api", + "owner_keyword": "FUNCTION", + "schema_name": "tenant" + }, + { + "catalog_kind": "function", + "function_signature": "(bigint, bigint, text)", + "object_name": "account_id_span", + "object_type": "FUNCTION", + "owner": "onex_api", + "owner_keyword": "FUNCTION", + "schema_name": "tenant" + }, + { + "catalog_kind": "function", + "function_signature": "(tenant.account_id_span)", + "object_name": "account_id_span_set", + "object_type": "FUNCTION", + "owner": "onex_api", + "owner_keyword": "FUNCTION", + "schema_name": "tenant" + }, + { + "catalog_kind": "materialized_view", + "object_name": "plan_tier_snapshot", + "object_type": "TABLE", + "owner": "onex_api", + "owner_keyword": "MATERIALIZED VIEW", + "schema_name": "platform_catalog" + }, + { + "catalog_kind": "procedure", + "function_signature": "(IN p_payload text)", + "object_name": "record_delegation", + "object_type": "PROCEDURE", + "owner": "app_dashboard", + "owner_keyword": "PROCEDURE", + "schema_name": "tenant" + }, + { + "catalog_kind": "sequence", + "object_name": "delegation_events_id_seq", + "object_type": "SEQUENCE", + "owner": "app_dashboard", + "owner_keyword": "SEQUENCE", + "schema_name": "tenant" + }, + { + "catalog_kind": "table", + "object_name": "delegation_events", + "object_type": "TABLE", + "owner": "app_dashboard", + "owner_keyword": "TABLE", + "schema_name": "tenant" + }, + { + "catalog_kind": "table", + "object_name": "partitioned_events", + "object_type": "TABLE", + "owner": "onex_api", + "owner_keyword": "TABLE", + "schema_name": "tenant" + }, + { + "catalog_kind": "table", + "object_name": "plan_tiers", + "object_type": "TABLE", + "owner": "onex_api", + "owner_keyword": "TABLE", + "schema_name": "platform_catalog" + }, + { + "catalog_kind": "table", + "object_name": "runtime_state", + "object_type": "TABLE", + "owner": "tenant_projection_writer", + "owner_keyword": "TABLE", + "schema_name": "omninode_internal" + }, + { + "catalog_kind": "table", + "object_name": "tenant_accounts", + "object_type": "TABLE", + "owner": "onex_api", + "owner_keyword": "TABLE", + "schema_name": "tenant" + }, + { + "catalog_kind": "type", + "object_name": "account_id_span", + "object_type": "TYPE", + "owner": "onex_api", + "owner_keyword": "TYPE", + "schema_name": "tenant" + }, + { + "catalog_kind": "type", + "object_name": "account_id_span_set", + "object_type": "TYPE", + "owner": "onex_api", + "owner_keyword": "TYPE", + "schema_name": "tenant" + }, + { + "catalog_kind": "type", + "object_name": "account_ref", + "object_type": "TYPE", + "owner": "onex_api", + "owner_keyword": "TYPE", + "schema_name": "tenant" + }, + { + "catalog_kind": "type", + "object_name": "runtime_code", + "object_type": "TYPE", + "owner": "omninode_runtime", + "owner_keyword": "TYPE", + "schema_name": "omninode_internal" + }, + { + "catalog_kind": "type", + "object_name": "runtime_status", + "object_type": "TYPE", + "owner": "omninode_runtime", + "owner_keyword": "TYPE", + "schema_name": "omninode_internal" + }, + { + "catalog_kind": "view", + "object_name": "tenant_account_names", + "object_type": "TABLE", + "owner": "app_dashboard", + "owner_keyword": "VIEW", + "schema_name": "tenant" + } + ], + "provenance": { + "authorization_scope": "synthetic_proof", + "dump_derived": false, + "live_database_read": false, + "postgres_major": 16, + "source": "sanitized_postgresql_16_fixture" + }, + "roles": [ + { + "rolbypassrls": false, + "rolcanlogin": false, + "rolcreatedb": false, + "rolcreaterole": false, + "rolinherit": true, + "rolname": "db_migrator", + "rolreplication": false, + "rolsuper": false + }, + { + "rolbypassrls": false, + "rolcanlogin": false, + "rolcreatedb": false, + "rolcreaterole": false, + "rolinherit": true, + "rolname": "owner_omninode_internal", + "rolreplication": false, + "rolsuper": false + }, + { + "rolbypassrls": false, + "rolcanlogin": false, + "rolcreatedb": false, + "rolcreaterole": false, + "rolinherit": true, + "rolname": "owner_onex_tenant", + "rolreplication": false, + "rolsuper": false + }, + { + "rolbypassrls": false, + "rolcanlogin": false, + "rolcreatedb": false, + "rolcreaterole": false, + "rolinherit": true, + "rolname": "owner_platform_catalog", + "rolreplication": false, + "rolsuper": false + }, + { + "rolbypassrls": false, + "rolcanlogin": true, + "rolcreatedb": false, + "rolcreaterole": false, + "rolinherit": false, + "rolname": "keycloak_service", + "rolreplication": false, + "rolsuper": false + }, + { + "rolbypassrls": false, + "rolcanlogin": true, + "rolcreatedb": false, + "rolcreaterole": false, + "rolinherit": false, + "rolname": "omnibase_infra_service", + "rolreplication": false, + "rolsuper": false + }, + { + "rolbypassrls": false, + "rolcanlogin": true, + "rolcreatedb": false, + "rolcreaterole": false, + "rolinherit": false, + "rolname": "omniclaude_service", + "rolreplication": false, + "rolsuper": false + }, + { + "rolbypassrls": false, + "rolcanlogin": true, + "rolcreatedb": false, + "rolcreaterole": false, + "rolinherit": false, + "rolname": "omniintelligence_service", + "rolreplication": false, + "rolsuper": false + }, + { + "rolbypassrls": false, + "rolcanlogin": true, + "rolcreatedb": false, + "rolcreaterole": false, + "rolinherit": false, + "rolname": "omnimemory_service", + "rolreplication": false, + "rolsuper": false + }, + { + "rolbypassrls": false, + "rolcanlogin": true, + "rolcreatedb": false, + "rolcreaterole": false, + "rolinherit": false, + "rolname": "omninode_cloud_service", + "rolreplication": false, + "rolsuper": false + }, + { + "rolbypassrls": false, + "rolcanlogin": true, + "rolcreatedb": false, + "rolcreaterole": false, + "rolinherit": false, + "rolname": "umami_service", + "rolreplication": false, + "rolsuper": false + }, + { + "rolbypassrls": false, + "rolcanlogin": true, + "rolcreatedb": false, + "rolcreaterole": false, + "rolinherit": true, + "rolname": "omninode_runtime", + "rolreplication": true, + "rolsuper": false + }, + { + "rolbypassrls": false, + "rolcanlogin": true, + "rolcreatedb": false, + "rolcreaterole": false, + "rolinherit": true, + "rolname": "untrusted_login", + "rolreplication": false, + "rolsuper": false + }, + { + "rolbypassrls": false, + "rolcanlogin": true, + "rolcreatedb": false, + "rolcreaterole": true, + "rolinherit": true, + "rolname": "app_dashboard", + "rolreplication": false, + "rolsuper": false + }, + { + "rolbypassrls": false, + "rolcanlogin": true, + "rolcreatedb": true, + "rolcreaterole": false, + "rolinherit": true, + "rolname": "onex_api", + "rolreplication": false, + "rolsuper": false + }, + { + "rolbypassrls": true, + "rolcanlogin": false, + "rolcreatedb": false, + "rolcreaterole": false, + "rolinherit": true, + "rolname": "external_connect_parent", + "rolreplication": false, + "rolsuper": false + }, + { + "rolbypassrls": true, + "rolcanlogin": false, + "rolcreatedb": false, + "rolcreaterole": false, + "rolinherit": true, + "rolname": "rls_admin", + "rolreplication": false, + "rolsuper": false + }, + { + "rolbypassrls": true, + "rolcanlogin": true, + "rolcreatedb": false, + "rolcreaterole": false, + "rolinherit": true, + "rolname": "tenant_projection_writer", + "rolreplication": false, + "rolsuper": false + } + ], + "schema_acl": [ + { + "grantee": "PUBLIC", + "grantor": "app_dashboard", + "is_grantable": false, + "privilege_type": "CREATE", + "schema_name": "tenant" + }, + { + "grantee": "PUBLIC", + "grantor": "app_dashboard", + "is_grantable": false, + "privilege_type": "USAGE", + "schema_name": "tenant" + }, + { + "grantee": "PUBLIC", + "grantor": "onex_api", + "is_grantable": false, + "privilege_type": "CREATE", + "schema_name": "platform_catalog" + }, + { + "grantee": "PUBLIC", + "grantor": "onex_api", + "is_grantable": false, + "privilege_type": "USAGE", + "schema_name": "platform_catalog" + }, + { + "grantee": "PUBLIC", + "grantor": "pg_database_owner", + "is_grantable": false, + "privilege_type": "USAGE", + "schema_name": "public" + }, + { + "grantee": "PUBLIC", + "grantor": "tenant_projection_writer", + "is_grantable": false, + "privilege_type": "CREATE", + "schema_name": "omninode_internal" + }, + { + "grantee": "PUBLIC", + "grantor": "tenant_projection_writer", + "is_grantable": false, + "privilege_type": "USAGE", + "schema_name": "omninode_internal" + }, + { + "grantee": "app_dashboard", + "grantor": "tenant_projection_writer", + "is_grantable": false, + "privilege_type": "USAGE", + "schema_name": "omninode_internal" + }, + { + "grantee": "untrusted_login", + "grantor": "app_dashboard", + "is_grantable": false, + "privilege_type": "USAGE", + "schema_name": "tenant" + } + ], + "schema_owners": [ + { + "owner": "app_dashboard", + "schema_name": "tenant" + }, + { + "owner": "onex_api", + "schema_name": "platform_catalog" + }, + { + "owner": "pg_database_owner", + "schema_name": "public" + }, + { + "owner": "tenant_projection_writer", + "schema_name": "omninode_internal" + } + ], + "schema_version": "3.0" +} diff --git a/docker/application-acl-proof/seed.sql b/docker/application-acl-proof/seed.sql new file mode 100644 index 0000000000..e698fb8e27 --- /dev/null +++ b/docker/application-acl-proof/seed.sql @@ -0,0 +1,187 @@ +-- SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +-- SPDX-License-Identifier: MIT +-- Synthetic unsafe ACL baseline. No dump, live identifier, or credential occurs here. + +\set ON_ERROR_STOP on + +CREATE ROLE owner_onex_tenant NOLOGIN NOSUPERUSER NOBYPASSRLS NOCREATEDB NOCREATEROLE NOREPLICATION; +CREATE ROLE owner_omninode_internal NOLOGIN NOSUPERUSER NOBYPASSRLS NOCREATEDB NOCREATEROLE NOREPLICATION; +CREATE ROLE owner_platform_catalog NOLOGIN NOSUPERUSER NOBYPASSRLS NOCREATEDB NOCREATEROLE NOREPLICATION; +CREATE ROLE onex_api LOGIN PASSWORD 'acl-proof-only' CREATEDB NOSUPERUSER NOBYPASSRLS NOCREATEROLE NOREPLICATION; -- pragma: allowlist secret +CREATE ROLE tenant_projection_writer LOGIN PASSWORD 'acl-proof-only' NOSUPERUSER BYPASSRLS NOCREATEDB NOCREATEROLE NOREPLICATION; -- pragma: allowlist secret +CREATE ROLE app_dashboard LOGIN PASSWORD 'acl-proof-only' NOSUPERUSER NOBYPASSRLS NOCREATEDB CREATEROLE NOREPLICATION; -- pragma: allowlist secret +CREATE ROLE omninode_runtime LOGIN PASSWORD 'acl-proof-only' NOSUPERUSER NOBYPASSRLS NOCREATEDB NOCREATEROLE REPLICATION; -- pragma: allowlist secret +CREATE ROLE untrusted_login LOGIN PASSWORD 'acl-proof-only' NOSUPERUSER NOBYPASSRLS NOCREATEDB NOCREATEROLE NOREPLICATION; -- pragma: allowlist secret +CREATE ROLE db_migrator NOLOGIN NOSUPERUSER NOBYPASSRLS NOCREATEDB NOCREATEROLE NOREPLICATION; +CREATE ROLE probe_migrator NOLOGIN NOSUPERUSER NOBYPASSRLS NOCREATEDB NOCREATEROLE NOREPLICATION NOINHERIT; +CREATE ROLE legacy_probe_login LOGIN PASSWORD 'acl-proof-only' NOSUPERUSER NOBYPASSRLS NOCREATEDB NOCREATEROLE NOREPLICATION NOINHERIT; -- pragma: allowlist secret +CREATE ROLE rls_admin NOLOGIN NOSUPERUSER BYPASSRLS NOCREATEDB NOCREATEROLE NOREPLICATION; +CREATE ROLE external_connect_parent NOLOGIN NOSUPERUSER BYPASSRLS NOCREATEDB NOCREATEROLE NOREPLICATION; +CREATE ROLE keycloak_service LOGIN PASSWORD 'acl-proof-only' NOSUPERUSER NOBYPASSRLS NOCREATEDB NOCREATEROLE NOREPLICATION NOINHERIT; -- pragma: allowlist secret +CREATE ROLE omnibase_infra_service LOGIN PASSWORD 'acl-proof-only' NOSUPERUSER NOBYPASSRLS NOCREATEDB NOCREATEROLE NOREPLICATION NOINHERIT; -- pragma: allowlist secret +CREATE ROLE omninode_cloud_service LOGIN PASSWORD 'acl-proof-only' NOSUPERUSER NOBYPASSRLS NOCREATEDB NOCREATEROLE NOREPLICATION NOINHERIT; -- pragma: allowlist secret +CREATE ROLE omniclaude_service LOGIN PASSWORD 'acl-proof-only' NOSUPERUSER NOBYPASSRLS NOCREATEDB NOCREATEROLE NOREPLICATION NOINHERIT; -- pragma: allowlist secret +CREATE ROLE omniintelligence_service LOGIN PASSWORD 'acl-proof-only' NOSUPERUSER NOBYPASSRLS NOCREATEDB NOCREATEROLE NOREPLICATION NOINHERIT; -- pragma: allowlist secret +CREATE ROLE omnimemory_service LOGIN PASSWORD 'acl-proof-only' NOSUPERUSER NOBYPASSRLS NOCREATEDB NOCREATEROLE NOREPLICATION NOINHERIT; -- pragma: allowlist secret +CREATE ROLE umami_service LOGIN PASSWORD 'acl-proof-only' NOSUPERUSER NOBYPASSRLS NOCREATEDB NOCREATEROLE NOREPLICATION NOINHERIT; -- pragma: allowlist secret +CREATE ROLE shadow_login LOGIN PASSWORD 'acl-proof-only' NOSUPERUSER NOBYPASSRLS NOCREATEDB NOCREATEROLE NOREPLICATION; -- pragma: allowlist secret + +CREATE DATABASE keycloak; +CREATE DATABASE omnibase_infra; +CREATE DATABASE omninode_cloud; +CREATE DATABASE omniclaude; +CREATE DATABASE omniintelligence; +CREATE DATABASE omnimemory; +CREATE DATABASE umami; +CREATE DATABASE acl_scaffold_probe; + +GRANT CREATE ON DATABASE keycloak TO app_dashboard; +GRANT CREATE, TEMPORARY ON DATABASE omnibase_infra TO onex_api; +GRANT CONNECT ON DATABASE keycloak TO external_connect_parent; +GRANT external_connect_parent TO rls_admin WITH ADMIN OPTION; +SET ROLE rls_admin; +GRANT external_connect_parent TO keycloak_service; +RESET ROLE; +GRANT keycloak_service TO shadow_login; +GRANT CONNECT, CREATE ON DATABASE omnibase_infra TO rls_admin WITH GRANT OPTION; +SET ROLE rls_admin; +GRANT CONNECT ON DATABASE omnibase_infra TO keycloak_service; +RESET ROLE; + +ALTER DATABASE omnidash_analytics OWNER TO app_dashboard; + +GRANT owner_onex_tenant TO tenant_projection_writer; +GRANT owner_omninode_internal TO omninode_runtime; +GRANT rls_admin TO app_dashboard WITH ADMIN TRUE, INHERIT TRUE, SET TRUE; +GRANT rls_admin TO owner_onex_tenant WITH ADMIN FALSE, INHERIT FALSE, SET TRUE; +GRANT owner_onex_tenant TO db_migrator + WITH ADMIN TRUE, INHERIT TRUE, SET FALSE; + +CREATE SCHEMA tenant AUTHORIZATION app_dashboard; +CREATE SCHEMA omninode_internal AUTHORIZATION tenant_projection_writer; +CREATE SCHEMA platform_catalog AUTHORIZATION onex_api; +CREATE SCHEMA legacy_acl_sentinel AUTHORIZATION owner_onex_tenant; + +CREATE TABLE tenant.tenant_accounts ( + account_id BIGINT PRIMARY KEY, + display_name TEXT NOT NULL +); +CREATE SEQUENCE tenant.delegation_events_id_seq; +CREATE TABLE tenant.delegation_events ( + id BIGINT PRIMARY KEY DEFAULT nextval('tenant.delegation_events_id_seq'), + payload TEXT NOT NULL +); +CREATE TABLE tenant.partitioned_events ( + event_id BIGINT NOT NULL, + occurred_at DATE NOT NULL +) PARTITION BY RANGE (occurred_at); +ALTER SEQUENCE tenant.delegation_events_id_seq OWNED BY tenant.delegation_events.id; +CREATE FUNCTION tenant.delegation_event_count() +RETURNS BIGINT +LANGUAGE sql +AS $$SELECT count(*) FROM tenant.delegation_events$$; +CREATE FUNCTION tenant.hostile_signature(IN "arg'name%" INTEGER) +RETURNS INTEGER +LANGUAGE sql +AS $$SELECT "arg'name%"$$; +CREATE PROCEDURE tenant.record_delegation(p_payload TEXT) +LANGUAGE sql +AS $$INSERT INTO tenant.delegation_events (payload) VALUES (p_payload)$$; +CREATE VIEW tenant.tenant_account_names AS +SELECT account_id, display_name FROM tenant.tenant_accounts; +CREATE TYPE tenant.account_ref AS ( + account_id BIGINT, + display_name TEXT +); +CREATE TYPE tenant.account_id_span AS RANGE ( + subtype = BIGINT, + multirange_type_name = tenant.account_id_span_set +); + +CREATE TYPE omninode_internal.runtime_status AS ENUM ('ready', 'blocked'); +CREATE DOMAIN omninode_internal.runtime_code AS TEXT + CHECK (VALUE <> ''); +CREATE TABLE omninode_internal.runtime_state ( + state_id BIGINT PRIMARY KEY, + status omninode_internal.runtime_status NOT NULL +); +CREATE TABLE platform_catalog.plan_tiers ( + code TEXT PRIMARY KEY, + display_name TEXT NOT NULL +); +CREATE MATERIALIZED VIEW platform_catalog.plan_tier_snapshot AS +SELECT code, display_name FROM platform_catalog.plan_tiers; + +ALTER TABLE tenant.tenant_accounts OWNER TO onex_api; +ALTER TABLE tenant.delegation_events OWNER TO app_dashboard; +ALTER TABLE tenant.partitioned_events OWNER TO onex_api; +ALTER SEQUENCE tenant.delegation_events_id_seq OWNER TO app_dashboard; +ALTER FUNCTION tenant.delegation_event_count() OWNER TO app_dashboard; +ALTER FUNCTION tenant.hostile_signature(IN "arg'name%" INTEGER) OWNER TO app_dashboard; +ALTER PROCEDURE tenant.record_delegation(TEXT) OWNER TO app_dashboard; +ALTER VIEW tenant.tenant_account_names OWNER TO app_dashboard; +ALTER TYPE tenant.account_ref OWNER TO onex_api; +ALTER TYPE tenant.account_id_span OWNER TO onex_api; +ALTER TYPE tenant.account_id_span_set OWNER TO onex_api; +ALTER FUNCTION tenant.account_id_span(BIGINT, BIGINT) OWNER TO onex_api; +ALTER FUNCTION tenant.account_id_span(BIGINT, BIGINT, TEXT) OWNER TO onex_api; +ALTER FUNCTION tenant.account_id_span_set() OWNER TO onex_api; +ALTER FUNCTION tenant.account_id_span_set(VARIADIC tenant.account_id_span[]) OWNER TO onex_api; +ALTER FUNCTION tenant.account_id_span_set(tenant.account_id_span) OWNER TO onex_api; +ALTER TYPE omninode_internal.runtime_status OWNER TO omninode_runtime; +ALTER DOMAIN omninode_internal.runtime_code OWNER TO omninode_runtime; +ALTER TABLE omninode_internal.runtime_state OWNER TO tenant_projection_writer; +ALTER TABLE platform_catalog.plan_tiers OWNER TO onex_api; +ALTER MATERIALIZED VIEW platform_catalog.plan_tier_snapshot OWNER TO onex_api; + +GRANT ALL PRIVILEGES ON DATABASE omnidash_analytics TO app_dashboard; +GRANT CONNECT, TEMPORARY ON DATABASE omnidash_analytics TO untrusted_login; +GRANT CREATE, USAGE ON SCHEMA tenant, omninode_internal, platform_catalog TO PUBLIC; +GRANT USAGE ON SCHEMA tenant TO untrusted_login; +GRANT USAGE ON SCHEMA omninode_internal TO app_dashboard; +GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA tenant, omninode_internal, platform_catalog TO app_dashboard; +GRANT SELECT ON tenant.tenant_accounts TO untrusted_login; +GRANT SELECT (display_name) ON tenant.tenant_accounts TO untrusted_login WITH GRANT OPTION; +GRANT UPDATE (display_name) ON tenant.tenant_accounts TO rls_admin WITH GRANT OPTION; +SET ROLE rls_admin; +GRANT UPDATE (display_name) ON tenant.tenant_accounts TO untrusted_login; +RESET ROLE; +GRANT SELECT ON tenant.tenant_accounts TO app_dashboard WITH GRANT OPTION; +GRANT SELECT ON tenant.tenant_accounts TO rls_admin WITH GRANT OPTION; +SET ROLE rls_admin; +GRANT SELECT ON tenant.tenant_accounts TO untrusted_login; +RESET ROLE; +GRANT SELECT ON tenant.partitioned_events TO rls_admin WITH GRANT OPTION; +SET ROLE rls_admin; +GRANT SELECT ON tenant.partitioned_events TO untrusted_login; +RESET ROLE; +GRANT TRIGGER ON tenant.tenant_accounts TO onex_api; +GRANT USAGE ON SCHEMA omninode_internal TO tenant_projection_writer; +GRANT SELECT ON omninode_internal.runtime_state TO tenant_projection_writer; +GRANT EXECUTE ON FUNCTION tenant.delegation_event_count() TO PUBLIC; +GRANT USAGE ON TYPE omninode_internal.runtime_status TO PUBLIC; + +ALTER DEFAULT PRIVILEGES FOR ROLE owner_onex_tenant IN SCHEMA tenant + GRANT SELECT ON TABLES TO app_dashboard WITH GRANT OPTION; +ALTER DEFAULT PRIVILEGES FOR ROLE owner_onex_tenant IN SCHEMA tenant + GRANT EXECUTE ON FUNCTIONS TO PUBLIC; +ALTER DEFAULT PRIVILEGES FOR ROLE owner_onex_tenant + GRANT SELECT ON TABLES TO app_dashboard; +ALTER DEFAULT PRIVILEGES FOR ROLE owner_onex_tenant + GRANT SELECT ON TABLES TO untrusted_login; +ALTER DEFAULT PRIVILEGES FOR ROLE owner_onex_tenant IN SCHEMA tenant + GRANT SELECT ON TABLES TO keycloak_service WITH GRANT OPTION; +ALTER DEFAULT PRIVILEGES FOR ROLE owner_onex_tenant IN SCHEMA legacy_acl_sentinel + GRANT SELECT ON TABLES TO untrusted_login; + +INSERT INTO tenant.tenant_accounts VALUES (1, 'Synthetic'); +INSERT INTO tenant.delegation_events (payload) VALUES ('before-matrix'); +INSERT INTO omninode_internal.runtime_state VALUES (1, 'ready'); +INSERT INTO platform_catalog.plan_tiers VALUES ('beta', 'Beta'); +REFRESH MATERIALIZED VIEW platform_catalog.plan_tier_snapshot; + +\connect acl_scaffold_probe +CREATE TABLE public.legacy_scaffold_data(id integer PRIMARY KEY); +INSERT INTO public.legacy_scaffold_data VALUES (1); +GRANT SELECT, INSERT ON public.legacy_scaffold_data TO legacy_probe_login; +\connect omnidash_analytics diff --git a/docker/application-acl-proof/source-lock.yaml b/docker/application-acl-proof/source-lock.yaml new file mode 100644 index 0000000000..8ed72bfacd --- /dev/null +++ b/docker/application-acl-proof/source-lock.yaml @@ -0,0 +1,55 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT +schema_version: "1.0" +required_connect_databases: + - keycloak + - omnibase_infra + - omnidash_analytics + - omninode_cloud + - omniclaude + - omniintelligence + - omnimemory + - umami +sources: + - source_key: topology_owner + repository: OmniNode-ai/omnibase_infra + revision: d7f1ac464a54696ac9ed05fd8f3766463a0a7eea + path: src/omnibase_infra/topology/instances/local.yaml + sha256: e4170e97e26fb9c63a53f5f660cedacd15bf7e99609309c54bff15c3d026ac8d + purpose: topology + - source_key: typed_ownership_loader + repository: OmniNode-ai/omnibase_infra + revision: 9e9e62c3177f568b7e5110f653ee4be6dcda965c + path: src/omnibase_infra/validation/application_relation_ownership.py + sha256: be712ed5d6372dc9bc0720742291b2739f7b815c61abbab3d87157dfb80216c4 + purpose: typed_loader + - source_key: kubernetes_topology_projection + repository: OmniNode-ai/omninode_infra + revision: 1a1fff92cbf8e02e488ac6e6e89b1087ca396657 + path: topology/kubernetes/source-lock.yaml + sha256: aa6b4502f79244160f07769da788f1826f2b9d5e756b477508eddf5af929226f + purpose: rendered_topology + - source_key: omnimarket_relation_inventory + repository: OmniNode-ai/omnimarket + revision: a0f65e9471da06b88eecb91bbc1c847989cb10d8 + path: docs/evidence/OMN-15423-relation-inventory.json + sha256: c7ff16080dc553ae204da405519f51b5b631847b129f5876db136c048a4c63da + purpose: relation_inventory + - source_key: onex_api_service_ownership + repository: OmniNode-ai/omninode_infra + revision: 39033d55147ef22a061b665345b506246d3aa543 + path: db/migrations/application-relation-ownership.yaml + sha256: 4a47bb42a8e724ffc44453cb649b754568f3ffa83dabaf831ccfaebaa0723712 + purpose: service_ownership + - source_key: node_migration_service_ownership + repository: OmniNode-ai/omninode_infra + revision: 39033d55147ef22a061b665345b506246d3aa543 + path: k8s/migrations/application-relation-ownership.yaml + sha256: 8ca701c4804d2f7d749dc1ef2a26fc383dcd3806bc42c004ed8851a5ff5d25e0 + purpose: service_ownership + - source_key: sanitized_legacy_fixture + repository: OmniNode-ai/omnibase_infra + revision: 18df1728bdbcc7a773c790f64b6569f58b524841 + path: docker/legacy-rds-fixture/fixture-manifest.json + sha256: 1cdc1db7d707bc2daa72ad8f1521bb589cf87594e5b48f6480893b08875e3f26 + purpose: legacy_fixture diff --git a/scripts/ci/prove_application_database_acl.py b/scripts/ci/prove_application_database_acl.py new file mode 100644 index 0000000000..a9c086ea39 --- /dev/null +++ b/scripts/ci/prove_application_database_acl.py @@ -0,0 +1,2378 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT + +"""Rebuilt PostgreSQL 16 ACL/default-privilege and rollback proof.""" + +from __future__ import annotations + +import json +import os +import subprocess +from collections import Counter, defaultdict +from collections.abc import Callable, Iterable, Mapping, Sequence +from pathlib import Path +from typing import TypedDict, cast + +import psycopg2 +import psycopg2.extras +import yaml +from psycopg2 import sql + +from omnibase_core.enums.enum_database_grant_object_type import ( + EnumDatabaseGrantObjectType, +) +from omnibase_core.enums.enum_database_privilege import EnumDatabasePrivilege +from omnibase_core.enums.enum_database_schema_domain import EnumDatabaseSchemaDomain +from omnibase_core.models.core.model_deployment_topology import ModelDeploymentTopology +from omnibase_infra.validation.application_database_acl import ( + PUBLIC_PRINCIPAL, + build_application_database_acl_matrix, + render_application_database_acl_sql, +) +from omnibase_infra.validation.enums.enum_application_database_acl_authorization_scope import ( + EnumApplicationDatabaseAclAuthorizationScope, +) +from omnibase_infra.validation.enums.enum_application_database_acl_render_phase import ( + EnumApplicationDatabaseAclRenderPhase, +) +from omnibase_infra.validation.models.model_application_database_acl_matrix import ( + ModelApplicationDatabaseAclMatrix, + ModelApplicationDatabaseAclSource, +) +from omnibase_infra.validation.models.model_application_database_acl_policy import ( + ModelApplicationDatabaseAclPolicy, +) +from omnibase_infra.validation.models.model_application_database_acl_row import ( + ModelApplicationDatabaseAclRow, +) +from omnibase_infra.validation.models.model_application_database_default_acl_row import ( + ModelApplicationDatabaseDefaultAclRow, +) +from omnibase_infra.validation.models.model_application_database_observed_role_state import ( + ModelApplicationDatabaseObservedRoleState, +) +from omnibase_infra.validation.models.model_application_database_principal_inventory import ( + ModelApplicationDatabasePrincipalInventory, +) +from omnibase_infra.validation.models.model_application_database_role_membership import ( + ModelApplicationDatabaseRoleMembership, +) +from omnibase_infra.validation.models.model_application_database_role_state import ( + ModelApplicationDatabaseRoleState, +) +from omnibase_infra.validation.models.model_application_relation_evidence_inventory import ( + ModelApplicationRelationEvidenceInventory, +) + +ADMIN_DSN = os.environ["ADMIN_DSN"] +DATABASE = os.environ.get("PROOF_DATABASE", "omnidash_analytics") +DATABASE_HOST = os.environ.get("PROOF_DB_HOST", "postgres") +DATABASE_PORT = int(os.environ.get("PROOF_DB_PORT", "5432")) +ROLE_PASSWORD = "acl-proof-only" # pragma: allowlist secret +MANAGED_SCHEMAS = ("tenant", "omninode_internal", "platform_catalog") +MUTATED_SCHEMAS = (*MANAGED_SCHEMAS, "public") +LEGACY_DEFAULT_SCHEMA = "legacy_acl_sentinel" +OWNERS = ( + "owner_onex_tenant", + "owner_omninode_internal", + "owner_platform_catalog", +) +WORKLOADS = ( + "app_dashboard", + "omninode_runtime", + "onex_api", + "tenant_projection_writer", +) +SERVICE_DATABASE_ROLES = { + "keycloak": "keycloak_service", + "omnibase_infra": "omnibase_infra_service", + "omninode_cloud": "omninode_cloud_service", + "omniclaude": "omniclaude_service", + "omniintelligence": "omniintelligence_service", + "omnimemory": "omnimemory_service", + "umami": "umami_service", +} +EXPECTED_PRECHANGE = Path( + os.environ.get( + "EXPECTED_PRECHANGE", + "/app/proof/prechange-fixture-acl.json", + ) +) +OBSERVED_PRECHANGE = Path( + os.environ.get( + "OBSERVED_PRECHANGE", + "/output/observed-prechange-acl.json", + ) +) +FIXTURES = Path(os.environ.get("ACL_FIXTURES", "/app/proof/fixtures")) + + +class _AclSnapshot(TypedDict): + """Typed shape of the durable synthetic pre-change ACL artifact.""" + + schema_version: str + provenance: dict[str, object] + roles: list[dict[str, object]] + memberships: list[dict[str, object]] + database_owner: list[dict[str, object]] + database_acl: list[dict[str, object]] + schema_owners: list[dict[str, object]] + schema_acl: list[dict[str, object]] + object_owners: list[dict[str, object]] + object_acl: list[dict[str, object]] + column_acl: list[dict[str, object]] + default_acl: list[dict[str, object]] + default_acl_catalog_rows: list[dict[str, object]] + + +def _admin(dsn: str = ADMIN_DSN) -> psycopg2.extensions.connection: + connection = psycopg2.connect(dsn) + connection.autocommit = True + return connection + + +def _dict_rows( + statement: str, + parameters: Sequence[object] = (), + *, + dsn: str = ADMIN_DSN, +) -> list[dict[str, object]]: + connection = _admin(dsn) + try: + with connection.cursor(cursor_factory=psycopg2.extras.RealDictCursor) as cursor: + cursor.execute(statement, parameters) + return [dict(row) for row in cursor.fetchall()] + finally: + connection.close() + + +def _sorted_rows(rows: Iterable[Mapping[str, object]]) -> list[dict[str, object]]: + materialized = [dict(row) for row in rows] + return sorted( + materialized, + key=lambda row: json.dumps(row, sort_keys=True, separators=(",", ":")), + ) + + +def _capture_legacy_default_acl( + *, + dsn: str = ADMIN_DSN, +) -> list[dict[str, object]]: + """Capture the unrelated-schema default ACL sentinel exactly.""" + return _sorted_rows( + _dict_rows( + """ + SELECT owner.rolname AS owner, namespace.nspname AS schema_name, + defaults.defaclobjtype AS object_type, + array_to_string( + ARRAY( + SELECT acl_item::text + FROM unnest(defaults.defaclacl) acl_item + ORDER BY acl_item::text + ), + ',' + ) AS raw_acl + FROM pg_default_acl defaults + JOIN pg_roles owner ON owner.oid = defaults.defaclrole + JOIN pg_namespace namespace ON namespace.oid = defaults.defaclnamespace + WHERE namespace.nspname = %s + """, + (LEGACY_DEFAULT_SCHEMA,), + dsn=dsn, + ) + ) + + +def _postgres_major() -> int: + row = _dict_rows("SHOW server_version_num")[0] + return int(str(row["server_version_num"])) // 10_000 + + +def _matrix_principals(matrix: ModelApplicationDatabaseAclMatrix) -> set[str]: + return { + principal + for principals in ( + *matrix.declared_principals.values(), + *matrix.observed_principals.values(), + *matrix.absent_principals.values(), + *matrix.observed_connect_principals.values(), + *matrix.absent_connect_principals.values(), + *matrix.allowed_connect_principals.values(), + ) + for principal in principals + } + + +def _owner_roles(matrix: ModelApplicationDatabaseAclMatrix) -> set[str]: + return ( + set(matrix.database_owners.values()) + | {obj.owner for obj in matrix.objects} + | {row.owner for row in matrix.default_privileges} + ) + + +def _allowed_connect_roles(matrix: ModelApplicationDatabaseAclMatrix) -> set[str]: + return { + principal + for principals in matrix.allowed_connect_principals.values() + for principal in principals + } + + +def _controlled_roles(matrix: ModelApplicationDatabaseAclMatrix) -> set[str]: + return ( + _owner_roles(matrix) + | _matrix_principals(matrix) + | {membership.role for membership in matrix.allowed_memberships} + | {membership.member for membership in matrix.allowed_memberships} + ) + + +def _membership_member_roles(matrix: ModelApplicationDatabaseAclMatrix) -> set[str]: + """Roles whose parent edges are explicitly reconciled by the renderer.""" + return ( + _matrix_principals(matrix) + .union(_owner_roles(matrix)) + .difference(matrix.retained_administrative_principals) + ) + + +def _protected_parent_roles(matrix: ModelApplicationDatabaseAclMatrix) -> set[str]: + """Roles whose inheritance by any undeclared child breaks the allowlist.""" + return { + state.role for state in matrix.governed_role_states if state.manage_memberships + } + + +def _capture_snapshot( + matrix: ModelApplicationDatabaseAclMatrix, + *, + dsn: str = ADMIN_DSN, +) -> _AclSnapshot: + """Capture every fixture ACL input needed by rollback mechanics.""" + + def query( + statement: str, + parameters: Sequence[object] = (), + ) -> list[dict[str, object]]: + return _dict_rows(statement, parameters, dsn=dsn) + + owner_names = sorted(_owner_roles(matrix)) + controlled_roles = sorted(_controlled_roles(matrix)) + protected_parent_roles = sorted(_protected_parent_roles(matrix)) + membership_member_roles = sorted(_membership_member_roles(matrix)) + managed_schema_names = list(MANAGED_SCHEMAS) + mutated_schema_names = list(MUTATED_SCHEMAS) + roles = query( + """ + SELECT rolname, rolcanlogin, rolsuper, rolinherit, rolcreaterole, + rolcreatedb, rolreplication, rolbypassrls + FROM pg_roles + WHERE rolname = ANY(%s) + """, + (controlled_roles,), + ) + memberships = query( + """ + SELECT parent.rolname AS parent_role, member.rolname AS member_role, + grantor.rolname AS grantor, + membership.admin_option, membership.inherit_option, + membership.set_option + FROM pg_auth_members membership + JOIN pg_roles parent ON parent.oid = membership.roleid + JOIN pg_roles member ON member.oid = membership.member + JOIN pg_roles grantor ON grantor.oid = membership.grantor + WHERE member.rolname = ANY(%s) + OR parent.rolname = ANY(%s) + """, + (membership_member_roles, protected_parent_roles), + ) + database_owner = query( + """ + SELECT database.datname AS database_name, owner.rolname AS owner + FROM pg_database database + JOIN pg_roles owner ON owner.oid = database.datdba + WHERE database.datname = ANY(%s) + """, + (list(matrix.required_connect_databases),), + ) + database_acl = query( + """ + SELECT database.datname AS database_name, + COALESCE(grantee.rolname, 'PUBLIC') AS grantee, + grantor.rolname AS grantor, acl.privilege_type, + acl.is_grantable + FROM pg_database database + CROSS JOIN LATERAL aclexplode( + COALESCE(database.datacl, acldefault('d', database.datdba)) + ) acl + LEFT JOIN pg_roles grantee ON grantee.oid = acl.grantee + JOIN pg_roles grantor ON grantor.oid = acl.grantor + WHERE database.datname = ANY(%s) + AND acl.grantee <> database.datdba + """, + (list(matrix.required_connect_databases),), + ) + schema_owners = query( + """ + SELECT namespace.nspname AS schema_name, owner.rolname AS owner + FROM pg_namespace namespace + JOIN pg_roles owner ON owner.oid = namespace.nspowner + WHERE namespace.nspname = ANY(%s) + """, + (mutated_schema_names,), + ) + schema_acl = query( + """ + SELECT namespace.nspname AS schema_name, + COALESCE(grantee.rolname, 'PUBLIC') AS grantee, + grantor.rolname AS grantor, acl.privilege_type, + acl.is_grantable + FROM pg_namespace namespace + CROSS JOIN LATERAL aclexplode( + COALESCE(namespace.nspacl, acldefault('n', namespace.nspowner)) + ) acl + LEFT JOIN pg_roles grantee ON grantee.oid = acl.grantee + JOIN pg_roles grantor ON grantor.oid = acl.grantor + WHERE namespace.nspname = ANY(%s) + AND acl.grantee <> namespace.nspowner + """, + (mutated_schema_names,), + ) + relation_owners = query( + """ + SELECT namespace.nspname AS schema_name, relation.relname AS object_name, + CASE relation.relkind + WHEN 'r' THEN 'table' + WHEN 'p' THEN 'table' + WHEN 'v' THEN 'view' + WHEN 'm' THEN 'materialized_view' + WHEN 'S' THEN 'sequence' + END AS catalog_kind, + CASE relation.relkind + WHEN 'v' THEN 'VIEW' + WHEN 'm' THEN 'MATERIALIZED VIEW' + WHEN 'S' THEN 'SEQUENCE' + ELSE 'TABLE' + END AS owner_keyword, + CASE WHEN relation.relkind = 'S' THEN 'SEQUENCE' ELSE 'TABLE' END + AS object_type, + owner.rolname AS owner + FROM pg_class relation + JOIN pg_namespace namespace ON namespace.oid = relation.relnamespace + JOIN pg_roles owner ON owner.oid = relation.relowner + WHERE namespace.nspname = ANY(%s) + AND relation.relkind IN ('r', 'p', 'v', 'm', 'S') + """, + (managed_schema_names,), + ) + relation_acl = query( + """ + SELECT namespace.nspname AS schema_name, relation.relname AS object_name, + CASE WHEN relation.relkind = 'S' THEN 'SEQUENCE' ELSE 'TABLE' END + AS object_type, + CASE relation.relkind + WHEN 'r' THEN 'table' + WHEN 'p' THEN 'table' + WHEN 'v' THEN 'view' + WHEN 'm' THEN 'materialized_view' + WHEN 'S' THEN 'sequence' + END AS catalog_kind, + COALESCE(grantee.rolname, 'PUBLIC') AS grantee, + grantor.rolname AS grantor, acl.privilege_type, + acl.is_grantable + FROM pg_class relation + JOIN pg_namespace namespace ON namespace.oid = relation.relnamespace + CROSS JOIN LATERAL aclexplode( + COALESCE( + relation.relacl, + acldefault( + (CASE WHEN relation.relkind = 'S' THEN 's' ELSE 'r' END)::"char", + relation.relowner + ) + ) + ) acl + LEFT JOIN pg_roles grantee ON grantee.oid = acl.grantee + JOIN pg_roles grantor ON grantor.oid = acl.grantor + WHERE namespace.nspname = ANY(%s) + AND relation.relkind IN ('r', 'p', 'v', 'm', 'S') + AND acl.grantee <> relation.relowner + """, + (managed_schema_names,), + ) + routine_owners = query( + """ + SELECT namespace.nspname AS schema_name, procedure.proname AS object_name, + '(' || pg_get_function_identity_arguments(procedure.oid) || ')' + AS function_signature, + CASE WHEN procedure.prokind = 'p' THEN 'procedure' ELSE 'function' END + AS catalog_kind, + CASE WHEN procedure.prokind = 'p' THEN 'PROCEDURE' ELSE 'FUNCTION' END + AS owner_keyword, + CASE WHEN procedure.prokind = 'p' THEN 'PROCEDURE' ELSE 'FUNCTION' END + AS object_type, + owner.rolname AS owner + FROM pg_proc procedure + JOIN pg_namespace namespace ON namespace.oid = procedure.pronamespace + JOIN pg_roles owner ON owner.oid = procedure.proowner + WHERE namespace.nspname = ANY(%s) AND procedure.prokind IN ('f', 'p') + """, + (managed_schema_names,), + ) + routine_acl = query( + """ + SELECT namespace.nspname AS schema_name, procedure.proname AS object_name, + '(' || pg_get_function_identity_arguments(procedure.oid) || ')' + AS function_signature, + CASE WHEN procedure.prokind = 'p' THEN 'PROCEDURE' ELSE 'FUNCTION' END + AS object_type, + CASE WHEN procedure.prokind = 'p' THEN 'procedure' ELSE 'function' END + AS catalog_kind, + COALESCE(grantee.rolname, 'PUBLIC') AS grantee, + grantor.rolname AS grantor, acl.privilege_type, + acl.is_grantable + FROM pg_proc procedure + JOIN pg_namespace namespace ON namespace.oid = procedure.pronamespace + CROSS JOIN LATERAL aclexplode( + COALESCE(procedure.proacl, acldefault('f', procedure.proowner)) + ) acl + LEFT JOIN pg_roles grantee ON grantee.oid = acl.grantee + JOIN pg_roles grantor ON grantor.oid = acl.grantor + WHERE namespace.nspname = ANY(%s) AND procedure.prokind IN ('f', 'p') + AND acl.grantee <> procedure.proowner + """, + (managed_schema_names,), + ) + type_owners = query( + """ + SELECT namespace.nspname AS schema_name, type.typname AS object_name, + 'type' AS catalog_kind, 'TYPE' AS owner_keyword, + 'TYPE' AS object_type, + owner.rolname AS owner + FROM pg_type type + JOIN pg_namespace namespace ON namespace.oid = type.typnamespace + JOIN pg_roles owner ON owner.oid = type.typowner + LEFT JOIN pg_class relation ON relation.oid = type.typrelid + WHERE namespace.nspname = ANY(%s) + AND type.typisdefined + AND ( + (type.typtype IN ('b', 'd', 'e', 'r', 'm') AND type.typelem = 0) + OR (type.typtype = 'c' AND relation.relkind = 'c') + ) + """, + (managed_schema_names,), + ) + type_acl = query( + """ + SELECT namespace.nspname AS schema_name, type.typname AS object_name, + 'TYPE' AS object_type, 'type' AS catalog_kind, + COALESCE(grantee.rolname, 'PUBLIC') AS grantee, + grantor.rolname AS grantor, acl.privilege_type, + acl.is_grantable + FROM pg_type type + JOIN pg_namespace namespace ON namespace.oid = type.typnamespace + LEFT JOIN pg_class relation ON relation.oid = type.typrelid + CROSS JOIN LATERAL aclexplode( + COALESCE(type.typacl, acldefault('T', type.typowner)) + ) acl + LEFT JOIN pg_roles grantee ON grantee.oid = acl.grantee + JOIN pg_roles grantor ON grantor.oid = acl.grantor + WHERE namespace.nspname = ANY(%s) + AND type.typisdefined + AND ( + (type.typtype IN ('b', 'd', 'e', 'r', 'm') AND type.typelem = 0) + OR (type.typtype = 'c' AND relation.relkind = 'c') + ) + AND acl.grantee <> type.typowner + """, + (managed_schema_names,), + ) + column_acl = query( + """ + SELECT namespace.nspname AS schema_name, + relation.relname AS object_name, + CASE relation.relkind + WHEN 'r' THEN 'table' + WHEN 'p' THEN 'table' + WHEN 'v' THEN 'view' + WHEN 'm' THEN 'materialized_view' + END AS catalog_kind, + attribute.attname AS column_name, + COALESCE(grantee.rolname, 'PUBLIC') AS grantee, + grantor.rolname AS grantor, acl.privilege_type, + acl.is_grantable + FROM pg_attribute attribute + JOIN pg_class relation ON relation.oid = attribute.attrelid + JOIN pg_namespace namespace ON namespace.oid = relation.relnamespace + CROSS JOIN LATERAL aclexplode(attribute.attacl) acl + LEFT JOIN pg_roles grantee ON grantee.oid = acl.grantee + JOIN pg_roles grantor ON grantor.oid = acl.grantor + WHERE namespace.nspname = ANY(%s) + AND relation.relkind IN ('r', 'p', 'v', 'm') + AND attribute.attnum > 0 + AND NOT attribute.attisdropped + AND attribute.attacl IS NOT NULL + AND acl.grantee <> relation.relowner + """, + (managed_schema_names,), + ) + default_acl = query( + """ + SELECT owner.rolname AS owner, + namespace.nspname AS schema_name, + CASE defaults.defaclobjtype + WHEN 'r' THEN 'TABLE' + WHEN 'S' THEN 'SEQUENCE' + WHEN 'f' THEN 'FUNCTION' + WHEN 'T' THEN 'TYPE' + END AS object_type, + COALESCE(grantee.rolname, 'PUBLIC') AS grantee, + grantor.rolname AS grantor, acl.privilege_type, + acl.is_grantable + FROM pg_default_acl defaults + JOIN pg_roles owner ON owner.oid = defaults.defaclrole + LEFT JOIN pg_namespace namespace ON namespace.oid = defaults.defaclnamespace + CROSS JOIN LATERAL aclexplode(defaults.defaclacl) acl + LEFT JOIN pg_roles grantee ON grantee.oid = acl.grantee + JOIN pg_roles grantor ON grantor.oid = acl.grantor + WHERE owner.rolname = ANY(%s) + AND (defaults.defaclnamespace = 0 OR namespace.nspname = ANY(%s)) + AND acl.grantee <> defaults.defaclrole + """, + (owner_names, managed_schema_names), + ) + default_acl_catalog_rows = query( + """ + SELECT owner.rolname AS owner, + namespace.nspname AS schema_name, + CASE defaults.defaclobjtype + WHEN 'r' THEN 'TABLE' + WHEN 'S' THEN 'SEQUENCE' + WHEN 'f' THEN 'FUNCTION' + WHEN 'T' THEN 'TYPE' + END AS object_type, + array_to_string( + ARRAY( + SELECT acl_item::text + FROM unnest(defaults.defaclacl) acl_item + ORDER BY acl_item::text + ), + ',' + ) AS raw_acl + FROM pg_default_acl defaults + JOIN pg_roles owner ON owner.oid = defaults.defaclrole + LEFT JOIN pg_namespace namespace ON namespace.oid = defaults.defaclnamespace + WHERE owner.rolname = ANY(%s) + AND (defaults.defaclnamespace = 0 OR namespace.nspname = ANY(%s)) + """, + (owner_names, managed_schema_names), + ) + return { + "schema_version": "3.0", + "provenance": { + "source": "sanitized_postgresql_16_fixture", + "live_database_read": False, + "dump_derived": False, + "authorization_scope": "synthetic_proof", + "postgres_major": _postgres_major(), + }, + "roles": _sorted_rows(roles), + "memberships": _sorted_rows(memberships), + "database_owner": _sorted_rows(database_owner), + "database_acl": _sorted_rows(database_acl), + "schema_owners": _sorted_rows(schema_owners), + "schema_acl": _sorted_rows(schema_acl), + "object_owners": _sorted_rows( + [ + *relation_owners, + *routine_owners, + *type_owners, + ] + ), + "object_acl": _sorted_rows([*relation_acl, *routine_acl, *type_acl]), + "column_acl": _sorted_rows(column_acl), + "default_acl": _sorted_rows(default_acl), + "default_acl_catalog_rows": _sorted_rows(default_acl_catalog_rows), + } + + +def _fixture_matrix() -> ModelApplicationDatabaseAclMatrix: + topology = ModelDeploymentTopology.from_yaml(FIXTURES / "topology.yaml") + inventory = ModelApplicationRelationEvidenceInventory.model_validate( + yaml.safe_load((FIXTURES / "inventory.yaml").read_text(encoding="utf-8")) + ) + principal_inventory = ModelApplicationDatabasePrincipalInventory.model_validate( + yaml.safe_load( + (FIXTURES / "principal-inventory-postgres16.yaml").read_text( + encoding="utf-8" + ) + ) + ) + external_principal_inventories = tuple( + ModelApplicationDatabasePrincipalInventory.model_validate(item) + for item in yaml.safe_load( + (FIXTURES / "principal-inventories-external.yaml").read_text( + encoding="utf-8" + ) + ) + ) + acl_policy = ModelApplicationDatabaseAclPolicy.model_validate( + yaml.safe_load( + (FIXTURES / "acl-policy-postgres16.yaml").read_text(encoding="utf-8") + ) + ) + external_inventory_sources = tuple( + ModelApplicationDatabaseAclSource( + source_key=f"synthetic_principal_inventory_{inventory.database_ref}", + repository="synthetic/docker-proof", + revision=f"{index:x}" * 40, + path="proof/fixtures/principal-inventories-external.yaml", + sha256=f"{index:x}" * 64, + purpose="principal_inventory", + ) + for index, inventory in enumerate(external_principal_inventories, start=3) + ) + sources = ( + ModelApplicationDatabaseAclSource( + source_key="synthetic_topology", + repository="synthetic/docker-proof", + revision="a" * 40, + path="proof/fixtures/topology.yaml", + sha256="b" * 64, + purpose="topology", + ), + ModelApplicationDatabaseAclSource( + source_key="synthetic_inventory", + repository="synthetic/docker-proof", + revision="c" * 40, + path="proof/fixtures/inventory.yaml", + sha256="d" * 64, + purpose="relation_inventory", + ), + ModelApplicationDatabaseAclSource( + source_key="synthetic_principal_inventory", + repository="synthetic/docker-proof", + revision="e" * 40, + path="proof/fixtures/principal-inventory-postgres16.yaml", + sha256="f" * 64, + purpose="principal_inventory", + ), + ModelApplicationDatabaseAclSource( + source_key="synthetic_acl_policy", + repository="synthetic/docker-proof", + revision="1" * 40, + path="proof/fixtures/acl-policy-postgres16.yaml", + sha256="2" * 64, + purpose="acl_policy", + ), + *external_inventory_sources, + ) + principal_inventories = { + "synthetic_principal_inventory": principal_inventory, + **{ + f"synthetic_principal_inventory_{inventory.database_ref}": inventory + for inventory in external_principal_inventories + }, + } + return build_application_database_acl_matrix( + topology=topology, + sources=sources, + relation_inventories={"synthetic_inventory": inventory}, + service_manifests={}, + principal_inventories=principal_inventories, + acl_policies={"synthetic_acl_policy": acl_policy}, + authorization_scope=EnumApplicationDatabaseAclAuthorizationScope.SYNTHETIC_PROOF, + required_connect_databases=tuple( + policy.physical_database for policy in acl_policy.connection_policies + ), + ) + + +def _expected_acl_set( + matrix: ModelApplicationDatabaseAclMatrix, +) -> set[tuple[object, ...]]: + objects = {obj.identity: obj for obj in matrix.objects} + expected: set[tuple[object, ...]] = { + ( + ( + "PROCEDURE" + if row.object_type is EnumDatabaseGrantObjectType.FUNCTION + and objects[ + ( + row.database_ref, + row.schema_ref or "", + row.object_type, + row.object_ref or "", + row.function_signature, + ) + ].catalog_kind + == "procedure" + else row.object_type.value + ), + row.physical_database, + row.schema_ref or "", + row.object_ref or "", + row.function_signature or "", + row.principal, + privilege.value, + False, + ) + for row in matrix.rows + for privilege in row.privileges + } + expected.update( + ( + "DATABASE", + physical_database, + "", + "", + "", + principal, + "CONNECT", + False, + ) + for physical_database, principals in matrix.allowed_connect_principals.items() + for principal in principals + ) + return expected + + +def _actual_acl_set( + snapshot: _AclSnapshot, + application_database: str, +) -> set[tuple[object, ...]]: + result: set[tuple[object, ...]] = set() + for row in snapshot["database_acl"]: + result.add( + ( + "DATABASE", + str(row["database_name"]), + "", + "", + "", + str(row["grantee"]), + str(row["privilege_type"]), + bool(row["is_grantable"]), + ) + ) + for row in snapshot["schema_acl"]: + result.add( + ( + "SCHEMA", + application_database, + str(row["schema_name"]), + "", + "", + str(row["grantee"]), + str(row["privilege_type"]), + bool(row["is_grantable"]), + ) + ) + for row in snapshot["object_acl"]: + result.add( + ( + str(row["object_type"]), + application_database, + str(row["schema_name"]), + str(row["object_name"]), + str(row.get("function_signature") or ""), + str(row["grantee"]), + str(row["privilege_type"]), + bool(row["is_grantable"]), + ) + ) + return result + + +def _expected_hardened_default_acl_catalog_rows( + matrix: ModelApplicationDatabaseAclMatrix, +) -> list[dict[str, object]]: + """Project the exact explicit rows needed to remove builtin PUBLIC defaults.""" + rows: list[dict[str, object]] = [] + for owner in sorted(_owner_roles(matrix)): + rows.extend( + ( + { + "owner": owner, + "schema_name": None, + "object_type": "FUNCTION", + "raw_acl": f"{owner}=X/{owner}", + }, + { + "owner": owner, + "schema_name": None, + "object_type": "TYPE", + "raw_acl": f"{owner}=U/{owner}", + }, + ) + ) + return _sorted_rows(rows) + + +def _catalog_violations( + snapshot: _AclSnapshot, + matrix: ModelApplicationDatabaseAclMatrix, +) -> set[str]: + violations: set[str] = set() + expected = _expected_acl_set(matrix) + application_databases = {row.physical_database for row in matrix.default_privileges} + assert len(application_databases) == 1, application_databases + actual = _actual_acl_set(snapshot, next(iter(application_databases))) + unexpected = actual - expected + missing = expected - actual + if missing: + violations.add("MISSING_DECLARED_PRIVILEGE") + if any(row[5] == PUBLIC_PRINCIPAL for row in unexpected): + violations.add("PUBLIC_PRIVILEGE") + if any(bool(row[7]) for row in actual): + violations.add("GRANT_OPTION") + if any( + row[0] == "DATABASE" and row[6] in {"CREATE", "TEMPORARY"} for row in unexpected + ): + violations.add("DATABASE_DDL_PRIVILEGE") + if snapshot["column_acl"]: + violations.add("COLUMN_PRIVILEGE") + + declared_principals = { + principal + for principals in matrix.declared_principals.values() + for principal in principals + } + if any( + row[5] not in declared_principals | {PUBLIC_PRINCIPAL} for row in unexpected + ): + violations.add("UNDECLARED_PRINCIPAL_PRIVILEGE") + + governed_roles = {state.role for state in matrix.governed_role_states} + owner_roles = _owner_roles(matrix) + governed_login_roles = { + state.role for state in matrix.governed_role_states if state.login + } + object_domains = { + ( + obj.object_type.value, + obj.schema_ref, + obj.object_ref, + obj.function_signature or "", + ): obj.domain + for obj in matrix.objects + } + database_ref_by_physical = { + row.physical_database: row.database_ref + for row in matrix.rows + if row.object_type is EnumDatabaseGrantObjectType.DATABASE + } + for row in unexpected: + object_type, _, schema_name, object_name, signature, grantee, _, _ = row + if object_type == "SCHEMA": + domain = matrix.schema_domains.get( + database_ref_by_physical.get(str(row[1]), ""), {} + ).get(str(schema_name)) + else: + normalized_object_type = str( + "FUNCTION" if object_type == "PROCEDURE" else object_type + ) + domain = object_domains.get( + ( + normalized_object_type, + str(schema_name), + str(object_name), + str(signature), + ) + ) + if domain is not None and domain not in matrix.principal_domains.get( + str(grantee), () + ): + violations.add("CROSS_DOMAIN_PRIVILEGE") + unexpected_objects = Counter( + (row[5], row[2], row[3], row[4]) + for row in unexpected + if row[0] in {"TABLE", "SEQUENCE", "FUNCTION", "PROCEDURE", "TYPE"} + and row[5] != PUBLIC_PRINCIPAL + ) + if len(unexpected_objects) >= 2 or any( + count > 1 for count in unexpected_objects.values() + ): + violations.add("BROAD_GRANT") + elif unexpected: + violations.add("UNEXPECTED_PRIVILEGE") + + if snapshot["default_acl"] or snapshot[ + "default_acl_catalog_rows" + ] != _expected_hardened_default_acl_catalog_rows(matrix): + violations.add("UNSAFE_DEFAULT_PRIVILEGE") + expected_owners = { + ( + obj.catalog_kind, + obj.schema_ref, + obj.object_ref, + obj.function_signature or "", + ): obj.owner + for obj in matrix.objects + } + actual_owners = { + ( + str(row["catalog_kind"]), + str(row["schema_name"]), + str(row["object_name"]), + str(row.get("function_signature") or ""), + ): str(row["owner"]) + for row in snapshot["object_owners"] + } + if actual_owners != expected_owners: + violations.add("OWNER_MISMATCH") + expected_schema_owners = { + (row.schema_ref, row.owner) for row in matrix.default_privileges + } + actual_schema_owners = { + (str(row["schema_name"]), str(row["owner"])) + for row in snapshot["schema_owners"] + if str(row["schema_name"]) in MANAGED_SCHEMAS + } + if expected_schema_owners != actual_schema_owners: + violations.add("OWNER_MISMATCH") + + expected_database_owners = dict(matrix.observed_connect_database_owners) + expected_database_owners.update( + { + row.physical_database: matrix.database_owners[row.database_ref] + for row in matrix.rows + if row.object_type is EnumDatabaseGrantObjectType.DATABASE + } + ) + actual_database_owners = { + str(row["database_name"]): str(row["owner"]) + for row in snapshot["database_owner"] + } + if actual_database_owners != expected_database_owners: + violations.add("OWNER_MISMATCH") + + runtime_owned = { + str(row["owner"]) + for row in ( + *snapshot["schema_owners"], + *snapshot["object_owners"], + ) + if str(row["owner"]) in declared_principals + } + application_database_owned = { + str(row["owner"]) + for row in snapshot["database_owner"] + if str(row["database_name"]) == DATABASE + and str(row["owner"]) in declared_principals + } + runtime_owned.update(application_database_owned) + if runtime_owned: + violations.add("RUNTIME_OWNERSHIP") + + for role in snapshot["roles"]: + role_name = str(role["rolname"]) + if role_name not in governed_roles: + continue + if ( + (role_name in governed_login_roles and not bool(role["rolcanlogin"])) + or (role_name in owner_roles and bool(role["rolcanlogin"])) + or bool(role["rolsuper"]) + or bool(role["rolinherit"]) + or bool(role["rolcreaterole"]) + or bool(role["rolcreatedb"]) + or bool(role["rolreplication"]) + or bool(role["rolbypassrls"]) + ): + violations.add("RUNTIME_ROLE_ATTRIBUTES") + + expected_memberships = { + ( + membership.role, + membership.member, + membership.admin_option, + membership.inherit_option, + membership.set_option, + ) + for membership in matrix.allowed_memberships + } + actual_memberships = { + ( + str(row["parent_role"]), + str(row["member_role"]), + bool(row["admin_option"]), + bool(row["inherit_option"]), + bool(row["set_option"]), + ) + for row in snapshot["memberships"] + } + if actual_memberships - expected_memberships: + violations.add("OWNER_MEMBERSHIP") + if expected_memberships - actual_memberships: + violations.add("MISSING_DECLARED_MEMBERSHIP") + return violations + + +def _execute_matrix( + matrix: ModelApplicationDatabaseAclMatrix, + *, + dsn: str = ADMIN_DSN, + phase: EnumApplicationDatabaseAclRenderPhase = ( + EnumApplicationDatabaseAclRenderPhase.FULL + ), +) -> None: + rendered = render_application_database_acl_sql( + matrix, + allow_synthetic_proof=True, + phase=phase, + ) + result = subprocess.run( + ["psql", "--no-psqlrc", "--dbname", dsn], + input=rendered, + text=True, + capture_output=True, + check=False, + ) + if result.returncode != 0: + raise AssertionError( + "psql ACL apply failed:\n" + f"stdout:\n{result.stdout}\n" + f"stderr:\n{result.stderr}" + ) + + +def _atomic_failure_proof( + matrix: ModelApplicationDatabaseAclMatrix, + snapshot: _AclSnapshot, + *, + dsn: str = ADMIN_DSN, + phase: EnumApplicationDatabaseAclRenderPhase = ( + EnumApplicationDatabaseAclRenderPhase.FULL + ), +) -> None: + """Prove the emitted psql script rolls back all prior statements on error.""" + rendered = render_application_database_acl_sql( + matrix, + allow_synthetic_proof=True, + phase=phase, + ) + injected = rendered.replace( + "COMMIT;\n", + "SELECT 1 / 0; -- injected atomicity control\nCOMMIT;\n", + ) + assert injected != rendered + result = subprocess.run( + ["psql", "--no-psqlrc", "--dbname", dsn], + input=injected, + text=True, + capture_output=True, + check=False, + ) + assert result.returncode != 0, result.stdout + assert _capture_snapshot(matrix, dsn=dsn) == snapshot, ( + "failed psql application leaked a partial ACL mutation" + ) + print("acl_phase=psql_atomic_failure red_control=ROLLBACK status=PASS") + + +def _identifier_list(values: Sequence[str]) -> sql.Composed: + return sql.SQL(", ").join(sql.Identifier(value) for value in values) + + +def _grant_rows( + cursor: psycopg2.extensions.cursor, + rows: Sequence[Mapping[str, object]], + *, + target: Callable[[Mapping[str, object]], sql.Composable], + prefix: Callable[[Mapping[str, object]], sql.Composable], +) -> None: + grouped: dict[tuple[str, str, str, bool], set[str]] = defaultdict(set) + row_by_key: dict[tuple[str, str, str, bool], Mapping[str, object]] = {} + for row in rows: + target_identity = { + key_name: value + for key_name, value in row.items() + if key_name not in {"privilege_type", "grantee", "grantor", "is_grantable"} + } + group_key = ( + json.dumps(target_identity, sort_keys=True), + str(row["grantee"]), + str(row["grantor"]), + bool(row["is_grantable"]), + ) + grouped[group_key].add(str(row["privilege_type"])) + row_by_key[group_key] = row + + remaining = set(grouped) + ordered: list[tuple[str, str, str, bool]] = [] + while remaining: + ready = sorted( + key + for key in remaining + if not any( + key[0] == prerequisite[0] + and key[2] == prerequisite[1] + and prerequisite[3] + and bool(grouped[key] & grouped[prerequisite]) + for prerequisite in remaining + if prerequisite != key + ) + ) + if not ready: + raise AssertionError("ACL grantor graph is cyclic or lacks a grant option") + ordered.extend(ready) + remaining.difference_update(ready) + + for key in ordered: + privileges = grouped[key] + row = row_by_key[key] + cursor.execute( + sql.SQL("SET ROLE {}").format(sql.Identifier(str(row["grantor"]))) + ) + cursor.execute( + sql.SQL("GRANT {} ON {} TO {}{}").format( + sql.SQL(", ").join(sql.SQL(item) for item in sorted(privileges)), + prefix(row) + target(row), + sql.SQL("PUBLIC") + if row["grantee"] == PUBLIC_PRINCIPAL + else sql.Identifier(str(row["grantee"])), + sql.SQL(" WITH GRANT OPTION") if row["is_grantable"] else sql.SQL(""), + ) + ) + cursor.execute("RESET ROLE") + + +def _restore_memberships( + cursor: psycopg2.extensions.cursor, + rows: Sequence[Mapping[str, object]], +) -> None: + """Restore exact PG16 membership grantors after their ADMIN paths exist.""" + remaining = {json.dumps(dict(row), sort_keys=True) for row in rows} + row_by_key = {json.dumps(dict(row), sort_keys=True): row for row in rows} + ordered: list[str] = [] + while remaining: + ready = sorted( + key + for key in remaining + if not any( + str(row_by_key[key]["parent_role"]) + == str(row_by_key[prerequisite]["parent_role"]) + and str(row_by_key[key]["grantor"]) + == str(row_by_key[prerequisite]["member_role"]) + and bool(row_by_key[prerequisite]["admin_option"]) + for prerequisite in remaining + if prerequisite != key + ) + ) + if not ready: + raise AssertionError( + "role membership grantor graph is cyclic or lacks ADMIN OPTION" + ) + ordered.extend(ready) + remaining.difference_update(ready) + + for key in ordered: + row = row_by_key[key] + cursor.execute( + sql.SQL("SET ROLE {}").format(sql.Identifier(str(row["grantor"]))) + ) + cursor.execute( + sql.SQL("GRANT {} TO {} WITH ADMIN {}, INHERIT {}, SET {}").format( + sql.Identifier(str(row["parent_role"])), + sql.Identifier(str(row["member_role"])), + sql.SQL("TRUE" if row["admin_option"] else "FALSE"), + sql.SQL("TRUE" if row["inherit_option"] else "FALSE"), + sql.SQL("TRUE" if row["set_option"] else "FALSE"), + ) + ) + cursor.execute("RESET ROLE") + + +def _object_target(row: Mapping[str, object]) -> sql.Composable: + qualified = sql.SQL("{}.{}").format( + sql.Identifier(str(row["schema_name"])), + sql.Identifier(str(row["object_name"])), + ) + if row["object_type"] in {"FUNCTION", "PROCEDURE"}: + return qualified + sql.SQL(str(row.get("function_signature", "()"))) + return qualified + + +def _object_prefix(row: Mapping[str, object]) -> sql.Composable: + return sql.SQL(str(row["object_type"]) + " ") + + +def _grant_column_rows( + cursor: psycopg2.extensions.cursor, + rows: Sequence[Mapping[str, object]], +) -> None: + """Restore exact per-column ACLs, including grantor and grant option.""" + grouped: dict[tuple[str, str, str, bool], set[str]] = defaultdict(set) + row_by_key: dict[tuple[str, str, str, bool], Mapping[str, object]] = {} + for row in rows: + target_identity = json.dumps( + { + "schema_name": row["schema_name"], + "object_name": row["object_name"], + "column_name": row["column_name"], + }, + sort_keys=True, + ) + key = ( + target_identity, + str(row["grantee"]), + str(row["grantor"]), + bool(row["is_grantable"]), + ) + grouped[key].add(str(row["privilege_type"])) + row_by_key[key] = row + remaining = set(grouped) + ordered: list[tuple[str, str, str, bool]] = [] + while remaining: + ready = sorted( + key + for key in remaining + if not any( + key[0] == prerequisite[0] + and key[2] == prerequisite[1] + and prerequisite[3] + and bool(grouped[key] & grouped[prerequisite]) + for prerequisite in remaining + if prerequisite != key + ) + ) + if not ready: + raise AssertionError( + "column ACL grantor graph is cyclic or lacks a grant option" + ) + ordered.extend(ready) + remaining.difference_update(ready) + + for key in ordered: + row = row_by_key[key] + grantee = ( + sql.SQL("PUBLIC") + if row["grantee"] == PUBLIC_PRINCIPAL + else sql.Identifier(str(row["grantee"])) + ) + cursor.execute( + sql.SQL("SET ROLE {}").format(sql.Identifier(str(row["grantor"]))) + ) + cursor.execute( + sql.SQL("GRANT {} ON TABLE {}.{} TO {}{}").format( + sql.SQL(", ").join( + sql.SQL("{} ({})").format( + sql.SQL(privilege), + sql.Identifier(str(row["column_name"])), + ) + for privilege in sorted(grouped[key]) + ), + sql.Identifier(str(row["schema_name"])), + sql.Identifier(str(row["object_name"])), + grantee, + sql.SQL(" WITH GRANT OPTION") if row["is_grantable"] else sql.SQL(""), + ) + ) + cursor.execute("RESET ROLE") + + +def _reset_target_default_acls( + cursor: psycopg2.extensions.cursor, + *, + owners: Sequence[str], + schemas: Sequence[str], +) -> None: + """Return governed global/schema defaults to PostgreSQL built-ins.""" + cursor.execute( + """ + SELECT owner.rolname AS owner, namespace.nspname AS schema_name, + CASE defaults.defaclobjtype + WHEN 'r' THEN 'TABLES' + WHEN 'S' THEN 'SEQUENCES' + WHEN 'f' THEN 'FUNCTIONS' + WHEN 'T' THEN 'TYPES' + END AS object_keyword, + COALESCE(grantee.rolname, 'PUBLIC') AS grantee, + acl.privilege_type + FROM pg_default_acl defaults + JOIN pg_roles owner ON owner.oid = defaults.defaclrole + LEFT JOIN pg_namespace namespace ON namespace.oid = defaults.defaclnamespace + CROSS JOIN LATERAL aclexplode(defaults.defaclacl) acl + LEFT JOIN pg_roles grantee ON grantee.oid = acl.grantee + WHERE owner.rolname = ANY(%s) + AND (defaults.defaclnamespace = 0 OR namespace.nspname = ANY(%s)) + AND acl.grantee <> defaults.defaclrole + ORDER BY owner.rolname, namespace.nspname NULLS FIRST, + defaults.defaclobjtype, grantee.rolname NULLS FIRST, + acl.privilege_type + """, + (list(owners), list(schemas)), + ) + for owner, schema_name, object_keyword, grantee, privilege in cursor.fetchall(): + grantee_sql = ( + sql.SQL("PUBLIC") + if str(grantee) == PUBLIC_PRINCIPAL + else sql.Identifier(str(grantee)) + ) + scope = ( + sql.SQL(" IN SCHEMA {}").format(sql.Identifier(str(schema_name))) + if schema_name is not None + else sql.SQL("") + ) + cursor.execute( + sql.SQL( + "ALTER DEFAULT PRIVILEGES FOR ROLE {}{} REVOKE {} ON {} FROM {} CASCADE" + ).format( + sql.Identifier(str(owner)), + scope, + sql.SQL(str(privilege)), + sql.SQL(str(object_keyword)), + grantee_sql, + ) + ) + + # Global function/type defaults include PUBLIC by definition. Table and + # sequence defaults do not; grant-then-revoke removes any explicit row that + # merely encodes the built-in state. + for owner in owners: + owner_identifier = sql.Identifier(owner) + cursor.execute( + sql.SQL( + "ALTER DEFAULT PRIVILEGES FOR ROLE {} " + "GRANT EXECUTE ON FUNCTIONS TO PUBLIC" + ).format(owner_identifier) + ) + cursor.execute( + sql.SQL( + "ALTER DEFAULT PRIVILEGES FOR ROLE {} GRANT USAGE ON TYPES TO PUBLIC" + ).format(owner_identifier) + ) + for object_keyword in ("TABLES", "SEQUENCES"): + cursor.execute( + sql.SQL( + "ALTER DEFAULT PRIVILEGES FOR ROLE {} " + f"GRANT ALL PRIVILEGES ON {object_keyword} TO PUBLIC" + ).format(owner_identifier) + ) + cursor.execute( + sql.SQL( + "ALTER DEFAULT PRIVILEGES FOR ROLE {} " + f"REVOKE ALL PRIVILEGES ON {object_keyword} FROM PUBLIC" + ).format(owner_identifier) + ) + + +def _restore_snapshot( + snapshot: _AclSnapshot, + matrix: ModelApplicationDatabaseAclMatrix, + *, + inject_failure: bool = False, + dsn: str = ADMIN_DSN, +) -> None: + """Atomically restore only from the durable pre-change catalog snapshot.""" + matrix_principals = _matrix_principals(matrix) + snapshot_grantees = { + str(row["grantee"]) + for rows in ( + snapshot["database_acl"], + snapshot["schema_acl"], + snapshot["object_acl"], + snapshot["column_acl"], + snapshot["default_acl"], + ) + for row in rows + if str(row["grantee"]) != PUBLIC_PRINCIPAL + } + membership_roles = { + str(row[key]) + for row in snapshot["memberships"] + for key in ("parent_role", "member_role", "grantor") + } + revocation_principals = sorted( + matrix_principals | snapshot_grantees | membership_roles + ) + database_revocation_principals = revocation_principals + membership_members = sorted(_membership_member_roles(matrix)) + protected_parents = sorted(_protected_parent_roles(matrix)) + snapshot_role_names = {str(row["rolname"]) for row in snapshot["roles"]} + renderer_created_roles = sorted( + ( + _owner_roles(matrix) + | { + principal + for principals in matrix.declared_principals.values() + for principal in principals + } + | _allowed_connect_roles(matrix) + ) + - snapshot_role_names + ) + snapshot_schema_names = { + str(row["schema_name"]) for row in snapshot["schema_owners"] + } + renderer_created_schemas = sorted(set(MANAGED_SCHEMAS) - snapshot_schema_names) + connection = psycopg2.connect(dsn) + try: + with connection.cursor() as cursor: + grantees = _identifier_list(revocation_principals) + database_grantees = _identifier_list(database_revocation_principals) + for database_name in matrix.required_connect_databases: + cursor.execute( + sql.SQL( + "REVOKE ALL PRIVILEGES ON DATABASE {} FROM PUBLIC, {} CASCADE" + ).format( + sql.Identifier(database_name), + database_grantees, + ) + ) + for schema_name in MUTATED_SCHEMAS: + cursor.execute( + sql.SQL( + "REVOKE ALL PRIVILEGES ON SCHEMA {} FROM PUBLIC, {} CASCADE" + ).format(sql.Identifier(schema_name), grantees) + ) + for obj in matrix.objects: + keyword = { + "table": "TABLE", + "view": "TABLE", + "materialized_view": "TABLE", + "sequence": "SEQUENCE", + "function": "FUNCTION", + "procedure": "PROCEDURE", + "type": "TYPE", + }[obj.catalog_kind] + target = sql.SQL("{}.{}").format( + sql.Identifier(obj.schema_ref), sql.Identifier(obj.object_ref) + ) + if obj.object_type is EnumDatabaseGrantObjectType.FUNCTION: + target += sql.SQL(obj.function_signature or "()") + cursor.execute( + sql.SQL( + f"REVOKE ALL PRIVILEGES ON {keyword} {{}} FROM PUBLIC, {{}} CASCADE" + ).format(target, grantees) + ) + default_owners = sorted(_owner_roles(matrix)) + _reset_target_default_acls( + cursor, + owners=default_owners, + schemas=MANAGED_SCHEMAS, + ) + + if inject_failure: + cursor.execute("SELECT 1 / 0") + + for row in snapshot["roles"]: + attributes = [ + "LOGIN" if row["rolcanlogin"] else "NOLOGIN", + "SUPERUSER" if row["rolsuper"] else "NOSUPERUSER", + "INHERIT" if row["rolinherit"] else "NOINHERIT", + "CREATEROLE" if row["rolcreaterole"] else "NOCREATEROLE", + "CREATEDB" if row["rolcreatedb"] else "NOCREATEDB", + "REPLICATION" if row["rolreplication"] else "NOREPLICATION", + "BYPASSRLS" if row["rolbypassrls"] else "NOBYPASSRLS", + ] + cursor.execute( + sql.SQL("ALTER ROLE {} " + " ".join(attributes)).format( + sql.Identifier(str(row["rolname"])) + ) + ) + cursor.execute( + """ + SELECT parent.rolname, child.rolname, grantor.rolname + FROM pg_auth_members membership + JOIN pg_roles parent ON parent.oid = membership.roleid + JOIN pg_roles child ON child.oid = membership.member + JOIN pg_roles grantor ON grantor.oid = membership.grantor + WHERE child.rolname = ANY(%s) + OR parent.rolname = ANY(%s) + """, + (membership_members, protected_parents), + ) + current_memberships = cursor.fetchall() + for parent, member, grantor in current_memberships: + cursor.execute( + sql.SQL("REVOKE {} FROM {} GRANTED BY {} CASCADE").format( + sql.Identifier(str(parent)), + sql.Identifier(str(member)), + sql.Identifier(str(grantor)), + ) + ) + _restore_memberships(cursor, snapshot["memberships"]) + for row in snapshot["database_owner"]: + cursor.execute( + sql.SQL("ALTER DATABASE {} OWNER TO {}").format( + sql.Identifier(str(row["database_name"])), + sql.Identifier(str(row["owner"])), + ) + ) + for row in snapshot["schema_owners"]: + cursor.execute( + sql.SQL("ALTER SCHEMA {} OWNER TO {}").format( + sql.Identifier(str(row["schema_name"])), + sql.Identifier(str(row["owner"])), + ) + ) + owner_restore_order = { + "TABLE": 0, + "VIEW": 1, + "MATERIALIZED VIEW": 2, + "SEQUENCE": 3, + "TYPE": 4, + "FUNCTION": 5, + "PROCEDURE": 6, + } + for row in sorted( + snapshot["object_owners"], + key=lambda item: ( + owner_restore_order[str(item["owner_keyword"])], + str(item["schema_name"]), + str(item["object_name"]), + ), + ): + keyword = str(row["owner_keyword"]) + target = _object_target(row) + cursor.execute( + sql.SQL(f"ALTER {keyword} {{}} OWNER TO {{}}").format( + target, sql.Identifier(str(row["owner"])) + ) + ) + + _grant_rows( + cursor, + snapshot["database_acl"], + target=lambda row: sql.Identifier(str(row["database_name"])), + prefix=lambda row: sql.SQL("DATABASE "), + ) + _grant_rows( + cursor, + snapshot["schema_acl"], + target=lambda row: sql.Identifier(str(row["schema_name"])), + prefix=lambda row: sql.SQL("SCHEMA "), + ) + _grant_rows( + cursor, + snapshot["object_acl"], + target=_object_target, + prefix=_object_prefix, + ) + _grant_column_rows(cursor, snapshot["column_acl"]) + raw_default_rows = { + ( + str(row["owner"]), + row["schema_name"], + str(row["object_type"]), + ): str(row["raw_acl"]) + for row in snapshot["default_acl_catalog_rows"] + } + for owner in default_owners: + for object_type, privilege, marker in ( + ("FUNCTION", "EXECUTE", "=X"), + ("TYPE", "USAGE", "=U"), + ): + raw_acl = raw_default_rows.get((owner, None, object_type)) + public_builtin_present = raw_acl is not None and any( + item.startswith(marker) for item in raw_acl.split(",") + ) + if raw_acl is not None and not public_builtin_present: + cursor.execute( + sql.SQL( + "ALTER DEFAULT PRIVILEGES FOR ROLE {} " + f"REVOKE {privilege} ON {object_type}S FROM PUBLIC" + ).format(sql.Identifier(owner)) + ) + default_rows = snapshot["default_acl"] + for row in default_rows: + if row["grantor"] != row["owner"]: + raise AssertionError( + "default ACL grantor must equal its owning role for exact restore" + ) + grantee = ( + sql.SQL("PUBLIC") + if row["grantee"] == PUBLIC_PRINCIPAL + else sql.Identifier(str(row["grantee"])) + ) + keyword = { + "TABLE": "TABLES", + "SEQUENCE": "SEQUENCES", + "FUNCTION": "FUNCTIONS", + "TYPE": "TYPES", + }[str(row["object_type"])] + default_schema_name = row["schema_name"] + scope = ( + sql.SQL(" IN SCHEMA {} ").format( + sql.Identifier(str(default_schema_name)) + ) + if default_schema_name is not None + else sql.SQL(" ") + ) + cursor.execute( + sql.SQL("SET ROLE {}").format(sql.Identifier(str(row["owner"]))) + ) + cursor.execute( + sql.SQL( + f"ALTER DEFAULT PRIVILEGES{{}}" + f"GRANT {row['privilege_type']} ON {keyword} TO {{}}{{}}" + ).format( + scope, + grantee, + sql.SQL(" WITH GRANT OPTION") + if row["is_grantable"] + else sql.SQL(""), + ) + ) + cursor.execute("RESET ROLE") + for schema_name in renderer_created_schemas: + cursor.execute( + sql.SQL("DROP SCHEMA {}").format(sql.Identifier(schema_name)) + ) + for role_name in renderer_created_roles: + # Return newly-created owners to PostgreSQL's built-in default ACL. + # DROP ROLE then remains a fail-closed emptiness/dependency check: + # it cannot cascade into a relation that appeared after apply. + cursor.execute( + sql.SQL( + "ALTER DEFAULT PRIVILEGES FOR ROLE {} " + "GRANT EXECUTE ON FUNCTIONS TO PUBLIC" + ).format(sql.Identifier(role_name)) + ) + cursor.execute( + sql.SQL( + "ALTER DEFAULT PRIVILEGES FOR ROLE {} " + "GRANT USAGE ON TYPES TO PUBLIC" + ).format(sql.Identifier(role_name)) + ) + cursor.execute( + sql.SQL("DROP ROLE {}").format(sql.Identifier(role_name)) + ) + connection.commit() + except Exception: + connection.rollback() + raise + finally: + connection.close() + + +def _role_connection( + role: str, + database: str = DATABASE, +) -> psycopg2.extensions.connection: + return psycopg2.connect( + host=DATABASE_HOST, + port=DATABASE_PORT, + dbname=database, + user=role, + password=ROLE_PASSWORD, + ) + + +def _expect_denied(connection: psycopg2.extensions.connection, statement: str) -> None: + try: + with connection.cursor() as cursor: + cursor.execute(statement) + except psycopg2.Error: + connection.rollback() + return + raise AssertionError(f"Expected PostgreSQL denial: {statement}") + + +def _expect_connection_denied(role: str, database: str) -> None: + try: + connection = _role_connection(role, database) + except psycopg2.OperationalError: + return + connection.close() + raise AssertionError(f"{role} unexpectedly connected to {database}") + + +def _legacy_default_behavior_proof() -> None: + """Prove the unrelated-schema default grant still affects future objects.""" + connection = psycopg2.connect(ADMIN_DSN) + try: + with connection.cursor() as cursor: + cursor.execute("SET ROLE owner_onex_tenant") + cursor.execute( + "CREATE TABLE legacy_acl_sentinel.default_acl_probe(id integer)" + ) + cursor.execute("RESET ROLE") + cursor.execute( + "SELECT has_table_privilege(%s, %s, 'SELECT')", + ( + "untrusted_login", + "legacy_acl_sentinel.default_acl_probe", + ), + ) + assert cursor.fetchone() == (True,) + finally: + connection.rollback() + connection.close() + + +def _builtin_default_rollback_proof() -> None: + """Prove rollback restores PostgreSQL's implicit PUBLIC routine/type ACLs.""" + connection = psycopg2.connect(ADMIN_DSN) + try: + with connection.cursor() as cursor: + cursor.execute("SET ROLE owner_onex_tenant") + cursor.execute( + "CREATE FUNCTION legacy_acl_sentinel.rollback_function() " + "RETURNS integer LANGUAGE sql AS $$SELECT 1$$" + ) + cursor.execute( + "CREATE TYPE legacy_acl_sentinel.rollback_type AS ENUM ('restored')" + ) + cursor.execute("RESET ROLE") + cursor.execute( + """ + SELECT has_function_privilege( + 'untrusted_login', + 'legacy_acl_sentinel.rollback_function()', + 'EXECUTE' + ), + has_type_privilege( + 'untrusted_login', + 'legacy_acl_sentinel.rollback_type', + 'USAGE' + ) + """ + ) + assert cursor.fetchone() == (True, True) + finally: + connection.rollback() + connection.close() + + +def _legacy_scaffold_behavior_proof() -> None: + """Prove P1 preserves a pre-existing login's CONNECT/read/write path.""" + connection = _role_connection("legacy_probe_login", "acl_scaffold_probe") + try: + with connection.cursor() as cursor: + cursor.execute("SELECT id FROM public.legacy_scaffold_data") + assert cursor.fetchall() == [(1,)] + cursor.execute("INSERT INTO public.legacy_scaffold_data VALUES (2)") + finally: + connection.rollback() + connection.close() + + +def _connection_isolation_proof(matrix: ModelApplicationDatabaseAclMatrix) -> None: + """Exercise positive and cross-database negative CONNECT cases.""" + assert set(matrix.required_connect_databases) == { + DATABASE, + *SERVICE_DATABASE_ROLES, + } + all_service_roles = set(SERVICE_DATABASE_ROLES.values()) + for database, allowed_role in SERVICE_DATABASE_ROLES.items(): + allowed = _role_connection(allowed_role, database) + allowed.close() + for denied_role in sorted( + set(WORKLOADS) | all_service_roles | {"shadow_login", "untrusted_login"} + ): + if denied_role != allowed_role: + _expect_connection_denied(denied_role, database) + for service_role in sorted(all_service_roles): + _expect_connection_denied(service_role, DATABASE) + print("acl_phase=eight_database_connect_isolation status=PASS") + + +def _behavioral_proof(matrix: ModelApplicationDatabaseAclMatrix) -> None: + tenant = _role_connection("tenant_projection_writer") + dashboard = _role_connection("app_dashboard") + api = _role_connection("onex_api") + runtime = _role_connection("omninode_runtime") + try: + with tenant.cursor() as cursor: + cursor.execute( + "INSERT INTO tenant.delegation_events (payload) VALUES ('matrix')" + ) + cursor.execute("CALL tenant.record_delegation('procedure')") + tenant.commit() + _expect_denied(tenant, "SELECT * FROM omninode_internal.runtime_state") + _expect_denied(tenant, "CREATE TABLE tenant.illegal(id integer)") + + with dashboard.cursor() as cursor: + cursor.execute("SELECT count(*) FROM tenant.delegation_events") + assert cursor.fetchone()[0] >= 1 + cursor.execute("SELECT display_name FROM tenant.tenant_account_names") + assert cursor.fetchone()[0] == "Synthetic" + cursor.execute("SELECT code FROM platform_catalog.plan_tier_snapshot") + assert cursor.fetchone()[0] == "beta" + _expect_denied( + dashboard, + "INSERT INTO tenant.delegation_events (payload) VALUES ('forbidden')", + ) + _expect_denied(dashboard, "SELECT * FROM omninode_internal.runtime_state") + + with api.cursor() as cursor: + cursor.execute( + "INSERT INTO tenant.tenant_accounts VALUES (2, 'API matrix')" + ) + cursor.execute("SELECT code FROM platform_catalog.plan_tiers") + assert cursor.fetchone()[0] == "beta" + cursor.execute("SELECT ROW(1, 'API')::tenant.account_ref") + cursor.execute("SELECT '[1,2)'::tenant.account_id_span") + cursor.execute("SELECT '{}'::tenant.account_id_span_set") + api.commit() + _expect_denied(api, "UPDATE platform_catalog.plan_tiers SET code='x'") + _expect_denied(api, "SELECT * FROM omninode_internal.runtime_state") + + with runtime.cursor() as cursor: + cursor.execute( + "INSERT INTO omninode_internal.runtime_state VALUES (2, 'blocked')" + ) + cursor.execute("SELECT 'runtime'::omninode_internal.runtime_code") + runtime.commit() + _expect_denied(runtime, "SELECT * FROM tenant.delegation_events") + _expect_denied(runtime, "SELECT * FROM platform_catalog.plan_tiers") + finally: + tenant.close() + dashboard.close() + api.close() + runtime.close() + + try: + untrusted = _role_connection("untrusted_login") + except psycopg2.OperationalError: + pass + else: + untrusted.close() + raise AssertionError("PUBLIC CONNECT was not revoked") + _connection_isolation_proof(matrix) + + +def _migration_membership_proof() -> None: + inherited = _dict_rows( + """ + SELECT has_table_privilege( + 'db_migrator', 'tenant.tenant_accounts', 'SELECT' + ) AS inherited + """ + )[0] + assert not bool(inherited["inherited"]), inherited + connection = _admin() + try: + with connection.cursor() as cursor: + cursor.execute("SET SESSION AUTHORIZATION db_migrator") + cursor.execute("SET ROLE owner_onex_tenant") + cursor.execute("SELECT count(*) FROM tenant.tenant_accounts") + assert cursor.fetchone()[0] >= 1 + cursor.execute("RESET SESSION AUTHORIZATION") + finally: + connection.close() + + +def _future_default_proof() -> None: + connection = _admin() + try: + with connection.cursor() as cursor: + cursor.execute("SET ROLE owner_onex_tenant") + cursor.execute("CREATE TABLE tenant.future_table(id integer)") + cursor.execute("CREATE SEQUENCE tenant.future_sequence") + cursor.execute( + "CREATE FUNCTION tenant.future_function() RETURNS integer " + "LANGUAGE sql AS $$SELECT 1$$" + ) + cursor.execute("CREATE TYPE tenant.future_type AS ENUM ('future')") + cursor.execute("RESET ROLE") + for role in (*WORKLOADS, "untrusted_login"): + checks = _dict_rows( + """ + SELECT has_table_privilege(%s, 'tenant.future_table', 'SELECT') AS table_ok, + has_sequence_privilege(%s, 'tenant.future_sequence', 'USAGE') AS sequence_ok, + has_function_privilege(%s, 'tenant.future_function()', 'EXECUTE') AS function_ok, + has_type_privilege(%s, 'tenant.future_type', 'USAGE') AS type_ok + """, + (role, role, role, role), + )[0] + assert not any(bool(value) for value in checks.values()), (role, checks) + with connection.cursor() as cursor: + cursor.execute("DROP TABLE tenant.future_table") + cursor.execute("DROP SEQUENCE tenant.future_sequence") + cursor.execute("DROP FUNCTION tenant.future_function()") + cursor.execute("DROP TYPE tenant.future_type") + finally: + connection.close() + + +def _extra_object_rejection_proof( + matrix: ModelApplicationDatabaseAclMatrix, +) -> None: + """Prove an undeclared runtime-owned object is a hard catalog violation.""" + connection = _admin() + try: + with connection.cursor() as cursor: + cursor.execute("CREATE TABLE tenant.undeclared_runtime_owned(id integer)") + cursor.execute( + "ALTER TABLE tenant.undeclared_runtime_owned OWNER TO app_dashboard" + ) + violations = _catalog_violations(_capture_snapshot(matrix), matrix) + assert {"OWNER_MISMATCH", "RUNTIME_OWNERSHIP"} <= violations, violations + with connection.cursor() as cursor: + cursor.execute("DROP TABLE tenant.undeclared_runtime_owned") + finally: + connection.close() + print("acl_phase=extra_object_red status=DETECTED") + + +def _unknown_acl_and_membership_reconciliation_proof( + matrix: ModelApplicationDatabaseAclMatrix, + green: _AclSnapshot, +) -> None: + """Prove live catalog sweeps remove grantees/children absent from evidence.""" + connection = _admin() + try: + with connection.cursor() as cursor: + cursor.execute("CREATE ROLE hostile_unknown") + cursor.execute( + "GRANT SELECT ON tenant.partitioned_events " + "TO rls_admin WITH GRANT OPTION" + ) + cursor.execute("GRANT USAGE ON SCHEMA tenant TO rls_admin") + cursor.execute("SET ROLE rls_admin") + cursor.execute( + "GRANT SELECT ON tenant.partitioned_events TO hostile_unknown" + ) + cursor.execute("RESET ROLE") + cursor.execute("REVOKE USAGE ON SCHEMA tenant FROM rls_admin") + cursor.execute("GRANT owner_onex_tenant TO hostile_unknown") + cursor.execute( + "ALTER DEFAULT PRIVILEGES FOR ROLE owner_onex_tenant " + "IN SCHEMA tenant GRANT SELECT ON TABLES TO hostile_unknown" + ) + _execute_matrix(matrix) + assert _capture_snapshot(matrix) == green + with connection.cursor() as cursor: + cursor.execute("DROP ROLE hostile_unknown") + finally: + connection.close() + print("acl_phase=unknown_catalog_rows_reconciled status=PASS") + + +def _scaffold_probe_matrix( + source_matrix: ModelApplicationDatabaseAclMatrix, +) -> ModelApplicationDatabaseAclMatrix: + """Build a typed scaffold whose desired roles and schemas are all absent.""" + database_ref = "probe" + physical_database = "acl_scaffold_probe" + principals_by_domain = { + EnumDatabaseSchemaDomain.TENANT: "probe_tenant_writer", + EnumDatabaseSchemaDomain.OMNINODE_INTERNAL: "probe_internal_writer", + EnumDatabaseSchemaDomain.PLATFORM_CATALOG: "probe_catalog_reader", + } + schema_domains = { + "tenant": EnumDatabaseSchemaDomain.TENANT, + "omninode_internal": EnumDatabaseSchemaDomain.OMNINODE_INTERNAL, + "platform_catalog": EnumDatabaseSchemaDomain.PLATFORM_CATALOG, + } + owners = { + "tenant": "probe_owner_tenant", + "omninode_internal": "probe_owner_internal", + "platform_catalog": "probe_owner_catalog", + } + declared = tuple(sorted(principals_by_domain.values())) + observed = ("probe_migrator",) + grantees = (PUBLIC_PRINCIPAL, *declared, *observed) + rows: list[ModelApplicationDatabaseAclRow] = [] + for principal in grantees: + rows.append( + ModelApplicationDatabaseAclRow( + principal=principal, + database_ref=database_ref, + physical_database=physical_database, + object_type=EnumDatabaseGrantObjectType.DATABASE, + privileges=(EnumDatabasePrivilege.CONNECT,) + if principal in declared + else (), + ) + ) + for schema_name, domain in schema_domains.items(): + rows.append( + ModelApplicationDatabaseAclRow( + principal=principal, + database_ref=database_ref, + physical_database=physical_database, + object_type=EnumDatabaseGrantObjectType.SCHEMA, + schema_ref=schema_name, + privileges=(EnumDatabasePrivilege.USAGE,) + if principals_by_domain.get(domain) == principal + else (), + ) + ) + defaults = tuple( + ModelApplicationDatabaseDefaultAclRow( + owner=owners[schema_name], + database_ref=database_ref, + physical_database=physical_database, + schema_ref=schema_name, + object_type=object_type, + grantee=grantee, + ) + for schema_name in sorted(schema_domains) + for object_type in ( + EnumDatabaseGrantObjectType.TABLE, + EnumDatabaseGrantObjectType.SEQUENCE, + EnumDatabaseGrantObjectType.FUNCTION, + EnumDatabaseGrantObjectType.TYPE, + ) + for grantee in grantees + ) + payload = { + "authorization_scope": ( + EnumApplicationDatabaseAclAuthorizationScope.SYNTHETIC_PROOF + ), + "scaffold_status": "READY", + "scaffold_blockers": (), + "status": "BLOCKED", + "blockers": ( + "scaffold proof deliberately withholds materialized object evidence", + ), + "sources": source_matrix.sources, + "declared_principals": {database_ref: declared}, + "observed_principals": {database_ref: observed}, + "absent_principals": {database_ref: declared}, + "observed_owner_roles": (), + "absent_owner_roles": tuple(sorted(owners.values())), + "observed_role_states": ( + ModelApplicationDatabaseObservedRoleState( + role="probe_migrator", + login=False, + superuser=False, + bypass_rls=False, + create_database=False, + create_role=False, + replication=False, + inherit=False, + ), + ), + "governed_role_states": ( + *( + ModelApplicationDatabaseRoleState( + role=owner, + role_kind="owner", + login=False, + ) + for owner in sorted(owners.values()) + ), + *( + ModelApplicationDatabaseRoleState( + role=principal, + role_kind="workload", + login=True, + ) + for principal in declared + ), + ModelApplicationDatabaseRoleState( + role="probe_migrator", + role_kind="migration", + login=False, + ), + ), + "retained_administrative_principals": (), + "database_owners": {database_ref: owners["platform_catalog"]}, + "required_connect_databases": (physical_database,), + "observed_connect_database_owners": {physical_database: "postgres"}, + "allowed_connect_principals": {physical_database: declared}, + "observed_connect_principals": {physical_database: observed}, + "absent_connect_principals": {physical_database: declared}, + "schema_domains": {database_ref: schema_domains}, + "observed_schema_owners": {database_ref: {}}, + "absent_schemas": {database_ref: tuple(sorted(schema_domains))}, + "principal_domains": { + principal: (domain,) for domain, principal in principals_by_domain.items() + }, + "allowed_memberships": tuple( + ModelApplicationDatabaseRoleMembership( + database_ref=database_ref, + role=owner, + member="probe_migrator", + ) + for owner in sorted(owners.values()) + ), + "observed_objects": (), + "objects": (), + "rows": tuple(rows), + "default_privileges": defaults, + "excluded_objects": (), + } + return ModelApplicationDatabaseAclMatrix.model_validate(payload) + + +def _scaffold_phase_proof(matrix: ModelApplicationDatabaseAclMatrix) -> None: + """Prove P1 can precede object materialization without weakening rollback.""" + probe = _scaffold_probe_matrix(matrix) + probe_dsn = ( + f"postgresql://postgres@{DATABASE_HOST}:{DATABASE_PORT}/acl_scaffold_probe" + ) + assert probe.status == "BLOCKED" + assert probe.scaffold_status == "READY" + rendered = render_application_database_acl_sql( + probe, + allow_synthetic_proof=True, + phase=EnumApplicationDatabaseAclRenderPhase.SCAFFOLD, + ) + assert "-- Render phase: scaffold" in rendered + assert "ALTER TABLE " not in rendered + assert "ALTER VIEW " not in rendered + assert "ALTER MATERIALIZED VIEW " not in rendered + assert "ALTER FUNCTION " not in rendered + assert "ALTER PROCEDURE " not in rendered + assert "ALTER TYPE " not in rendered + assert "GRANT SELECT ON TABLE " not in rendered + + prechange = _capture_snapshot(probe, dsn=probe_dsn) + _legacy_scaffold_behavior_proof() + application_prechange = _capture_snapshot(matrix) + wrong_database = subprocess.run( + ["psql", "--no-psqlrc", "--dbname", ADMIN_DSN], + input=rendered, + text=True, + capture_output=True, + check=False, + ) + assert wrong_database.returncode != 0 + assert _capture_snapshot(probe, dsn=probe_dsn) == prechange + assert _capture_snapshot(matrix) == application_prechange + print("acl_phase=scaffold_wrong_database_guard status=PASS") + + collision_connection = _admin(probe_dsn) + try: + with collision_connection.cursor() as cursor: + cursor.execute( + "CREATE ROLE probe_catalog_reader LOGIN PASSWORD %s CREATEROLE", + (ROLE_PASSWORD,), + ) + hostile_role_snapshot = _capture_snapshot(probe, dsn=probe_dsn) + hostile_role_apply = subprocess.run( + ["psql", "--no-psqlrc", "--dbname", probe_dsn], + input=rendered, + text=True, + capture_output=True, + check=False, + ) + assert hostile_role_apply.returncode != 0 + assert _capture_snapshot(probe, dsn=probe_dsn) == hostile_role_snapshot, ( + "stale expected-absent role evidence leaked a mutation" + ) + with collision_connection.cursor() as cursor: + cursor.execute("DROP ROLE probe_catalog_reader") + assert _capture_snapshot(probe, dsn=probe_dsn) == prechange + + with collision_connection.cursor() as cursor: + cursor.execute("CREATE SCHEMA tenant") + cursor.execute("CREATE TABLE tenant.hostile_collision(id integer)") + hostile_schema_snapshot = _capture_snapshot(probe, dsn=probe_dsn) + hostile_schema_apply = subprocess.run( + ["psql", "--no-psqlrc", "--dbname", probe_dsn], + input=rendered, + text=True, + capture_output=True, + check=False, + ) + assert hostile_schema_apply.returncode != 0 + assert _capture_snapshot(probe, dsn=probe_dsn) == hostile_schema_snapshot, ( + "stale expected-absent schema evidence leaked a mutation" + ) + with collision_connection.cursor() as cursor: + cursor.execute("DROP SCHEMA tenant CASCADE") + assert _capture_snapshot(probe, dsn=probe_dsn) == prechange + finally: + collision_connection.close() + print("acl_phase=scaffold_stale_absence_collision status=REJECTED") + + _atomic_failure_proof( + probe, + prechange, + dsn=probe_dsn, + phase=EnumApplicationDatabaseAclRenderPhase.SCAFFOLD, + ) + for pass_number in (1, 2): + _execute_matrix( + probe, + dsn=probe_dsn, + phase=EnumApplicationDatabaseAclRenderPhase.SCAFFOLD, + ) + print(f"acl_phase=scaffold_apply pass={pass_number} status=PASS") + green = _capture_snapshot(probe, dsn=probe_dsn) + expected_additions = _expected_acl_set(probe) + actual_acl = _actual_acl_set(green, "acl_scaffold_probe") + assert expected_additions <= actual_acl, expected_additions - actual_acl + assert green["database_owner"] == prechange["database_owner"] + expected_schema_owners = { + (schema_name, owner) + for schema_name, owner in { + row.schema_ref: row.owner for row in probe.default_privileges + }.items() + } + assert expected_schema_owners <= { + (str(row["schema_name"]), str(row["owner"])) for row in green["schema_owners"] + } + for role in green["roles"]: + if str(role["rolname"]) == "probe_migrator": + continue + assert not any( + bool(role[field]) + for field in ( + "rolsuper", + "rolinherit", + "rolcreaterole", + "rolcreatedb", + "rolreplication", + "rolbypassrls", + ) + ), role + assert not green["object_owners"] + assert not green["object_acl"] + assert not green["column_acl"] + assert not green["default_acl"] + assert green[ + "default_acl_catalog_rows" + ] == _expected_hardened_default_acl_catalog_rows(probe) + _legacy_scaffold_behavior_proof() + + hostile_connection = _admin(probe_dsn) + try: + for create_statement, drop_statement in ( + ( + 'CREATE COLLATION tenant.hostile_collation FROM "C"', + "DROP COLLATION tenant.hostile_collation", + ), + ( + "CREATE TYPE tenant.hostile_enum AS ENUM ('collision')", + "DROP TYPE tenant.hostile_enum", + ), + ): + with hostile_connection.cursor() as cursor: + cursor.execute(create_statement) + hostile_snapshot = _capture_snapshot(probe, dsn=probe_dsn) + hostile_apply = subprocess.run( + ["psql", "--no-psqlrc", "--dbname", probe_dsn], + input=rendered, + text=True, + capture_output=True, + check=False, + ) + assert hostile_apply.returncode != 0 + assert "expected-absent schema collision for tenant" in hostile_apply.stderr + assert _capture_snapshot(probe, dsn=probe_dsn) == hostile_snapshot + with hostile_connection.cursor() as cursor: + cursor.execute(drop_statement) + assert _capture_snapshot(probe, dsn=probe_dsn) == green + finally: + hostile_connection.close() + + full_payload = probe.model_dump(mode="json") + full_payload.update({"status": "READY", "blockers": []}) + full_probe = ModelApplicationDatabaseAclMatrix.model_validate(full_payload) + for pass_number in (1, 2): + _execute_matrix(full_probe, dsn=probe_dsn) + print(f"acl_phase=scaffold_probe_full_apply pass={pass_number} status=PASS") + full_green = _capture_snapshot(full_probe, dsn=probe_dsn) + assert not _catalog_violations(full_green, full_probe), _catalog_violations( + full_green, + full_probe, + ) + _expect_connection_denied("legacy_probe_login", "acl_scaffold_probe") + _restore_snapshot(prechange, probe, dsn=probe_dsn) + assert _capture_snapshot(probe, dsn=probe_dsn) == prechange + _legacy_scaffold_behavior_proof() + print("acl_phase=scaffold_fresh_additive_round_trip status=PASS") + + +def main() -> None: + postgres_major = _postgres_major() + assert postgres_major == 16, postgres_major + matrix = _fixture_matrix() + assert matrix.status == "READY", matrix.blockers + assert matrix.scaffold_status == "BLOCKED" + assert any( + "additive scaffold intended roles are not already safe" in blocker + for blocker in matrix.scaffold_blockers + ) + + _scaffold_phase_proof(matrix) + _extra_object_rejection_proof(matrix) + legacy_default_acl = _capture_legacy_default_acl() + assert legacy_default_acl + _legacy_default_behavior_proof() + prechange = _capture_snapshot(matrix) + OBSERVED_PRECHANGE.write_text( + json.dumps(prechange, indent=2, sort_keys=True) + "\n", encoding="utf-8" + ) + update = os.environ.get("UPDATE_PRECHANGE", "false").lower() == "true" + if update: + rollback_input = prechange + else: + rollback_input = cast( + "_AclSnapshot", + json.loads(EXPECTED_PRECHANGE.read_text(encoding="utf-8")), + ) + assert rollback_input == prechange, "durable pre-change ACL artifact drift" + + red = _catalog_violations(prechange, matrix) + required_red = { + "OWNER_MISMATCH", + "PUBLIC_PRIVILEGE", + "BROAD_GRANT", + "UNSAFE_DEFAULT_PRIVILEGE", + "CROSS_DOMAIN_PRIVILEGE", + "RUNTIME_ROLE_ATTRIBUTES", + "OWNER_MEMBERSHIP", + "UNDECLARED_PRINCIPAL_PRIVILEGE", + "MISSING_DECLARED_MEMBERSHIP", + "RUNTIME_OWNERSHIP", + "GRANT_OPTION", + "COLUMN_PRIVILEGE", + "DATABASE_DDL_PRIVILEGE", + } + assert required_red <= red, (required_red - red, red) + print(f"acl_phase=prechange red_controls={','.join(sorted(red))} status=DETECTED") + + _atomic_failure_proof(matrix, prechange) + for pass_number in (1, 2): + _execute_matrix(matrix) + print(f"acl_phase=apply pass={pass_number} status=PASS") + green = _capture_snapshot(matrix) + assert not _catalog_violations(green, matrix), _catalog_violations(green, matrix) + assert [row for row in green["roles"] if row["rolname"] == "rls_admin"] == [ + row for row in prechange["roles"] if row["rolname"] == "rls_admin" + ] + assert [ + row for row in green["database_owner"] if row["database_name"] != DATABASE + ] == [ + row for row in prechange["database_owner"] if row["database_name"] != DATABASE + ] + assert _capture_legacy_default_acl() == legacy_default_acl + _legacy_default_behavior_proof() + _unknown_acl_and_membership_reconciliation_proof(matrix, green) + try: + _restore_snapshot(rollback_input, matrix, inject_failure=True) + except psycopg2.errors.DivisionByZero: + pass + else: + raise AssertionError("injected rollback failure unexpectedly succeeded") + assert _capture_snapshot(matrix) == green, ( + "failed rollback leaked a partial catalog mutation" + ) + print("acl_phase=rollback_atomic_failure red_control=ROLLBACK status=PASS") + _behavioral_proof(matrix) + _migration_membership_proof() + _future_default_proof() + print("acl_phase=postgres16_readback status=PASS") + + _restore_snapshot(rollback_input, matrix) + restored = _capture_snapshot(matrix) + assert restored == prechange, "rollback did not reproduce durable pre-change ACL" + assert _capture_legacy_default_acl() == legacy_default_acl + _legacy_default_behavior_proof() + _builtin_default_rollback_proof() + print("acl_phase=rollback_round_trip status=PASS") + + for pass_number in (1, 2): + _execute_matrix(matrix) + print(f"acl_phase=reapply pass={pass_number} status=PASS") + final = _capture_snapshot(matrix) + assert not _catalog_violations(final, matrix), _catalog_violations(final, matrix) + assert _capture_legacy_default_acl() == legacy_default_acl + _legacy_default_behavior_proof() + print( + f"acl_status=PASS postgres_major={postgres_major} objects={len(matrix.objects)} " + f"rows={len(matrix.rows)} defaults={len(matrix.default_privileges)}" + ) + + +if __name__ == "__main__": + main() diff --git a/scripts/generate_application_database_acl.py b/scripts/generate_application_database_acl.py new file mode 100644 index 0000000000..cebe5b2b55 --- /dev/null +++ b/scripts/generate_application_database_acl.py @@ -0,0 +1,279 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT + +"""Generate the one-database ACL matrix from immutable Git blobs.""" + +from __future__ import annotations + +import argparse +import hashlib +import json +import subprocess +import sys +from pathlib import Path +from typing import Literal + +import yaml +from pydantic import BaseModel, ConfigDict + +from omnibase_core.models.core.model_deployment_topology import ModelDeploymentTopology +from omnibase_infra.validation.application_database_acl import ( + build_application_database_acl_matrix, + render_application_database_acl_sql, +) +from omnibase_infra.validation.enums.enum_application_database_acl_authorization_scope import ( + EnumApplicationDatabaseAclAuthorizationScope, +) +from omnibase_infra.validation.enums.enum_application_database_acl_render_phase import ( + EnumApplicationDatabaseAclRenderPhase, +) +from omnibase_infra.validation.models.model_application_database_acl_matrix import ( + ModelApplicationDatabaseAclSource, +) +from omnibase_infra.validation.models.model_application_database_acl_policy import ( + ModelApplicationDatabaseAclPolicy, +) +from omnibase_infra.validation.models.model_application_database_activity_result_evidence import ( + ModelApplicationDatabaseActivityResultEvidence, +) +from omnibase_infra.validation.models.model_application_database_catalog_result_evidence import ( + ModelApplicationDatabaseCatalogResultEvidence, +) +from omnibase_infra.validation.models.model_application_database_principal_inventory import ( + ModelApplicationDatabasePrincipalInventory, +) +from omnibase_infra.validation.models.model_application_relation_evidence_inventory import ( + ModelApplicationRelationEvidenceInventory, +) +from omnibase_infra.validation.models.model_migration_ownership_manifest import ( + ModelMigrationOwnershipManifest, +) + + +class _SourceLock(BaseModel): + model_config = ConfigDict(frozen=True, extra="forbid") + + schema_version: Literal["1.0"] + required_connect_databases: tuple[str, ...] + sources: tuple[ModelApplicationDatabaseAclSource, ...] + + +class _IndentedSafeDumper(yaml.SafeDumper): + """Match the repository YAML formatter's nested-sequence indentation.""" + + def increase_indent( + self, + flow: bool = False, + indentless: bool = False, + ) -> None: + return super().increase_indent(flow=flow, indentless=False) + + +def _parse_repository_roots(values: list[str]) -> dict[str, Path]: + result: dict[str, Path] = {} + for value in values: + repository, separator, raw_path = value.partition("=") + if not separator or not repository or not raw_path: + raise ValueError("--repository-root must be REPOSITORY=/absolute/git/clone") + root = Path(raw_path).resolve() + if not root.is_dir(): + raise ValueError(f"Repository root does not exist: {root}") + result[repository] = root + return result + + +def _git_blob(root: Path, source: ModelApplicationDatabaseAclSource) -> bytes: + result = subprocess.run( + ["git", "-C", str(root), "show", f"{source.revision}:{source.path}"], + check=False, + capture_output=True, + ) + if result.returncode != 0: + detail = result.stderr.decode("utf-8", errors="replace").strip() + raise ValueError( + f"Cannot read {source.source_key} from {source.repository}@" + f"{source.revision}: {detail}" + ) + digest = hashlib.sha256(result.stdout).hexdigest() + if digest != source.sha256: + raise ValueError( + f"Source-lock digest mismatch for {source.source_key}: " + f"expected {source.sha256}, got {digest}" + ) + return result.stdout + + +def _mapping(blob: bytes, source_id: str) -> object: + try: + if blob.lstrip().startswith((b"{", b"[")): + return json.loads(blob) + return yaml.safe_load(blob) + except (json.JSONDecodeError, yaml.YAMLError) as exc: + raise ValueError(f"Cannot parse locked source {source_id}: {exc}") from exc + + +def _write_yaml(path: Path, value: object) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text( + yaml.dump( + value, + Dumper=_IndentedSafeDumper, + default_flow_style=False, + sort_keys=True, + width=1_000_000, + ), + encoding="utf-8", + ) + + +def _parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument( + "--source-lock", + type=Path, + default=Path("docker/application-acl-proof/source-lock.yaml"), + ) + parser.add_argument( + "--repository-root", + action="append", + default=[], + metavar="REPOSITORY=PATH", + help="Local Git clone containing every locked revision (repeatable)", + ) + parser.add_argument("--matrix-output", type=Path, required=True) + parser.add_argument("--sql-output", type=Path) + parser.add_argument( + "--render-phase", + type=EnumApplicationDatabaseAclRenderPhase, + choices=tuple(EnumApplicationDatabaseAclRenderPhase), + default=EnumApplicationDatabaseAclRenderPhase.FULL, + help="Render the additive scaffold before full object materialization", + ) + parser.add_argument( + "--allow-blocked-matrix", + action="store_true", + help="Write candidate evidence but never SQL when dependencies are incomplete", + ) + return parser.parse_args() + + +def main() -> int: + args = _parse_args() + lock = _SourceLock.model_validate( + yaml.safe_load(args.source_lock.read_text(encoding="utf-8")) + ) + roots = _parse_repository_roots(args.repository_root) + missing_roots = sorted( + {source.repository for source in lock.sources} - roots.keys() + ) + if missing_roots: + raise ValueError(f"Missing --repository-root values: {missing_roots!r}") + + blobs = { + source.source_key: _git_blob(roots[source.repository], source) + for source in lock.sources + } + topology_sources = [ + source for source in lock.sources if source.purpose == "topology" + ] + if len(topology_sources) != 1: + raise ValueError("Source lock must contain exactly one topology source") + topology_source = topology_sources[0] + topology = ModelDeploymentTopology.model_validate( + _mapping(blobs[topology_source.source_key], topology_source.source_key) + ) + inventories = { + source.source_key: ModelApplicationRelationEvidenceInventory.model_validate( + _mapping(blobs[source.source_key], source.source_key) + ) + for source in lock.sources + if source.purpose == "relation_inventory" + } + manifests = { + source.source_key: ModelMigrationOwnershipManifest.model_validate( + _mapping(blobs[source.source_key], source.source_key) + ) + for source in lock.sources + if source.purpose == "service_ownership" + } + principal_inventories = { + source.source_key: ModelApplicationDatabasePrincipalInventory.model_validate( + _mapping(blobs[source.source_key], source.source_key) + ) + for source in lock.sources + if source.purpose == "principal_inventory" + } + catalog_results = { + source.source_key: ModelApplicationDatabaseCatalogResultEvidence.model_validate( + _mapping(blobs[source.source_key], source.source_key) + ) + for source in lock.sources + if source.purpose == "catalog_result_evidence" + } + activity_results = { + source.source_key: ModelApplicationDatabaseActivityResultEvidence.model_validate( + _mapping(blobs[source.source_key], source.source_key) + ) + for source in lock.sources + if source.purpose == "activity_result_evidence" + } + acl_policies = { + source.source_key: ModelApplicationDatabaseAclPolicy.model_validate( + _mapping(blobs[source.source_key], source.source_key) + ) + for source in lock.sources + if source.purpose == "acl_policy" + } + matrix = build_application_database_acl_matrix( + topology=topology, + sources=lock.sources, + relation_inventories=inventories, + service_manifests=manifests, + principal_inventories=principal_inventories, + acl_policies=acl_policies, + authorization_scope=EnumApplicationDatabaseAclAuthorizationScope.DEPLOYMENT, + required_connect_databases=lock.required_connect_databases, + catalog_results=catalog_results, + activity_results=activity_results, + ) + _write_yaml(args.matrix_output, matrix.model_dump(mode="json")) + print( + f"matrix_status={matrix.status} scaffold_status={matrix.scaffold_status} " + f"objects={len(matrix.objects)} " + f"rows={len(matrix.rows)} defaults={len(matrix.default_privileges)} " + f"blockers={len(matrix.blockers)} " + f"scaffold_blockers={len(matrix.scaffold_blockers)}" + ) + phase_blocked = ( + matrix.status == "BLOCKED" + if args.render_phase is EnumApplicationDatabaseAclRenderPhase.FULL + else matrix.scaffold_status == "BLOCKED" + ) + phase_blockers = ( + matrix.blockers + if args.render_phase is EnumApplicationDatabaseAclRenderPhase.FULL + else matrix.scaffold_blockers + ) + if phase_blocked: + for blocker in phase_blockers: + print(f"blocker={blocker}") + if args.sql_output is not None and args.sql_output.exists(): + raise ValueError( + "Refusing to overwrite an existing SQL output from a blocked phase" + ) + return 0 if args.allow_blocked_matrix else 2 + if args.sql_output is not None: + args.sql_output.parent.mkdir(parents=True, exist_ok=True) + args.sql_output.write_text( + render_application_database_acl_sql(matrix, phase=args.render_phase), + encoding="utf-8", + ) + return 0 + + +if __name__ == "__main__": + try: + raise SystemExit(main()) + except (OSError, ValueError) as exc: + print(f"application ACL generation failed: {exc}", file=sys.stderr) + raise SystemExit(1) from exc diff --git a/src/omnibase_infra/validation/application_database_acl.py b/src/omnibase_infra/validation/application_database_acl.py new file mode 100644 index 0000000000..3715112c0a --- /dev/null +++ b/src/omnibase_infra/validation/application_database_acl.py @@ -0,0 +1,3661 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT + +"""Generate and validate explicit application-database ACL matrices. + +The matrix is a projection. Deployment topology owns role/database/schema and +explicit object grants; typed relation inventories and service manifests own the +object set and access evidence. No table name or PostgreSQL role allowlist is +maintained here. +""" + +from __future__ import annotations + +import re +from collections import Counter, defaultdict +from collections.abc import Mapping, Sequence +from dataclasses import dataclass +from typing import Protocol + +from omnibase_core.enums.enum_database_grant_object_type import ( + EnumDatabaseGrantObjectType, +) +from omnibase_core.enums.enum_database_privilege import EnumDatabasePrivilege +from omnibase_core.enums.enum_database_schema_domain import EnumDatabaseSchemaDomain +from omnibase_core.models.contracts.subcontracts.model_db_table_declaration import ( + ModelDbTableDeclaration, +) +from omnibase_core.models.core.model_deployment_topology import ModelDeploymentTopology +from omnibase_infra.validation.enums.enum_application_database_acl_authorization_scope import ( + EnumApplicationDatabaseAclAuthorizationScope, +) +from omnibase_infra.validation.enums.enum_application_database_acl_policy_source_kind import ( + EnumApplicationDatabaseAclPolicySourceKind, +) +from omnibase_infra.validation.enums.enum_application_database_acl_render_phase import ( + EnumApplicationDatabaseAclRenderPhase, +) +from omnibase_infra.validation.enums.enum_application_database_object_kind import ( + EnumApplicationDatabaseObjectKind, +) +from omnibase_infra.validation.enums.enum_application_database_principal_inventory_source_kind import ( + EnumApplicationDatabasePrincipalInventorySourceKind, +) +from omnibase_infra.validation.enums.enum_application_inventory_object_kind import ( + EnumApplicationInventoryObjectKind, +) +from omnibase_infra.validation.enums.enum_application_relation_kind import ( + EnumApplicationRelationKind, +) +from omnibase_infra.validation.models.model_application_database_acl_matrix import ( + ModelApplicationDatabaseAclMatrix, + ModelApplicationDatabaseAclObject, + ModelApplicationDatabaseAclRow, + ModelApplicationDatabaseAclSource, + ModelApplicationDatabaseDefaultAclRow, +) +from omnibase_infra.validation.models.model_application_database_acl_policy import ( + ModelApplicationDatabaseAclPolicy, +) +from omnibase_infra.validation.models.model_application_database_activity_result_evidence import ( + ModelApplicationDatabaseActivityResultEvidence, +) +from omnibase_infra.validation.models.model_application_database_catalog_object_evidence import ( + ModelApplicationDatabaseCatalogObjectEvidence, +) +from omnibase_infra.validation.models.model_application_database_catalog_result_evidence import ( + ModelApplicationDatabaseCatalogResultEvidence, +) +from omnibase_infra.validation.models.model_application_database_connection_policy import ( + ModelApplicationDatabaseConnectionPolicy, +) +from omnibase_infra.validation.models.model_application_database_observed_role_state import ( + ModelApplicationDatabaseObservedRoleState, +) +from omnibase_infra.validation.models.model_application_database_principal_inventory import ( + ModelApplicationDatabasePrincipalInventory, +) +from omnibase_infra.validation.models.model_application_database_role_membership import ( + ModelApplicationDatabaseRoleMembership, +) +from omnibase_infra.validation.models.model_application_database_role_state import ( + ModelApplicationDatabaseRoleState, +) +from omnibase_infra.validation.models.model_application_relation_evidence_inventory import ( + ModelApplicationRelationEvidenceInventory, +) +from omnibase_infra.validation.models.model_migration_ownership_manifest import ( + ModelMigrationOwnershipManifest, +) + +PUBLIC_PRINCIPAL = "PUBLIC" +_SQL_IDENTIFIER = re.compile(r"^[a-z_][a-z0-9_]*$") +_READY_STATUSES = frozenset({"complete", "pass", "passed", "verified"}) +_OBJECT_TYPES = ( + EnumDatabaseGrantObjectType.TABLE, + EnumDatabaseGrantObjectType.SEQUENCE, + EnumDatabaseGrantObjectType.FUNCTION, + EnumDatabaseGrantObjectType.TYPE, +) +_DEPLOYMENT_CONNECT_DATABASES = frozenset( + { + "keycloak", + "omnibase_infra", + "omnidash_analytics", + "omninode_cloud", + "omniclaude", + "omniintelligence", + "omnimemory", + "umami", + } +) + + +@dataclass +class ObjectEvidence: + obj: ModelApplicationDatabaseAclObject + + +class ProtocolApplicationDatabaseRoleAttributeState(Protocol): + """Structural shape shared by observed and governed PostgreSQL role state.""" + + @property + def login(self) -> bool: ... + + @property + def superuser(self) -> bool: ... + + @property + def bypass_rls(self) -> bool: ... + + @property + def create_database(self) -> bool: ... + + @property + def create_role(self) -> bool: ... + + @property + def replication(self) -> bool: ... + + @property + def inherit(self) -> bool: ... + + +def _status_is_ready(status: str | None) -> bool: + return status is not None and status.strip().lower() in _READY_STATUSES + + +def _role_attribute_values( + state: ProtocolApplicationDatabaseRoleAttributeState, +) -> tuple[bool, ...]: + """Return the security-relevant PostgreSQL role attributes in stable order.""" + return ( + state.login, + state.superuser, + state.bypass_rls, + state.create_database, + state.create_role, + state.replication, + state.inherit, + ) + + +def validate_application_database_principal_evidence( + inventory: ModelApplicationDatabasePrincipalInventory, + catalog_result: ModelApplicationDatabaseCatalogResultEvidence, + activity_result: ModelApplicationDatabaseActivityResultEvidence, +) -> tuple[str, ...]: + """Bind inventory authorization fields to parsed immutable result content.""" + violations: list[str] = [] + for field_name in ( + "database_ref", + "physical_database", + "completion_status", + "catalog_parity_status", + "catalog_query_sha256", + "database_owner_role", + ): + inventory_field = ( + inventory.catalog_query_sha256 + if field_name == "catalog_query_sha256" + else getattr(inventory, field_name) + ) + if getattr(catalog_result, field_name) != inventory_field: + violations.append(f"catalog result {field_name} disagrees with inventory") + for field_name in ( + "principal_refs", + "absent_principal_refs", + "owner_refs", + "absent_owner_refs", + "absent_schema_refs", + ): + if set(getattr(catalog_result, field_name)) != set( + getattr(inventory, field_name) + ): + violations.append(f"catalog result {field_name} disagrees with inventory") + inventory_role_states = { + state.role: state.model_dump(mode="json") + for state in inventory.observed_role_states + } + result_role_states = { + state.role: state.model_dump(mode="json") + for state in catalog_result.observed_role_states + } + if result_role_states != inventory_role_states: + violations.append( + "catalog result observed_role_states disagrees with inventory" + ) + if catalog_result.observed_schema_owners != inventory.observed_schema_owners: + violations.append( + "catalog result observed_schema_owners disagrees with inventory" + ) + inventory_objects = { + obj.identity: obj.model_dump(mode="json") for obj in inventory.observed_objects + } + result_objects = { + obj.identity: obj.model_dump(mode="json") + for obj in catalog_result.observed_objects + } + if result_objects != inventory_objects: + violations.append("catalog result observed_objects disagrees with inventory") + activity = inventory.activity_evidence + if activity is None: + violations.append("inventory lacks activity evidence") + else: + for field_name, expected in ( + ("database_ref", inventory.database_ref), + ("physical_database", inventory.physical_database), + ("window_started_at", activity.window_started_at), + ("window_ended_at", activity.window_ended_at), + ("activity_query_sha256", activity.query_sha256), + ("observation_count", activity.observation_count), + ): + if getattr(activity_result, field_name) != expected: + violations.append( + f"activity result {field_name} disagrees with inventory" + ) + result_activity_principals = { + row.principal for row in activity_result.active_principals + } + if result_activity_principals != set(inventory.activity_principal_refs): + violations.append( + "activity result active principals disagree with inventory" + ) + return tuple(sorted(set(violations))) + + +def _schema_for_domain( + *, + topology: ModelDeploymentTopology, + database_ref: str, + domain: EnumDatabaseSchemaDomain, +) -> str: + database = topology.databases[database_ref] + matches = [ + name for name, schema in database.schemas.items() if schema.domain is domain + ] + if len(matches) != 1: + raise ValueError( + f"database_ref {database_ref!r} must resolve domain {domain.value!r} " + f"to exactly one schema, got {sorted(matches)!r}" + ) + return matches[0] + + +def _object_type_from_inventory( + kind: EnumApplicationInventoryObjectKind, +) -> EnumDatabaseGrantObjectType | None: + if kind in { + EnumApplicationInventoryObjectKind.TABLE, + EnumApplicationInventoryObjectKind.VIEW, + EnumApplicationInventoryObjectKind.MATERIALIZED_VIEW, + }: + return EnumDatabaseGrantObjectType.TABLE + if kind is EnumApplicationInventoryObjectKind.SEQUENCE: + return EnumDatabaseGrantObjectType.SEQUENCE + if kind in { + EnumApplicationInventoryObjectKind.FUNCTION, + EnumApplicationInventoryObjectKind.PROCEDURE, + }: + return EnumDatabaseGrantObjectType.FUNCTION + if kind is EnumApplicationInventoryObjectKind.TYPE: + return EnumDatabaseGrantObjectType.TYPE + return None + + +def _catalog_kind_from_inventory( + kind: EnumApplicationInventoryObjectKind, +) -> str: + return kind.value + + +def _object_type_from_service( + kind: EnumApplicationDatabaseObjectKind, +) -> EnumDatabaseGrantObjectType | None: + if kind is EnumApplicationDatabaseObjectKind.SEQUENCE: + return EnumDatabaseGrantObjectType.SEQUENCE + if kind in { + EnumApplicationDatabaseObjectKind.FUNCTION, + EnumApplicationDatabaseObjectKind.PROCEDURE, + }: + return EnumDatabaseGrantObjectType.FUNCTION + if kind is EnumApplicationDatabaseObjectKind.TYPE: + return EnumDatabaseGrantObjectType.TYPE + return None + + +def _source_status_blockers( + source_id: str, + inventory: ModelApplicationRelationEvidenceInventory, +) -> list[str]: + blockers: list[str] = [] + if inventory.relation_counts.type is None: + blockers.append( + f"{source_id}: relation_counts.type is not inventoried; " + "zero user-defined types cannot be inferred" + ) + if inventory.relation_counts.procedure is None: + blockers.append( + f"{source_id}: relation_counts.procedure is not inventoried; " + "zero procedures cannot be inferred" + ) + if not _status_is_ready(inventory.completion_status): + blockers.append( + f"{source_id}: completion_status={inventory.completion_status!r}" + ) + census = inventory.retained_live_census + typed_kind_counts = Counter(relation.kind.value for relation in inventory.relations) + expected_census_counts = { + "observed_base_tables": typed_kind_counts.get("table", 0), + "observed_views_and_materialized_views": ( + typed_kind_counts.get("view", 0) + + typed_kind_counts.get("materialized_view", 0) + ), + "observed_sequences": typed_kind_counts.get("sequence", 0), + "observed_functions": typed_kind_counts.get("function", 0), + "observed_procedures": typed_kind_counts.get("procedure", 0), + "observed_types": typed_kind_counts.get("type", 0), + "observed_extensions": typed_kind_counts.get("extension", 0), + } + for field_name in ( + "observed_base_tables", + "observed_views_and_materialized_views", + "observed_sequences", + "observed_functions", + "observed_procedures", + "observed_types", + "observed_extensions", + ): + live_count = getattr(census, field_name) + if live_count is None: + blockers.append( + f"{source_id}: retained_live_census.{field_name} is not inventoried" + ) + elif live_count != expected_census_counts[field_name]: + blockers.append( + f"{source_id}: retained_live_census.{field_name}={live_count} " + "does not match exact typed rows=" + f"{expected_census_counts[field_name]}" + ) + if not _status_is_ready(census.parity_status): + blockers.append( + f"{source_id}: retained_live_census={census.parity_status!r}: " + f"{census.reason or 'no reason supplied'}" + ) + for evidence_name in ( + "full_day_datname_usename_activity", + "live_catalog_parity", + ): + status = getattr(inventory.runtime_evidence, evidence_name) + if not _status_is_ready(status.status): + blockers.append( + f"{source_id}: runtime_evidence.{evidence_name}=" + f"{status.status.value!r}: " + f"{status.reason or 'no reason supplied'}" + ) + blockers.extend( + f"{source_id}: blocked {blocked.kind} {blocked.name!r}: {blocked.reason}" + for blocked in inventory.blocked_relations + ) + return blockers + + +def _service_status_blockers( + source_id: str, + manifest: ModelMigrationOwnershipManifest, +) -> list[str]: + blockers: list[str] = [] + if not manifest.completion_status: + blockers.append(f"{source_id}: completion_status is missing") + elif not _status_is_ready(manifest.completion_status): + blockers.append( + f"{source_id}: completion_status={manifest.completion_status!r}" + ) + if manifest.retained_live_census is None: + blockers.append(f"{source_id}: retained_live_census is missing") + else: + census = manifest.retained_live_census + relation_counts = Counter( + relation.kind.value for relation in manifest.relation_evidence + ) + object_counts = Counter( + database_object.kind.value for database_object in manifest.database_objects + ) + expected_counts = { + "observed_base_tables": relation_counts.get("table", 0), + "observed_views_and_materialized_views": ( + relation_counts.get("view", 0) + + relation_counts.get("materialized_view", 0) + ), + "observed_sequences": object_counts.get("sequence", 0), + "observed_functions": object_counts.get("function", 0), + "observed_procedures": object_counts.get("procedure", 0), + "observed_types": object_counts.get("type", 0), + "observed_extensions": object_counts.get("extension", 0), + } + for field_name, typed_count in expected_counts.items(): + live_count = getattr(census, field_name) + if live_count is None: + blockers.append( + f"{source_id}: retained_live_census.{field_name} is missing" + ) + elif live_count != typed_count: + blockers.append( + f"{source_id}: retained_live_census.{field_name}={live_count} " + f"does not match exact typed rows={typed_count}" + ) + census_status = census.parity_status + if not _status_is_ready(census_status): + blockers.append( + f"{source_id}: retained_live_census={census_status!r}: " + f"{census.reason or 'no reason supplied'}" + ) + required_runtime_evidence = { + "full_day_datname_usename_activity", + "live_catalog_parity", + } + missing_runtime_evidence = sorted( + required_runtime_evidence - manifest.runtime_evidence.keys() + ) + if missing_runtime_evidence: + blockers.append( + f"{source_id}: required runtime_evidence is missing " + f"{missing_runtime_evidence!r}" + ) + for evidence_name, runtime_status in sorted(manifest.runtime_evidence.items()): + if not _status_is_ready(runtime_status.status): + blockers.append( + f"{source_id}: runtime_evidence.{evidence_name}=" + f"{runtime_status.status.value!r}: " + f"{runtime_status.reason or 'no reason supplied'}" + ) + blockers.extend( + f"{source_id}: blocked {blocked.kind} {blocked.name!r}: {blocked.reason}" + for blocked in manifest.blocked_relations + ) + return blockers + + +def _merge_object( + objects: dict[ + tuple[str, str, EnumDatabaseGrantObjectType, str, str | None], + ObjectEvidence, + ], + evidence: ObjectEvidence, + blockers: list[str], +) -> None: + identity = evidence.obj.identity + existing = objects.get(identity) + if existing is None: + objects[identity] = evidence + return + blockers.append( + f"duplicate authoritative ownership declaration for {identity!r}: " + f"{existing.obj.owner_declaration!r} from {existing.obj.source_keys!r} vs " + f"{evidence.obj.owner_declaration!r} from {evidence.obj.source_keys!r}" + ) + + +def _append_inventory_objects( + *, + topology: ModelDeploymentTopology, + source_id: str, + inventory: ModelApplicationRelationEvidenceInventory, + objects: dict[ + tuple[str, str, EnumDatabaseGrantObjectType, str, str | None], + ObjectEvidence, + ], + blockers: list[str], + excluded: list[str], +) -> None: + database = topology.databases.get(inventory.database_ref) + if database is None: + blockers.append(f"{source_id}: unknown database_ref {inventory.database_ref!r}") + return + if database.physical_name != inventory.physical_seed_database: + blockers.append( + f"{source_id}: physical database drift: topology=" + f"{database.physical_name!r}, inventory=" + f"{inventory.physical_seed_database!r}" + ) + for relation in inventory.relations: + object_type = _object_type_from_inventory(relation.kind) + if object_type is None: + excluded.append( + f"{source_id}:{relation.target_schema}.{relation.name}:" + f"{relation.kind.value}" + ) + continue + if relation.target_schema not in database.schemas: + blockers.append( + f"{source_id}: object {relation.name!r} uses unknown schema " + f"{relation.target_schema!r}" + ) + continue + domain = database.schemas[relation.target_schema].domain + if relation.domain is None or relation.domain is not domain: + blockers.append( + f"{source_id}: object {relation.name!r} domain does not match " + f"topology schema {relation.target_schema!r}" + ) + if relation.classification_status.strip().lower() != "classified": + blockers.append( + f"{source_id}: object {relation.name!r} classification_status=" + f"{relation.classification_status!r}" + ) + if relation.target_schema not in relation.current_schema: + blockers.append( + f"{source_id}: object {relation.name!r} is currently in schemas " + f"{sorted(relation.current_schema)!r}, not the target schema " + f"{relation.target_schema!r}; full object ACL rendering is gated " + "until the additive target object is materialized and inventoried" + ) + for reason in relation.blocked_reasons: + blockers.append(f"{source_id}: object {relation.name!r} blocked: {reason}") + if relation.owner_declaration is None: + blockers.append( + f"{source_id}: object {relation.name!r} lacks an exact " + "owner_declaration" + ) + continue + owner = database.schemas[relation.target_schema].owner + _merge_object( + objects, + ObjectEvidence( + obj=ModelApplicationDatabaseAclObject( + database_ref=inventory.database_ref, + physical_database=database.physical_name, + schema_ref=relation.target_schema, + domain=domain, + object_type=object_type, + object_ref=relation.name, + catalog_kind=_catalog_kind_from_inventory(relation.kind), + owner=owner, + owner_declaration=relation.owner_declaration, + target_materialized=( + inventory.physical_seed_database == database.physical_name + and relation.target_schema in relation.current_schema + ), + function_signature=relation.function_signature, + source_keys=(source_id,), + ), + ), + blockers, + ) + + +def _append_service_objects( + *, + topology: ModelDeploymentTopology, + source_id: str, + manifest: ModelMigrationOwnershipManifest, + objects: dict[ + tuple[str, str, EnumDatabaseGrantObjectType, str, str | None], + ObjectEvidence, + ], + blockers: list[str], + excluded: list[str], +) -> None: + database = topology.databases.get(manifest.target_database_ref) + if database is None: + blockers.append( + f"{source_id}: unknown database_ref {manifest.target_database_ref!r}" + ) + return + if manifest.current_physical_database is None: + blockers.append(f"{source_id}: current_physical_database is not inventoried") + if database.physical_name not in manifest.materialized_physical_databases: + blockers.append( + f"{source_id}: target physical database {database.physical_name!r} is " + "absent from materialized_physical_databases; full object ACL rendering " + "is gated until the additive target is inventoried" + ) + tables_by_name: dict[str, list[ModelDbTableDeclaration]] = defaultdict(list) + for table in manifest.db_io.db_tables: + tables_by_name[table.name].append(table) + covered_table_identities: set[tuple[str, str, str]] = set() + for relation in manifest.relation_evidence: + if relation.kind is EnumApplicationRelationKind.FUNCTION: + blockers.append( + f"{source_id}: function relation_evidence {relation.name!r} requires " + "exact database_objects evidence including a routine signature" + ) + continue + schema_name: str | None + database_ref: str + if relation.kind is EnumApplicationRelationKind.TABLE: + matching_tables = tables_by_name.get(relation.name, []) + if relation.database_ref is not None: + matching_tables = [ + table + for table in matching_tables + if table.database_ref == relation.database_ref + ] + if relation.schema is not None: + matching_tables = [ + table + for table in matching_tables + if table.schema == relation.schema + ] + if len(matching_tables) != 1: + blockers.append( + f"{source_id}: table relation_evidence {relation.name!r} must " + "match exactly one db_io.db_tables declaration, got " + f"{[(table.database_ref, table.schema, table.name) for table in matching_tables]!r}" + ) + continue + table = matching_tables[0] + schema_name = relation.schema or table.schema + database_ref = relation.database_ref or table.database_ref + covered_table_identities.add((table.database_ref, table.schema, table.name)) + else: + schema_name = relation.schema + database_ref = relation.database_ref or manifest.target_database_ref + if schema_name is None: + try: + schema_name = _schema_for_domain( + topology=topology, + database_ref=database_ref, + domain=relation.domain, + ) + except (KeyError, ValueError) as exc: + blockers.append(f"{source_id}: {relation.name!r}: {exc}") + continue + if database_ref != manifest.target_database_ref: + blockers.append( + f"{source_id}: object {relation.name!r} database_ref " + f"{database_ref!r} conflicts with manifest target" + ) + continue + if schema_name not in database.schemas: + blockers.append( + f"{source_id}: object {relation.name!r} uses unknown schema " + f"{schema_name!r}" + ) + continue + if schema_name not in relation.current_schemas: + blockers.append( + f"{source_id}: object {relation.name!r} current_schemas=" + f"{relation.current_schemas!r} do not prove target schema " + f"{schema_name!r}; full object ACL rendering is gated" + ) + topology_domain = database.schemas[schema_name].domain + if relation.domain is not topology_domain: + blockers.append( + f"{source_id}: object {relation.name!r} domain does not match " + f"topology schema {schema_name!r}" + ) + _merge_object( + objects, + ObjectEvidence( + obj=ModelApplicationDatabaseAclObject( + database_ref=database_ref, + physical_database=database.physical_name, + schema_ref=schema_name, + domain=topology_domain, + object_type=EnumDatabaseGrantObjectType.TABLE, + object_ref=relation.name, + catalog_kind=relation.kind.value, + owner=database.schemas[schema_name].owner, + owner_declaration=relation.owner_declaration, + target_materialized=( + database.physical_name + in manifest.materialized_physical_databases + and schema_name in relation.current_schemas + ), + source_keys=(source_id,), + ), + ), + blockers, + ) + + for table in manifest.db_io.db_tables: + table_identity = (table.database_ref, table.schema, table.name) + if table_identity not in covered_table_identities: + blockers.append( + f"{source_id}: db_io table {table.database_ref}." + f"{table.schema}.{table.name} lacks exact relation_evidence" + ) + + for database_object in manifest.database_objects: + object_type = _object_type_from_service(database_object.kind) + if object_type is None: + excluded.append( + f"{source_id}:{database_object.name}:{database_object.kind.value}" + ) + continue + database_ref = database_object.database_ref or manifest.target_database_ref + try: + schema_name = database_object.schema or _schema_for_domain( + topology=topology, + database_ref=database_ref, + domain=database_object.domain, + ) + except (KeyError, ValueError) as exc: + blockers.append(f"{source_id}: {database_object.name!r}: {exc}") + continue + if database_ref != manifest.target_database_ref: + blockers.append( + f"{source_id}: object {database_object.name!r} database_ref " + f"{database_ref!r} conflicts with manifest target" + ) + continue + topology_domain = database.schemas[schema_name].domain + if database_object.domain is not topology_domain: + blockers.append( + f"{source_id}: object {database_object.name!r} domain does not " + f"match topology schema {schema_name!r}" + ) + if schema_name not in database_object.current_schemas: + blockers.append( + f"{source_id}: object {database_object.name!r} current_schemas=" + f"{database_object.current_schemas!r} do not prove target schema " + f"{schema_name!r}; full object ACL rendering is gated" + ) + _merge_object( + objects, + ObjectEvidence( + obj=ModelApplicationDatabaseAclObject( + database_ref=database_ref, + physical_database=database.physical_name, + schema_ref=schema_name, + domain=topology_domain, + object_type=object_type, + object_ref=database_object.name, + catalog_kind=database_object.kind.value, + owner=database.schemas[schema_name].owner, + owner_declaration=database_object.owner_declaration, + target_materialized=( + database.physical_name + in manifest.materialized_physical_databases + and schema_name in database_object.current_schemas + ), + function_signature=database_object.function_signature, + source_keys=(source_id,), + ), + ), + blockers, + ) + + +def _topology_privileges( + topology: ModelDeploymentTopology, +) -> dict[ + tuple[ + str, + str, + EnumDatabaseGrantObjectType, + str | None, + str | None, + ], + set[EnumDatabasePrivilege], +]: + result: dict[ + tuple[ + str, + str, + EnumDatabaseGrantObjectType, + str | None, + str | None, + ], + set[EnumDatabasePrivilege], + ] = defaultdict(set) + for database_ref, database in topology.databases.items(): + for principal_name, principal in database.principals.items(): + for grant in principal.grants: + if grant.object_type in { + EnumDatabaseGrantObjectType.DATABASE, + EnumDatabaseGrantObjectType.SCHEMA, + }: + scope_key: tuple[ + str, + str, + EnumDatabaseGrantObjectType, + str | None, + str | None, + ] = ( + principal_name, + database_ref, + grant.object_type, + grant.schema, + None, + ) + result[scope_key].update(grant.privileges) + continue + for object_name in grant.objects: + object_key: tuple[ + str, + str, + EnumDatabaseGrantObjectType, + str | None, + str | None, + ] = ( + principal_name, + database_ref, + grant.object_type, + grant.schema, + object_name, + ) + result[object_key].update(grant.privileges) + return result + + +def build_application_database_acl_matrix( + *, + topology: ModelDeploymentTopology, + sources: Sequence[ModelApplicationDatabaseAclSource], + relation_inventories: Mapping[str, ModelApplicationRelationEvidenceInventory], + service_manifests: Mapping[str, ModelMigrationOwnershipManifest], + principal_inventories: Mapping[str, ModelApplicationDatabasePrincipalInventory], + acl_policies: Mapping[str, ModelApplicationDatabaseAclPolicy], + authorization_scope: EnumApplicationDatabaseAclAuthorizationScope, + required_connect_databases: Sequence[str] | None = None, + catalog_results: Mapping[ + str, + ModelApplicationDatabaseCatalogResultEvidence, + ] + | None = None, + activity_results: Mapping[ + str, + ModelApplicationDatabaseActivityResultEvidence, + ] + | None = None, +) -> ModelApplicationDatabaseAclMatrix: + """Build a complete cell matrix without inventing missing grants.""" + source_ids = {source.source_key for source in sources} + if len(source_ids) != len(sources): + raise ValueError("Matrix source keys must be unique") + source_by_key = {source.source_key: source for source in sources} + parsed_catalog_results = dict(catalog_results or {}) + parsed_activity_results = dict(activity_results or {}) + unknown_result_sources = sorted( + set(parsed_catalog_results).union(parsed_activity_results) - source_ids + ) + if unknown_result_sources: + raise ValueError( + "Parsed evidence keys are absent from source records: " + f"{unknown_result_sources!r}" + ) + invalid_catalog_sources = sorted( + source_key + for source_key in parsed_catalog_results + if source_by_key[source_key].purpose != "catalog_result_evidence" + ) + invalid_activity_sources = sorted( + source_key + for source_key in parsed_activity_results + if source_by_key[source_key].purpose != "activity_result_evidence" + ) + if invalid_catalog_sources or invalid_activity_sources: + raise ValueError( + "Parsed evidence source purposes disagree: " + f"catalog={invalid_catalog_sources!r} activity={invalid_activity_sources!r}" + ) + verified_evidence: set[str] = set() + missing_source_ids = sorted( + ( + set(relation_inventories) + | set(service_manifests) + | set(principal_inventories) + | set(acl_policies) + ) + - source_ids + ) + if missing_source_ids: + raise ValueError(f"Matrix inputs lack source records: {missing_source_ids!r}") + + blockers: list[str] = [] + object_blockers: list[str] = [] + if required_connect_databases is None: + if ( + authorization_scope + is EnumApplicationDatabaseAclAuthorizationScope.DEPLOYMENT + ): + blockers.append( + "deployment authorization requires the explicit eight-database " + "CONNECT inventory" + ) + required_connect_values: Sequence[str] = () + else: + required_connect_values = tuple( + database.physical_name for database in topology.databases.values() + ) + else: + required_connect_values = required_connect_databases + required_connect = tuple(sorted(required_connect_values)) + if ( + authorization_scope is EnumApplicationDatabaseAclAuthorizationScope.DEPLOYMENT + and set(required_connect) != _DEPLOYMENT_CONNECT_DATABASES + ): + blockers.append( + "deployment CONNECT database universe disagrees with the approved " + f"eight-database scope: missing=" + f"{sorted(_DEPLOYMENT_CONNECT_DATABASES - set(required_connect))!r} " + f"extra={sorted(set(required_connect) - _DEPLOYMENT_CONNECT_DATABASES)!r}" + ) + if len(set(required_connect)) != len(required_connect): + blockers.append("required CONNECT database names must be unique") + topology_sources = { + source.source_key for source in sources if source.purpose == "topology" + } + if len(topology_sources) != 1: + blockers.append( + "matrix requires exactly one topology source, got " + f"{sorted(topology_sources)!r}" + ) + declared_relation_sources = { + source.source_key + for source in sources + if source.purpose == "relation_inventory" + } + declared_service_sources = { + source.source_key for source in sources if source.purpose == "service_ownership" + } + declared_principal_sources = { + source.source_key + for source in sources + if source.purpose == "principal_inventory" + } + declared_policy_sources = { + source.source_key for source in sources if source.purpose == "acl_policy" + } + declared_ownership_sources = declared_relation_sources.union( + declared_service_sources + ) + if not declared_ownership_sources: + object_blockers.append( + "matrix requires at least one typed ownership evidence source" + ) + missing_relation_inputs = sorted( + declared_relation_sources - relation_inventories.keys() + ) + if missing_relation_inputs: + object_blockers.append( + "declared relation_inventory sources were not parsed: " + f"{missing_relation_inputs!r}" + ) + missing_service_inputs = sorted(declared_service_sources - service_manifests.keys()) + if missing_service_inputs: + object_blockers.append( + "declared service_ownership sources were not parsed: " + f"{missing_service_inputs!r}" + ) + if not declared_principal_sources: + blockers.append( + "matrix requires a typed principal_inventory source for every database" + ) + missing_principal_inputs = sorted( + declared_principal_sources - principal_inventories.keys() + ) + if missing_principal_inputs: + blockers.append( + "declared principal_inventory sources were not parsed: " + f"{missing_principal_inputs!r}" + ) + if not declared_policy_sources: + blockers.append( + "matrix requires an independent typed acl_policy source for every database" + ) + missing_policy_inputs = sorted(declared_policy_sources - acl_policies.keys()) + if missing_policy_inputs: + blockers.append( + f"declared acl_policy sources were not parsed: {missing_policy_inputs!r}" + ) + excluded: list[str] = [] + objects: dict[ + tuple[str, str, EnumDatabaseGrantObjectType, str, str | None], + ObjectEvidence, + ] = {} + for source_id, inventory in sorted(relation_inventories.items()): + object_blockers.extend(_source_status_blockers(source_id, inventory)) + _append_inventory_objects( + topology=topology, + source_id=source_id, + inventory=inventory, + objects=objects, + blockers=object_blockers, + excluded=excluded, + ) + for source_id, manifest in sorted(service_manifests.items()): + object_blockers.extend(_service_status_blockers(source_id, manifest)) + _append_service_objects( + topology=topology, + source_id=source_id, + manifest=manifest, + objects=objects, + blockers=object_blockers, + excluded=excluded, + ) + topology_privileges = _topology_privileges(topology) + object_identities_by_topology_target: dict[ + tuple[str, str, EnumDatabaseGrantObjectType, str], + list[tuple[str, str, EnumDatabaseGrantObjectType, str, str | None]], + ] = defaultdict(list) + for identity in objects: + object_identities_by_topology_target[identity[:4]].append(identity) + resolved_object_privileges: dict[ + tuple[ + str, + str, + EnumDatabaseGrantObjectType, + str, + str, + str | None, + ], + set[EnumDatabasePrivilege], + ] = defaultdict(set) + explicit_object_grants = { + key: privileges + for key, privileges in topology_privileges.items() + if key[2] in _OBJECT_TYPES and privileges + } + if objects and not explicit_object_grants: + object_blockers.append( + "topology declares zero explicit object grants for " + f"{len(objects)} typed ownership objects" + ) + for key, privileges in sorted( + topology_privileges.items(), key=lambda item: tuple(str(x) for x in item[0]) + ): + principal, database_ref, object_type, schema_name, object_name = key + if object_type not in _OBJECT_TYPES: + continue + topology_target = ( + database_ref, + schema_name or "", + object_type, + object_name or "", + ) + matching_identities = object_identities_by_topology_target.get( + topology_target, [] + ) + if not matching_identities: + object_blockers.append( + f"topology grant {principal}:{object_type.value}:" + f"{schema_name}.{object_name} targets no typed ownership object " + f"({sorted(privilege.value for privilege in privileges)!r})" + ) + elif len(matching_identities) > 1: + signatures = sorted( + identity[4] or "" for identity in matching_identities + ) + object_blockers.append( + f"topology grant {principal}:{object_type.value}:" + f"{schema_name}.{object_name} is ambiguous across exact object " + f"identities {signatures!r}; overload-specific targeting is required" + ) + else: + exact_identity = matching_identities[0] + resolved_object_privileges[ + ( + principal, + exact_identity[0], + exact_identity[2], + exact_identity[1], + exact_identity[3], + exact_identity[4], + ) + ].update(privileges) + + for evidence in objects.values(): + obj = evidence.obj + if ( + obj.object_type is EnumDatabaseGrantObjectType.FUNCTION + and not obj.function_signature + ): + object_blockers.append( + f"{obj.schema_ref}.{obj.object_ref}: ownership and ACL rendering " + "require an explicit function_signature to avoid overload widening" + ) + + if not objects: + object_blockers.append( + "typed ownership evidence resolved to zero database objects" + ) + object_databases = {identity[0] for identity in objects} + for database_ref in sorted(set(topology.databases) - object_databases): + object_blockers.append( + f"{database_ref}: no typed ownership objects cover this topology database" + ) + + principal_inputs_by_database: dict[ + str, + list[tuple[str, ModelApplicationDatabasePrincipalInventory]], + ] = defaultdict(list) + observed_owner_roles = tuple( + sorted( + { + owner + for inventory in principal_inventories.values() + for owner in inventory.owner_refs + } + ) + ) + absent_owner_roles = tuple( + sorted( + { + owner + for inventory in principal_inventories.values() + for owner in inventory.absent_owner_refs + } + ) + ) + observed_role_state_by_name: dict[ + str, + ModelApplicationDatabaseObservedRoleState, + ] = {} + for source_id, principal_inventory in sorted(principal_inventories.items()): + for observed_state in principal_inventory.observed_role_states: + existing_state = observed_role_state_by_name.get(observed_state.role) + if existing_state is not None and existing_state != observed_state: + blockers.append( + f"{source_id}: observed role attributes for " + f"{observed_state.role!r} conflict across cluster inventories" + ) + observed_role_state_by_name[observed_state.role] = observed_state + if not _status_is_ready(principal_inventory.completion_status): + blockers.append( + f"{source_id}: completion_status=" + f"{principal_inventory.completion_status!r}" + ) + if not _status_is_ready(principal_inventory.catalog_parity_status): + blockers.append( + f"{source_id}: catalog_parity_status=" + f"{principal_inventory.catalog_parity_status!r}: " + f"{principal_inventory.reason}" + ) + if ( + authorization_scope + is EnumApplicationDatabaseAclAuthorizationScope.DEPLOYMENT + ): + if principal_inventory.source_kind != ( + EnumApplicationDatabasePrincipalInventorySourceKind.AUTHORIZED_CATALOG + ): + blockers.append( + f"{source_id}: deployment authorization requires " + "source_kind='authorized_catalog'" + ) + if ( + principal_inventory.activity_evidence is None + or principal_inventory.catalog_query_sha256 is None + or principal_inventory.catalog_result_sha256 is None + or principal_inventory.catalog_query_source_key is None + or principal_inventory.catalog_result_source_key is None + ): + blockers.append( + f"{source_id}: deployment authorization lacks durable full-day " + "activity and catalog query/result provenance" + ) + else: + catalog_result_key = principal_inventory.catalog_result_source_key + activity_result_key = ( + principal_inventory.activity_evidence.result_source_key + ) + catalog_result = parsed_catalog_results.get(catalog_result_key) + activity_result = parsed_activity_results.get(activity_result_key) + if catalog_result is None: + blockers.append( + f"{source_id}: catalog result {catalog_result_key!r} was " + "not supplied as parsed typed content" + ) + if activity_result is None: + blockers.append( + f"{source_id}: activity result {activity_result_key!r} was " + "not supplied as parsed typed content" + ) + if catalog_result is not None and activity_result is not None: + semantic_violations = ( + validate_application_database_principal_evidence( + principal_inventory, + catalog_result, + activity_result, + ) + ) + if semantic_violations: + blockers.extend( + f"{source_id}: typed evidence mismatch: {violation}" + for violation in semantic_violations + ) + else: + verified_evidence.update( + {catalog_result_key, activity_result_key} + ) + evidence_bindings = ( + ( + principal_inventory.catalog_query_source_key, + principal_inventory.catalog_query_sha256, + "catalog_query_evidence", + ), + ( + principal_inventory.catalog_result_source_key, + principal_inventory.catalog_result_sha256, + "catalog_result_evidence", + ), + ( + principal_inventory.activity_evidence.query_source_key, + principal_inventory.activity_evidence.query_sha256, + "activity_query_evidence", + ), + ( + principal_inventory.activity_evidence.result_source_key, + principal_inventory.activity_evidence.result_sha256, + "activity_result_evidence", + ), + ) + for ( + evidence_key, + evidence_digest, + evidence_purpose, + ) in evidence_bindings: + evidence_source = source_by_key.get(evidence_key) + if evidence_source is None: + blockers.append( + f"{source_id}: evidence source {evidence_key!r} is absent " + "from the immutable source lock" + ) + elif evidence_source.purpose != evidence_purpose: + blockers.append( + f"{source_id}: evidence source {evidence_key!r} has purpose " + f"{evidence_source.purpose!r}, expected {evidence_purpose!r}" + ) + elif evidence_source.sha256 != evidence_digest: + blockers.append( + f"{source_id}: evidence digest {evidence_digest!r} does not " + f"match locked source {evidence_key!r} " + f"({evidence_source.sha256!r})" + ) + elif ( + evidence_purpose + in { + "catalog_result_evidence", + "activity_result_evidence", + } + and evidence_key not in verified_evidence + ): + blockers.append( + f"{source_id}: evidence source {evidence_key!r} was " + "hash-bound but its typed result content was not " + "semantically verified" + ) + elif principal_inventory.source_kind != ( + EnumApplicationDatabasePrincipalInventorySourceKind.SYNTHETIC_FIXTURE + ): + blockers.append( + f"{source_id}: synthetic proof requires source_kind='synthetic_fixture'" + ) + database = topology.databases.get(principal_inventory.database_ref) + if ( + database is not None + and database.physical_name != principal_inventory.physical_database + ): + blockers.append( + f"{source_id}: physical database drift: topology=" + f"{database.physical_name!r} inventory=" + f"{principal_inventory.physical_database!r}" + ) + principal_inputs_by_database[principal_inventory.database_ref].append( + (source_id, principal_inventory) + ) + + policy_inputs_by_database: dict[ + str, + list[tuple[str, ModelApplicationDatabaseAclPolicy]], + ] = defaultdict(list) + for source_id, policy in sorted(acl_policies.items()): + if not _status_is_ready(policy.completion_status): + blockers.append( + f"{source_id}: completion_status={policy.completion_status!r}" + ) + required_policy_kind = ( + EnumApplicationDatabaseAclPolicySourceKind.TOPOLOGY_CONTRACT + if authorization_scope + is EnumApplicationDatabaseAclAuthorizationScope.DEPLOYMENT + else EnumApplicationDatabaseAclPolicySourceKind.SYNTHETIC_FIXTURE + ) + if policy.source_kind is not required_policy_kind: + blockers.append( + f"{source_id}: {authorization_scope.value} authorization requires " + f"ACL policy source_kind={required_policy_kind.value!r}" + ) + database = topology.databases.get(policy.database_ref) + if database is None: + blockers.append( + f"{source_id}: unknown database_ref {policy.database_ref!r}" + ) + continue + if database.physical_name != policy.physical_database: + blockers.append( + f"{source_id}: physical database drift: topology=" + f"{database.physical_name!r} policy={policy.physical_database!r}" + ) + policy_inputs_by_database[policy.database_ref].append((source_id, policy)) + + connection_policy_inputs: dict[ + str, + list[tuple[str, ModelApplicationDatabaseConnectionPolicy]], + ] = defaultdict(list) + policy_governed_roles = { + state.role + for policy in acl_policies.values() + for state in policy.governed_role_states + } + noncreatable_policy_roles = { + state.role + for policy in acl_policies.values() + for state in policy.governed_role_states + if not state.manage_attributes + } + for source_id, policy in sorted(acl_policies.items()): + for connection_policy in policy.connection_policies: + connection_policy_inputs[connection_policy.physical_database].append( + (source_id, connection_policy) + ) + + allowed_connect_principals: dict[str, tuple[str, ...]] = {} + observed_connect_principals: dict[str, tuple[str, ...]] = {} + absent_connect_principals: dict[str, tuple[str, ...]] = {} + observed_connect_database_owners: dict[str, str] = {} + connection_database_refs: set[str] = set() + for physical_database in required_connect: + policies = connection_policy_inputs.get(physical_database, []) + if len(policies) != 1: + blockers.append( + f"{physical_database}: requires exactly one CONNECT policy, got " + f"{[source_id for source_id, _ in policies]!r}" + ) + continue + source_id, connection_policy = policies[0] + database_ref = connection_policy.database_ref + connection_database_refs.add(database_ref) + inventory_inputs = principal_inputs_by_database.get(database_ref, []) + if len(inventory_inputs) != 1: + blockers.append( + f"{physical_database}: requires exactly one principal inventory " + f"for CONNECT policy {database_ref!r}, got " + f"{[item[0] for item in inventory_inputs]!r}" + ) + continue + connection_inventory = inventory_inputs[0][1] + if connection_inventory.physical_database != physical_database: + blockers.append( + f"{physical_database}: CONNECT inventory physical database is " + f"{connection_inventory.physical_database!r}" + ) + continue + allowed = tuple(sorted(connection_policy.allowed_principals)) + connection_observed = tuple(sorted(connection_inventory.principal_refs)) + connection_absent = tuple(sorted(connection_inventory.absent_principal_refs)) + missing_allowed = sorted( + set(allowed) - set(connection_observed) - set(connection_absent) + ) + if missing_allowed: + blockers.append( + f"{physical_database}: CONNECT inventory lacks presence/absence " + "evidence for allowed principals " + f"{missing_allowed!r}" + ) + unmanaged_absent = sorted( + set(allowed) + .intersection(connection_absent) + .intersection(noncreatable_policy_roles) + ) + if unmanaged_absent: + blockers.append( + f"{physical_database}: CONNECT-only policy cannot create absent " + "external principals without governed role-state authorization: " + f"{unmanaged_absent!r}" + ) + parent_policy = acl_policies[source_id] + classified_activity_principals = ( + set(allowed) + .union(parent_policy.retained_administrative_principals) + .union({parent_policy.migration_principal}) + .union({connection_inventory.database_owner_role}) + .union(connection_inventory.owner_refs) + ) + unclassified_activity = sorted( + set(connection_inventory.activity_principal_refs) + - classified_activity_principals + ) + if unclassified_activity: + object_blockers.append( + f"{physical_database}: full-day activity contains principals not " + "classified as allowed, migration, administrative, or owner: " + f"{unclassified_activity!r}" + ) + if ( + connection_policy.observed_database_owner_role + != connection_inventory.database_owner_role + ): + blockers.append( + f"{physical_database}: CONNECT policy observed database owner " + f"{connection_policy.observed_database_owner_role!r} disagrees " + f"with catalog inventory {connection_inventory.database_owner_role!r}" + ) + topology_database = topology.databases.get(database_ref) + if topology_database is not None: + topology_allowed = { + principal + for principal, principal_contract in topology_database.principals.items() + if any( + grant.object_type is EnumDatabaseGrantObjectType.DATABASE + and EnumDatabasePrivilege.CONNECT in grant.privileges + for grant in principal_contract.grants + ) + } + if set(allowed) != topology_allowed: + blockers.append( + f"{physical_database}: CONNECT policy disagrees with topology: " + f"missing={sorted(topology_allowed - set(allowed))!r} " + f"extra={sorted(set(allowed) - topology_allowed)!r}" + ) + observed_connect_database_owners[physical_database] = ( + connection_policy.observed_database_owner_role + ) + allowed_connect_principals[physical_database] = allowed + observed_connect_principals[physical_database] = connection_observed + absent_connect_principals[physical_database] = connection_absent + _ = source_id + + unexpected_connection_policies = sorted( + set(connection_policy_inputs) - set(required_connect) + ) + if unexpected_connection_policies: + blockers.append( + "CONNECT policies include databases outside the required inventory: " + f"{unexpected_connection_policies!r}" + ) + consumed_inventory_refs = set(topology.databases).union(connection_database_refs) + unexpected_inventory_refs = sorted( + set(principal_inputs_by_database) - consumed_inventory_refs + ) + if unexpected_inventory_refs: + blockers.append( + "principal inventories are not bound to topology or CONNECT policy: " + f"{unexpected_inventory_refs!r}" + ) + + declared_principals: dict[str, tuple[str, ...]] = {} + observed_principals: dict[str, tuple[str, ...]] = {} + absent_principals: dict[str, tuple[str, ...]] = {} + database_owners: dict[str, str] = {} + observed_schema_owners: dict[str, dict[str, str]] = {} + absent_schemas: dict[str, tuple[str, ...]] = {} + observed_catalog_objects: list[ModelApplicationDatabaseCatalogObjectEvidence] = [] + principal_domains: dict[str, set[EnumDatabaseSchemaDomain]] = defaultdict(set) + allowed_memberships: list[ModelApplicationDatabaseRoleMembership] = [] + governed_role_states: list[ModelApplicationDatabaseRoleState] = [] + retained_administrative_principals: set[str] = set() + for database_ref, database in sorted(topology.databases.items()): + declared = tuple(sorted(database.principals)) + declared_principals[database_ref] = declared + + inventory_inputs = principal_inputs_by_database.get(database_ref, []) + if len(inventory_inputs) != 1: + blockers.append( + f"{database_ref}: requires exactly one principal inventory, got " + f"{[source_id for source_id, _ in inventory_inputs]!r}" + ) + observed: tuple[str, ...] = () + absent: tuple[str, ...] = () + else: + observed = tuple(sorted(inventory_inputs[0][1].principal_refs)) + absent = tuple(sorted(inventory_inputs[0][1].absent_principal_refs)) + missing_declared = sorted(set(declared) - set(observed) - set(absent)) + if missing_declared: + blockers.append( + f"{database_ref}: principal inventory lacks presence/absence " + "evidence for topology principals " + f"{missing_declared!r}" + ) + observed_principals[database_ref] = observed + absent_principals[database_ref] = absent + if len(inventory_inputs) == 1: + observed_schema_owner_values = dict( + sorted(inventory_inputs[0][1].observed_schema_owners.items()) + ) + absent_schema_refs = tuple( + sorted(inventory_inputs[0][1].absent_schema_refs) + ) + missing_schema_evidence = sorted( + set(database.schemas) + - set(observed_schema_owner_values) + - set(absent_schema_refs) + ) + extra_schema_evidence = sorted( + set(observed_schema_owner_values).union(absent_schema_refs) + - set(database.schemas) + ) + if missing_schema_evidence or extra_schema_evidence: + blockers.append( + f"{database_ref}: target schema presence/absence evidence " + f"differs from topology: missing={missing_schema_evidence!r} " + f"extra={extra_schema_evidence!r}" + ) + observed_catalog_objects.extend(inventory_inputs[0][1].observed_objects) + else: + observed_schema_owner_values = {} + absent_schema_refs = () + observed_schema_owners[database_ref] = observed_schema_owner_values + absent_schemas[database_ref] = absent_schema_refs + + policy_inputs = policy_inputs_by_database.get(database_ref, []) + if len(policy_inputs) != 1: + blockers.append( + f"{database_ref}: requires exactly one independent ACL policy, got " + f"{[source_id for source_id, _ in policy_inputs]!r}" + ) + continue + policy = policy_inputs[0][1] + policy_principals = set(policy.principal_domains) + declared_set = set(declared) + if policy_principals != declared_set: + blockers.append( + f"{database_ref}: ACL policy principals differ from topology: " + f"missing={sorted(declared_set - policy_principals)!r} " + f"extra={sorted(policy_principals - declared_set)!r}" + ) + expected_owners = set(database.owners) + policy_owners = set(policy.migration_owner_roles) + if policy_owners != expected_owners: + blockers.append( + f"{database_ref}: migration owner roles differ from topology: " + f"missing={sorted(expected_owners - policy_owners)!r} " + f"extra={sorted(policy_owners - expected_owners)!r}" + ) + if policy.database_owner_role not in expected_owners: + blockers.append( + f"{database_ref}: database owner role " + f"{policy.database_owner_role!r} is not a topology owner" + ) + else: + database_owners[database_ref] = policy.database_owner_role + if len(inventory_inputs) == 1: + principal_inventory = inventory_inputs[0][1] + owner_evidence = set(principal_inventory.owner_refs).union( + principal_inventory.absent_owner_refs + ) + missing_owner_evidence = sorted(expected_owners - owner_evidence) + if missing_owner_evidence: + blockers.append( + f"{database_ref}: managed owner roles lack presence/absence " + f"evidence {missing_owner_evidence!r}" + ) + if policy.migration_principal not in observed: + blockers.append( + f"{database_ref}: principal inventory omits migration principal " + f"{policy.migration_principal!r}" + ) + if policy.migration_principal in declared_set or ( + policy.migration_principal in expected_owners + ): + blockers.append( + f"{database_ref}: migration principal must be distinct from " + "workload and owner roles" + ) + external_connect_roles = { + principal + for connection_policy in policy.connection_policies + for principal in connection_policy.allowed_principals + } - declared_set + expected_governed_roles = ( + expected_owners.union(declared_set) + .union({policy.migration_principal}) + .union(external_connect_roles) + ) + actual_governed_roles = {state.role for state in policy.governed_role_states} + if actual_governed_roles != expected_governed_roles: + blockers.append( + f"{database_ref}: governed role-state policy differs from topology " + f"and migration roles: missing=" + f"{sorted(expected_governed_roles - actual_governed_roles)!r} " + f"extra={sorted(actual_governed_roles - expected_governed_roles)!r}" + ) + retained_admins = set(policy.retained_administrative_principals) + retained_administrative_principals.update(retained_admins) + if retained_admins & actual_governed_roles: + blockers.append( + f"{database_ref}: retained administrative principals overlap " + "governed role-state policy" + ) + missing_retained_admins = sorted(retained_admins - set(observed)) + if missing_retained_admins: + blockers.append( + f"{database_ref}: retained administrative principals are absent " + f"from the observed census: {missing_retained_admins!r}" + ) + for state in policy.governed_role_states: + expected_kind = ( + "owner" + if state.role in expected_owners + else "workload" + if state.role in declared_set + else "migration" + if state.role == policy.migration_principal + else "external_connect" + ) + expected_login = state.role in declared_set.union(external_connect_roles) + expected_manage_attributes = state.role not in external_connect_roles + if ( + state.role_kind != expected_kind + or state.login is not expected_login + or state.manage_attributes is not expected_manage_attributes + or not state.manage_memberships + ): + blockers.append( + f"{database_ref}: governed role state for {state.role!r} must " + f"be kind={expected_kind!r} login={expected_login!r} " + f"manage_attributes={expected_manage_attributes!r} " + "manage_memberships=True" + ) + if not state.manage_attributes: + actual_role_state = observed_role_state_by_name.get(state.role) + if actual_role_state is None: + blockers.append( + f"{database_ref}: non-mutating governed role {state.role!r} " + "lacks observed attribute evidence" + ) + elif any( + getattr(actual_role_state, field_name) != getattr(state, field_name) + for field_name in ( + "login", + "superuser", + "bypass_rls", + "create_database", + "create_role", + "replication", + "inherit", + ) + ): + blockers.append( + f"{database_ref}: non-mutating governed role {state.role!r} " + "does not already match the safe desired attribute state" + ) + governed_role_states.extend(policy.governed_role_states) + for owner in sorted(policy_owners & expected_owners): + allowed_memberships.append( + ModelApplicationDatabaseRoleMembership( + database_ref=database_ref, + role=owner, + member=policy.migration_principal, + admin_option=False, + inherit_option=False, + set_option=True, + ) + ) + for principal_name, domains in policy.principal_domains.items(): + if principal_name in declared_set: + principal_domains[principal_name].update(domains) + + rows: list[ModelApplicationDatabaseAclRow] = [] + for database_ref, database in sorted(topology.databases.items()): + principal_universe = set(database.principals) | set( + observed_principals[database_ref] + ) + grantees = (PUBLIC_PRINCIPAL, *sorted(principal_universe)) + for principal in grantees: + rows.append( + ModelApplicationDatabaseAclRow( + principal=principal, + database_ref=database_ref, + physical_database=database.physical_name, + object_type=EnumDatabaseGrantObjectType.DATABASE, + privileges=tuple( + sorted( + topology_privileges.get( + ( + principal, + database_ref, + EnumDatabaseGrantObjectType.DATABASE, + None, + None, + ), + set(), + ), + key=lambda privilege: privilege.value, + ) + ), + ) + ) + for schema_name in sorted(database.schemas): + rows.append( + ModelApplicationDatabaseAclRow( + principal=principal, + database_ref=database_ref, + physical_database=database.physical_name, + object_type=EnumDatabaseGrantObjectType.SCHEMA, + schema_ref=schema_name, + privileges=tuple( + sorted( + topology_privileges.get( + ( + principal, + database_ref, + EnumDatabaseGrantObjectType.SCHEMA, + schema_name, + None, + ), + set(), + ), + key=lambda privilege: privilege.value, + ) + ), + ) + ) + + ordered_objects = tuple( + sorted( + (evidence.obj for evidence in objects.values()), + key=lambda obj: ( + obj.database_ref, + obj.schema_ref, + obj.object_type.value, + obj.object_ref, + obj.function_signature or "", + ), + ) + ) + expected_catalog_object_ids: set[tuple[str, str, str, str]] = { + ( + obj.catalog_kind, + obj.schema_ref, + obj.object_ref, + obj.function_signature or "", + ) + for obj in ordered_objects + } + observed_catalog_object_ids: set[tuple[str, str, str, str]] = { + obj.identity for obj in observed_catalog_objects + } + if expected_catalog_object_ids != observed_catalog_object_ids: + object_blockers.append( + "live catalog object identities differ from the exact typed ownership " + f"projection: missing=" + f"{sorted(expected_catalog_object_ids - observed_catalog_object_ids)!r} " + f"extra={sorted(observed_catalog_object_ids - expected_catalog_object_ids)!r}" + ) + for obj in ordered_objects: + database = topology.databases[obj.database_ref] + principal_universe = set(database.principals) | set( + observed_principals[obj.database_ref] + ) + for principal in (PUBLIC_PRINCIPAL, *sorted(principal_universe)): + rows.append( + ModelApplicationDatabaseAclRow( + principal=principal, + database_ref=obj.database_ref, + physical_database=obj.physical_database, + object_type=obj.object_type, + schema_ref=obj.schema_ref, + object_ref=obj.object_ref, + function_signature=obj.function_signature, + privileges=tuple( + sorted( + resolved_object_privileges.get( + ( + principal, + obj.database_ref, + obj.object_type, + obj.schema_ref, + obj.object_ref, + obj.function_signature, + ), + set(), + ), + key=lambda privilege: privilege.value, + ) + ), + ) + ) + + default_rows: list[ModelApplicationDatabaseDefaultAclRow] = [] + for database_ref, database in sorted(topology.databases.items()): + principal_universe = set(database.principals) | set( + observed_principals[database_ref] + ) + grantees = (PUBLIC_PRINCIPAL, *sorted(principal_universe)) + for schema_name, schema in sorted(database.schemas.items()): + for object_type in _OBJECT_TYPES: + for grantee in grantees: + default_rows.append( + ModelApplicationDatabaseDefaultAclRow( + owner=schema.owner, + database_ref=database_ref, + physical_database=database.physical_name, + schema_ref=schema_name, + object_type=object_type, + grantee=grantee, + ) + ) + + scaffold_blockers = tuple(sorted(set(blockers))) + unique_blockers = tuple(sorted({*blockers, *object_blockers})) + matrix = ModelApplicationDatabaseAclMatrix( + authorization_scope=authorization_scope, + scaffold_status="BLOCKED" if scaffold_blockers else "READY", + scaffold_blockers=scaffold_blockers, + status="BLOCKED" if unique_blockers else "READY", + sources=tuple(sorted(sources, key=lambda source: source.source_key)), + verified_evidence_source_keys=tuple(sorted(verified_evidence)), + declared_principals=declared_principals, + observed_principals=observed_principals, + absent_principals=absent_principals, + observed_owner_roles=observed_owner_roles, + absent_owner_roles=absent_owner_roles, + observed_role_states=tuple( + sorted(observed_role_state_by_name.values(), key=lambda state: state.role) + ), + governed_role_states=tuple( + sorted(governed_role_states, key=lambda state: state.role) + ), + retained_administrative_principals=tuple( + sorted(retained_administrative_principals) + ), + database_owners=database_owners, + required_connect_databases=required_connect, + observed_connect_database_owners=observed_connect_database_owners, + allowed_connect_principals=allowed_connect_principals, + observed_connect_principals=observed_connect_principals, + absent_connect_principals=absent_connect_principals, + schema_domains={ + database_ref: { + schema_name: schema.domain + for schema_name, schema in sorted(database.schemas.items()) + } + for database_ref, database in sorted(topology.databases.items()) + }, + observed_schema_owners=observed_schema_owners, + absent_schemas=absent_schemas, + principal_domains={ + principal: tuple(sorted(domains, key=lambda domain: domain.value)) + for principal, domains in sorted(principal_domains.items()) + }, + allowed_memberships=tuple( + sorted( + allowed_memberships, + key=lambda item: item.identity, + ) + ), + observed_objects=tuple( + sorted(observed_catalog_objects, key=lambda obj: obj.identity) + ), + objects=ordered_objects, + rows=tuple( + sorted( + rows, + key=lambda row: tuple(str(item) for item in row.identity), + ) + ), + default_privileges=tuple( + sorted( + default_rows, + key=lambda row: ( + row.database_ref, + row.schema_ref, + row.owner, + row.object_type.value, + row.grantee, + ), + ) + ), + blockers=unique_blockers, + excluded_objects=tuple(sorted(set(excluded))), + ) + shared_scaffold_violations = validate_application_database_acl_scaffold( + matrix, + require_safe_existing_roles=False, + ) + scaffold_violations = validate_application_database_acl_scaffold(matrix) + if scaffold_violations: + rendered_scaffold_blockers = tuple( + sorted( + { + *matrix.scaffold_blockers, + *( + f"ACL scaffold policy violation: {violation}" + for violation in scaffold_violations + ), + } + ) + ) + matrix = matrix.model_copy( + update={ + "scaffold_status": "BLOCKED", + "scaffold_blockers": rendered_scaffold_blockers, + } + ) + if shared_scaffold_violations: + matrix = matrix.model_copy( + update={ + "status": "BLOCKED", + "blockers": tuple( + sorted( + { + *matrix.blockers, + *( + f"ACL scaffold policy violation: {violation}" + for violation in shared_scaffold_violations + ), + } + ) + ), + } + ) + structural_violations = validate_application_database_acl_matrix(matrix) + if structural_violations: + matrix = matrix.model_copy( + update={ + "status": "BLOCKED", + "blockers": tuple( + sorted( + { + *matrix.blockers, + *( + f"ACL policy violation: {violation}" + for violation in structural_violations + ), + } + ) + ), + } + ) + return ModelApplicationDatabaseAclMatrix.model_validate( + matrix.model_dump(mode="json") + ) + + +def validate_application_database_acl_matrix( + matrix: ModelApplicationDatabaseAclMatrix, +) -> tuple[str, ...]: + """Validate deny-by-default, ownership, completeness, and domain separation.""" + violations: list[str] = [] + declared_principals = { + principal + for principals in matrix.declared_principals.values() + for principal in principals + } + matrix_principals = declared_principals.union( + principal + for principals in ( + *matrix.observed_principals.values(), + *matrix.observed_connect_principals.values(), + *matrix.absent_principals.values(), + *matrix.absent_connect_principals.values(), + *matrix.allowed_connect_principals.values(), + ) + for principal in principals + ) + for database_ref, owner in matrix.database_owners.items(): + if owner in matrix_principals: + violations.append( + f"runtime principal {owner!r} owns database {database_ref!r}" + ) + for obj in matrix.objects: + if not obj.target_materialized: + violations.append( + f"target object {obj.physical_database}.{obj.schema_ref}." + f"{obj.object_ref} is not materialized at the rendered location" + ) + if ( + obj.object_type is EnumDatabaseGrantObjectType.FUNCTION + and obj.function_signature is None + ): + violations.append( + f"routine {obj.schema_ref}.{obj.object_ref} lacks an exact signature" + ) + if obj.owner in matrix_principals: + violations.append( + f"runtime principal {obj.owner!r} owns " + f"{obj.schema_ref}.{obj.object_ref}" + ) + for row in matrix.rows: + if row.principal == PUBLIC_PRINCIPAL and row.privileges: + violations.append( + f"PUBLIC has {sorted(p.value for p in row.privileges)!r} on " + f"{row.object_type.value}:{row.schema_ref}:{row.object_ref}" + ) + + domains_by_object = {obj.identity: obj.domain for obj in matrix.objects} + for row in matrix.rows: + if not row.privileges: + continue + if row.object_type is EnumDatabaseGrantObjectType.SCHEMA: + domain = matrix.schema_domains.get(row.database_ref, {}).get( + row.schema_ref or "" + ) + elif row.object_type in _OBJECT_TYPES: + object_identity = ( + row.database_ref, + row.schema_ref or "", + row.object_type, + row.object_ref or "", + row.function_signature, + ) + domain = domains_by_object.get(object_identity) + else: + domain = None + if domain is None: + continue + allowed = matrix.principal_domains.get(row.principal, ()) + if domain not in allowed: + violations.append( + f"principal {row.principal!r} has cross-domain privileges on " + f"{row.schema_ref}.{row.object_ref} ({domain.value})" + ) + prohibited = { + EnumDatabasePrivilege.CREATE, + EnumDatabasePrivilege.TEMPORARY, + EnumDatabasePrivilege.TRIGGER, + EnumDatabasePrivilege.REFERENCES, + EnumDatabasePrivilege.TRUNCATE, + } + for acl_row in matrix.rows: + if acl_row.principal in matrix_principals and prohibited & set( + acl_row.privileges + ): + violations.append( + f"runtime principal {acl_row.principal!r} has DDL privilege on " + f"{acl_row.object_type.value}:{acl_row.schema_ref}:" + f"{acl_row.object_ref}" + ) + declared_by_database = { + database_ref: set(principals) + for database_ref, principals in matrix.declared_principals.items() + } + observed_by_database = { + database_ref: set(principals) + for database_ref, principals in matrix.observed_principals.items() + } + owner_roles = ( + set(matrix.database_owners.values()) + .union(obj.owner for obj in matrix.objects) + .union(row.owner for row in matrix.default_privileges) + ) + for membership in matrix.allowed_memberships: + if membership.member in declared_by_database.get( + membership.database_ref, set() + ): + violations.append( + f"workload principal {membership.member!r} has permitted role " + f"membership {membership.role!r}" + ) + if membership.member not in observed_by_database.get( + membership.database_ref, set() + ): + violations.append( + f"membership principal {membership.member!r} is absent from the " + "observed principal census" + ) + if membership.role not in owner_roles: + violations.append( + f"permitted membership role {membership.role!r} is not an owner role" + ) + if ( + membership.admin_option + or membership.inherit_option + or not membership.set_option + ): + violations.append( + f"migration membership {membership.role!r} -> " + f"{membership.member!r} must be SET-only" + ) + for default_row in matrix.default_privileges: + if default_row.grantee == PUBLIC_PRINCIPAL and default_row.privileges: + violations.append( + f"PUBLIC has future {default_row.object_type.value} privileges in " + f"{default_row.schema_ref!r}" + ) + if default_row.grantee in matrix_principals and default_row.privileges: + violations.append( + f"runtime principal {default_row.grantee!r} has broad future " + f"{default_row.object_type.value} privileges in " + f"{default_row.schema_ref!r}" + ) + + schema_usage = { + (row.principal, row.database_ref, row.schema_ref) + for row in matrix.rows + if row.object_type is EnumDatabaseGrantObjectType.SCHEMA + and EnumDatabasePrivilege.USAGE in row.privileges + } + for row in matrix.rows: + if row.object_type not in _OBJECT_TYPES or not row.privileges: + continue + if (row.principal, row.database_ref, row.schema_ref) not in schema_usage: + violations.append( + f"principal {row.principal!r} has object privilege without schema " + f"USAGE on {row.schema_ref!r}" + ) + + object_ids = {obj.identity for obj in matrix.objects} + object_row_ids = { + ( + row.database_ref, + row.schema_ref, + row.object_type, + row.object_ref, + row.function_signature, + ) + for row in matrix.rows + if row.object_type in _OBJECT_TYPES + } + if object_ids != object_row_ids: + violations.append("object rows do not cover the exact ownership object set") + expected_grantees_by_database = { + database_ref: { + row.principal + for row in matrix.rows + if row.database_ref == database_ref + and row.object_type is EnumDatabaseGrantObjectType.DATABASE + } + for database_ref in {obj.database_ref for obj in matrix.objects} + } + for obj in matrix.objects: + actual_grantees = { + row.principal + for row in matrix.rows + if ( + row.database_ref, + row.schema_ref, + row.object_type, + row.object_ref, + row.function_signature, + ) + == obj.identity + } + if actual_grantees != expected_grantees_by_database[obj.database_ref]: + violations.append( + f"{obj.schema_ref}.{obj.object_ref} lacks a complete principal row set" + ) + return tuple(sorted(set(violations))) + + +def validate_application_database_acl_scaffold( + matrix: ModelApplicationDatabaseAclMatrix, + *, + require_safe_existing_roles: bool = True, +) -> tuple[str, ...]: + """Validate the additive P1 roles/schemas/CONNECT/default-ACL stage only.""" + violations: list[str] = [] + database_refs = set(matrix.declared_principals) + if not database_refs: + violations.append("scaffold declares zero topology databases") + elif len(database_refs) != 1: + violations.append("scaffold requires exactly one topology application database") + if ( + set(matrix.observed_principals) != database_refs + or set(matrix.absent_principals) != database_refs + ): + violations.append( + "scaffold principal presence/absence database keys are incomplete" + ) + if set(matrix.database_owners) != database_refs: + violations.append("scaffold database owner map is incomplete") + if set(matrix.schema_domains) != database_refs: + violations.append("scaffold schema domain map is incomplete") + if ( + set(matrix.observed_schema_owners) != database_refs + or set(matrix.absent_schemas) != database_refs + ): + violations.append("scaffold schema presence/absence maps are incomplete") + application_physical_databases = { + row.physical_database for row in matrix.default_privileges + } + if len(application_physical_databases) != 1: + violations.append( + "scaffold requires exactly one application physical database target" + ) + if any( + _SQL_IDENTIFIER.fullmatch(database) is None + for database in application_physical_databases + ): + violations.append("scaffold application database target is not canonical") + row_physical_databases = { + row.physical_database + for row in matrix.rows + if row.database_ref in database_refs + } + object_physical_databases = { + obj.physical_database + for obj in matrix.objects + if obj.database_ref in database_refs + } + if row_physical_databases != application_physical_databases or ( + object_physical_databases + and object_physical_databases != application_physical_databases + ): + violations.append( + "scaffold application physical database target disagrees across rows, " + "objects, and future-ACL cells" + ) + if not application_physical_databases <= set(matrix.required_connect_databases): + violations.append( + "scaffold application physical database is absent from CONNECT scope" + ) + + required_connect = set(matrix.required_connect_databases) + for name, values in ( + ("allowed CONNECT", matrix.allowed_connect_principals), + ("observed CONNECT", matrix.observed_connect_principals), + ("observed CONNECT owner", matrix.observed_connect_database_owners), + ): + if set(values) != required_connect: + violations.append(f"{name} database keys do not cover required CONNECT set") + + declared = { + principal + for principals in matrix.declared_principals.values() + for principal in principals + } + observed = { + principal + for principals in matrix.observed_principals.values() + for principal in principals + } + connection_principals = { + principal + for principals in matrix.observed_connect_principals.values() + for principal in principals + } + desired_connect = { + principal + for principals in matrix.allowed_connect_principals.values() + for principal in principals + } + runtime_principals = declared.union( + observed, + connection_principals, + desired_connect, + ) + owner_roles = set(matrix.database_owners.values()) | { + row.owner for row in matrix.default_privileges + } + if owner_roles & runtime_principals: + violations.append("scaffold owner roles overlap runtime principal census") + + for database_ref in sorted(database_refs): + expected_grantees = { + PUBLIC_PRINCIPAL, + *matrix.declared_principals[database_ref], + *matrix.observed_principals[database_ref], + } + existing = set(matrix.observed_principals[database_ref]) + absent = set(matrix.absent_principals[database_ref]) + if existing & absent: + violations.append( + f"{database_ref}: principal presence/absence evidence overlaps" + ) + if not set(matrix.declared_principals[database_ref]) <= existing.union(absent): + violations.append( + f"{database_ref}: scaffold lacks presence/absence evidence for " + "declared principals" + ) + schemas = set(matrix.schema_domains[database_ref]) + if not schemas: + violations.append(f"{database_ref}: scaffold declares zero schemas") + observed_schemas = set(matrix.observed_schema_owners.get(database_ref, {})) + absent_schemas = set(matrix.absent_schemas.get(database_ref, ())) + if observed_schemas & absent_schemas: + violations.append( + f"{database_ref}: schema presence/absence evidence overlaps" + ) + if schemas != observed_schemas.union(absent_schemas): + violations.append( + f"{database_ref}: scaffold lacks exact target schema evidence" + ) + database_rows = { + row.principal: row + for row in matrix.rows + if row.database_ref == database_ref + and row.object_type is EnumDatabaseGrantObjectType.DATABASE + } + if set(database_rows) != expected_grantees: + violations.append( + f"{database_ref}: database ACL cells do not cover exact principal census" + ) + for schema_name in sorted(schemas): + schema_rows = { + row.principal: row + for row in matrix.rows + if row.database_ref == database_ref + and row.object_type is EnumDatabaseGrantObjectType.SCHEMA + and row.schema_ref == schema_name + } + if set(schema_rows) != expected_grantees: + violations.append( + f"{database_ref}.{schema_name}: schema ACL cells do not cover " + "exact principal census" + ) + owners = { + row.owner + for row in matrix.default_privileges + if row.database_ref == database_ref and row.schema_ref == schema_name + } + if len(owners) != 1: + violations.append( + f"{database_ref}.{schema_name}: requires exactly one schema owner" + ) + expected_defaults = { + (object_type, grantee) + for object_type in _OBJECT_TYPES + for grantee in expected_grantees + } + actual_defaults = { + (row.object_type, row.grantee) + for row in matrix.default_privileges + if row.database_ref == database_ref and row.schema_ref == schema_name + } + if actual_defaults != expected_defaults: + violations.append( + f"{database_ref}.{schema_name}: default ACL cells are incomplete" + ) + + for physical_database in sorted(required_connect): + allowed = set(matrix.allowed_connect_principals.get(physical_database, ())) + observed_connect = set( + matrix.observed_connect_principals.get(physical_database, ()) + ) + absent_connect = set( + matrix.absent_connect_principals.get(physical_database, ()) + ) + if not allowed: + violations.append(f"{physical_database}: CONNECT allowlist is empty") + if observed_connect & absent_connect: + violations.append( + f"{physical_database}: CONNECT presence/absence evidence overlaps" + ) + if not allowed <= observed_connect.union(absent_connect): + violations.append( + f"{physical_database}: CONNECT allowlist lacks presence/absence evidence" + ) + managed_owner_evidence = set(matrix.observed_owner_roles).union( + matrix.absent_owner_roles + ) + if not owner_roles <= managed_owner_evidence: + violations.append("scaffold managed owners lack presence/absence evidence") + governed_states = {state.role: state for state in matrix.governed_role_states} + if not owner_roles <= { + role for role, state in governed_states.items() if state.role_kind == "owner" + }: + violations.append("scaffold managed owners lack governed owner-role state") + if not declared <= { + role + for role, state in governed_states.items() + if state.role_kind == "workload" and state.login + }: + violations.append("scaffold workloads lack governed LOGIN role state") + observed_states = {state.role: state for state in matrix.observed_role_states} + globally_absent_roles = { + principal + for principals in ( + *matrix.absent_principals.values(), + *matrix.absent_connect_principals.values(), + matrix.absent_owner_roles, + ) + for principal in principals + } + scaffold_safe_roles = set(globally_absent_roles) + scaffold_safe_roles.update( + role + for role, governed_state in governed_states.items() + if role in observed_states + and _role_attribute_values(observed_states[role]) + == _role_attribute_values(governed_state) + ) + intended_scaffold_roles = set(owner_roles) + intended_scaffold_roles.update( + principal + for principals in matrix.allowed_connect_principals.values() + for principal in principals + ) + intended_scaffold_roles.update( + row.principal + for row in matrix.rows + if row.principal != PUBLIC_PRINCIPAL + and row.object_type + in { + EnumDatabaseGrantObjectType.DATABASE, + EnumDatabaseGrantObjectType.SCHEMA, + } + and row.privileges + ) + intended_scaffold_roles.update( + principal + for membership in matrix.allowed_memberships + for principal in (membership.role, membership.member) + ) + unsafe_scaffold_roles = sorted(intended_scaffold_roles - scaffold_safe_roles) + if require_safe_existing_roles and unsafe_scaffold_roles: + violations.append( + "additive scaffold intended roles are not already safe or proven absent: " + f"{unsafe_scaffold_roles!r}" + ) + + prohibited = { + EnumDatabasePrivilege.CREATE, + EnumDatabasePrivilege.TEMPORARY, + EnumDatabasePrivilege.TRIGGER, + EnumDatabasePrivilege.REFERENCES, + EnumDatabasePrivilege.TRUNCATE, + } + for row in matrix.rows: + if row.object_type not in { + EnumDatabaseGrantObjectType.DATABASE, + EnumDatabaseGrantObjectType.SCHEMA, + }: + continue + if row.principal == PUBLIC_PRINCIPAL and row.privileges: + violations.append("PUBLIC has privileges in the additive scaffold") + if row.principal in runtime_principals and prohibited & set(row.privileges): + violations.append( + f"runtime principal {row.principal!r} has scaffold DDL privileges" + ) + if row.object_type is EnumDatabaseGrantObjectType.SCHEMA and row.privileges: + domain = matrix.schema_domains.get(row.database_ref, {}).get( + row.schema_ref or "" + ) + if domain not in matrix.principal_domains.get(row.principal, ()): + violations.append( + f"principal {row.principal!r} has cross-domain scaffold access" + ) + if any(row.privileges for row in matrix.default_privileges): + violations.append("scaffold future-object defaults must be deny-by-default") + + for membership in matrix.allowed_memberships: + if membership.role not in owner_roles: + violations.append("scaffold membership targets a non-owner role") + if membership.member in declared: + violations.append("runtime workload has scaffold owner membership") + if ( + membership.admin_option + or membership.inherit_option + or not membership.set_option + ): + violations.append("scaffold owner membership must be SET-only") + return tuple(sorted(set(violations))) + + +def _quote_identifier(identifier: str) -> str: + if _SQL_IDENTIFIER.fullmatch(identifier) is None: + raise ValueError(f"Unsafe or non-canonical SQL identifier {identifier!r}") + return f'"{identifier}"' + + +def _quote_sql_literal(value: str) -> str: + """Quote one trusted typed value as a PostgreSQL string literal.""" + return "'" + value.replace("'", "''") + "'" + + +def _managed_provenance_marker( + matrix: ModelApplicationDatabaseAclMatrix, + *, + kind: str, + name: str, +) -> str: + """Return a deterministic source-lock marker for additive managed objects.""" + _ = matrix + return f"omnibase_application_acl:v1:managed:{kind}:{name}" + + +def _sql_object_target( + obj: ModelApplicationDatabaseAclObject, +) -> tuple[str, str, str]: + """Return ownership keyword, ACL keyword, and exact SQL target.""" + qualified = ( + f"{_quote_identifier(obj.schema_ref)}.{_quote_identifier(obj.object_ref)}" + ) + if obj.object_type is EnumDatabaseGrantObjectType.TABLE: + owner_keyword = { + "table": "TABLE", + "view": "VIEW", + "materialized_view": "MATERIALIZED VIEW", + }[obj.catalog_kind] + return owner_keyword, "TABLE", qualified + if obj.object_type is EnumDatabaseGrantObjectType.SEQUENCE: + return "SEQUENCE", "SEQUENCE", qualified + if obj.object_type is EnumDatabaseGrantObjectType.TYPE: + return "TYPE", "TYPE", qualified + if obj.function_signature is None: + raise ValueError( + f"Function {obj.schema_ref}.{obj.object_ref} lacks function_signature" + ) + keyword = "PROCEDURE" if obj.catalog_kind == "procedure" else "FUNCTION" + return keyword, keyword, f"{qualified}{obj.function_signature}" + + +def render_application_database_acl_sql( + matrix: ModelApplicationDatabaseAclMatrix, + *, + allow_synthetic_proof: bool = False, + phase: EnumApplicationDatabaseAclRenderPhase = ( + EnumApplicationDatabaseAclRenderPhase.FULL + ), +) -> str: + """Render an atomic additive scaffold or the materialized-object full phase.""" + if phase is EnumApplicationDatabaseAclRenderPhase.FULL and matrix.status != "READY": + raise ValueError( + f"Cannot render blocked ACL matrix ({len(matrix.blockers)} blocker(s))" + ) + if ( + phase is EnumApplicationDatabaseAclRenderPhase.SCAFFOLD + and matrix.scaffold_status != "READY" + ): + raise ValueError( + "Cannot render blocked ACL scaffold " + f"({len(matrix.scaffold_blockers)} blocker(s))" + ) + if ( + matrix.authorization_scope + is EnumApplicationDatabaseAclAuthorizationScope.SYNTHETIC_PROOF + and not allow_synthetic_proof + ): + raise ValueError( + "Synthetic proof matrices require explicit allow_synthetic_proof=true" + ) + scaffold_violations = validate_application_database_acl_scaffold( + matrix, + require_safe_existing_roles=( + phase is EnumApplicationDatabaseAclRenderPhase.SCAFFOLD + ), + ) + violations = ( + tuple( + sorted( + set(scaffold_violations).union( + validate_application_database_acl_matrix(matrix) + ) + ) + ) + if phase is EnumApplicationDatabaseAclRenderPhase.FULL + else scaffold_violations + ) + if violations: + raise ValueError("Cannot render invalid ACL matrix: " + "; ".join(violations)) + + declared_principals = sorted( + { + principal + for principals in matrix.declared_principals.values() + for principal in principals + } + ) + allowed_connect_principals = sorted( + { + principal + for principals in matrix.allowed_connect_principals.values() + for principal in principals + } + ) + governed_states = {state.role: state for state in matrix.governed_role_states} + revocation_principals = sorted( + set(declared_principals) + .union(allowed_connect_principals) + .union( + principal + for principals in ( + *matrix.observed_principals.values(), + *matrix.observed_connect_principals.values(), + ) + for principal in principals + ) + ) + owners = sorted( + set(matrix.database_owners.values()) + .union(obj.owner for obj in matrix.objects) + .union(row.owner for row in matrix.default_privileges) + ) + globally_observed_roles = sorted( + { + principal + for principals in ( + *matrix.observed_principals.values(), + *matrix.observed_connect_principals.values(), + matrix.observed_owner_roles, + tuple(matrix.observed_connect_database_owners.values()), + ) + for principal in principals + } + ) + globally_absent_roles = { + principal + for principals in ( + *matrix.absent_principals.values(), + *matrix.absent_connect_principals.values(), + matrix.absent_owner_roles, + ) + for principal in principals + } + application_physical_database = next( + iter({row.physical_database for row in matrix.default_privileges}) + ) + application_database_ref = next(iter(matrix.declared_principals)) + application_desired_owner = matrix.database_owners[application_database_ref] + schema_owners = { + (row.database_ref, row.schema_ref): row.owner + for row in matrix.default_privileges + } + observed_states = {state.role: state for state in matrix.observed_role_states} + desired_object_owners: dict[tuple[str, str, str, str], str] = { + ( + obj.catalog_kind, + obj.schema_ref, + obj.object_ref, + obj.function_signature or "", + ): obj.owner + for obj in matrix.objects + } + + def role_attribute_sql(role_name: str) -> tuple[str, ...]: + state = governed_states[role_name] + return ( + f"role.rolcanlogin IS DISTINCT FROM {'TRUE' if state.login else 'FALSE'}", + "role.rolsuper IS DISTINCT FROM FALSE", + "role.rolbypassrls IS DISTINCT FROM FALSE", + "role.rolcreatedb IS DISTINCT FROM FALSE", + "role.rolcreaterole IS DISTINCT FROM FALSE", + "role.rolreplication IS DISTINCT FROM FALSE", + "role.rolinherit IS DISTINCT FROM FALSE", + ) + + def role_attribute_clause(role_name: str) -> str: + state = governed_states[role_name] + return ( + f"{'LOGIN' if state.login else 'NOLOGIN'} NOSUPERUSER NOBYPASSRLS " + "NOCREATEDB NOCREATEROLE NOREPLICATION NOINHERIT" + ) + + def role_state_match_clause( + state: ProtocolApplicationDatabaseRoleAttributeState, + ) -> str: + attribute_columns = ( + ("login", "rolcanlogin"), + ("superuser", "rolsuper"), + ("bypass_rls", "rolbypassrls"), + ("create_database", "rolcreatedb"), + ("create_role", "rolcreaterole"), + ("replication", "rolreplication"), + ("inherit", "rolinherit"), + ) + return ( + "(" + + " AND ".join( + f"role.{column} IS {'TRUE' if getattr(state, field) else 'FALSE'}" + for field, column in attribute_columns + ) + + ")" + ) + + lines = [ + "-- Generated application-database ACL; do not hand edit.", + f"-- Render phase: {phase.value}", + "-- Source revisions:", + *[ + f"-- {source.source_key}: {source.repository}@{source.revision} " + f"{source.path} sha256:{source.sha256}" + for source in matrix.sources + ], + "\\set ON_ERROR_STOP on", + "BEGIN;", + "DO $acl_database_guard$ BEGIN", + f" IF current_database() <> '{application_physical_database}' THEN", + " RAISE EXCEPTION 'application ACL connected to unexpected database %', " + "current_database();", + " END IF;", + "END $acl_database_guard$;", + "LOCK TABLE pg_catalog.pg_authid IN SHARE MODE;", + "LOCK TABLE pg_catalog.pg_auth_members IN SHARE MODE;", + "LOCK TABLE pg_catalog.pg_database IN SHARE MODE;", + "LOCK TABLE pg_catalog.pg_namespace IN SHARE MODE;", + "LOCK TABLE pg_catalog.pg_class IN SHARE MODE;", + "LOCK TABLE pg_catalog.pg_attribute IN SHARE MODE;", + "LOCK TABLE pg_catalog.pg_proc IN SHARE MODE;", + "LOCK TABLE pg_catalog.pg_type IN SHARE MODE;", + "LOCK TABLE pg_catalog.pg_extension IN SHARE MODE;", + "LOCK TABLE pg_catalog.pg_depend IN SHARE MODE;", + "LOCK TABLE pg_catalog.pg_default_acl IN SHARE MODE;", + "LOCK TABLE pg_catalog.pg_description IN SHARE MODE;", + "LOCK TABLE pg_catalog.pg_shdescription IN SHARE MODE;", + "", + ] + lines.extend( + [ + "DO $acl_evidence_guard$", + "DECLARE actual_owner text;", + "DECLARE actual_objects text[];", + "BEGIN", + ] + ) + for role_name in globally_observed_roles: + lines.extend( + [ + " IF NOT EXISTS (SELECT 1 FROM pg_catalog.pg_authid role", + f" WHERE role.rolname = '{role_name}') THEN", + f" RAISE EXCEPTION 'locked role census is stale: expected present role {role_name}';", + " END IF;", + ] + ) + for role_name, observed_state in sorted(observed_states.items()): + accepted_state_clauses = [role_state_match_clause(observed_state)] + governed_state = governed_states.get(role_name) + if governed_state is not None and governed_state.manage_attributes: + accepted_state_clauses.append(role_state_match_clause(governed_state)) + accepted_state_sql = " OR ".join(sorted(set(accepted_state_clauses))) + lines.extend( + [ + " IF EXISTS (SELECT 1 FROM pg_catalog.pg_authid role", + f" WHERE role.rolname = '{role_name}'", + f" AND NOT ({accepted_state_sql})) THEN", + f" RAISE EXCEPTION 'locked role attribute census is stale for {role_name}';", + " END IF;", + ] + ) + for role_name, state in sorted(governed_states.items()): + if state.manage_attributes: + continue + mismatch = " OR ".join(role_attribute_sql(role_name)) + lines.extend( + [ + " IF EXISTS (SELECT 1 FROM pg_catalog.pg_authid role", + f" WHERE role.rolname = '{role_name}'", + f" AND ({mismatch})) THEN", + f" RAISE EXCEPTION 'non-mutating governed role {role_name} has unsafe attributes';", + " END IF;", + ] + ) + allowed_membership_conditions = [ + f"(parent.rolname = '{membership.role}' AND member.rolname = '{membership.member}')" + for membership in matrix.allowed_memberships + ] + allowed_membership_sql = ( + " AND NOT (" + " OR ".join(allowed_membership_conditions) + ")" + if allowed_membership_conditions + else "" + ) + for role_name in sorted(globally_absent_roles.intersection(governed_states)): + state = governed_states[role_name] + if not state.manage_attributes: + continue + marker = _managed_provenance_marker(matrix, kind="role", name=role_name) + mismatch = " OR ".join( + ( + f"pg_catalog.shobj_description(role.oid, 'pg_authid') IS DISTINCT FROM '{marker}'", + "role.rolpassword IS NOT NULL", + *role_attribute_sql(role_name), + ) + ) + lines.extend( + [ + " IF EXISTS (SELECT 1 FROM pg_catalog.pg_authid role", + f" WHERE role.rolname = '{role_name}'", + f" AND ({mismatch}))", + " OR EXISTS (", + " SELECT 1 FROM pg_catalog.pg_auth_members membership", + " JOIN pg_catalog.pg_authid parent ON parent.oid = membership.roleid", + " JOIN pg_catalog.pg_authid member ON member.oid = membership.member", + f" WHERE (parent.rolname = '{role_name}' OR member.rolname = '{role_name}')", + f" {allowed_membership_sql}", + " ) THEN", + f" RAISE EXCEPTION 'expected-absent role collision for {role_name}';", + " END IF;", + ] + ) + for physical_database, observed_owner in sorted( + matrix.observed_connect_database_owners.items() + ): + accepted_owners = {observed_owner} + if physical_database == application_physical_database: + accepted_owners.add(application_desired_owner) + owner_literals = ", ".join(f"'{owner}'" for owner in sorted(accepted_owners)) + lines.extend( + [ + " SELECT owner.rolname INTO actual_owner", + " FROM pg_catalog.pg_database database", + " JOIN pg_catalog.pg_authid owner ON owner.oid = database.datdba", + f" WHERE database.datname = '{physical_database}';", + f" IF actual_owner IS NULL OR actual_owner NOT IN ({owner_literals}) THEN", + f" RAISE EXCEPTION 'locked database owner census is stale for {physical_database}: %', actual_owner;", + " END IF;", + ] + ) + for (database_ref, schema_name), owner in sorted(schema_owners.items()): + if schema_name is None: + continue + if schema_name in matrix.observed_schema_owners[database_ref]: + observed_schema_owner = matrix.observed_schema_owners[database_ref][ + schema_name + ] + accepted_schema_owners = ", ".join( + f"'{role}'" for role in sorted({observed_schema_owner, owner}) + ) + lines.extend( + [ + " IF NOT EXISTS (SELECT 1 FROM pg_catalog.pg_namespace namespace", + f" WHERE namespace.nspname = '{schema_name}') THEN", + f" RAISE EXCEPTION 'locked schema census is stale: expected present schema {schema_name}';", + " END IF;", + " IF EXISTS (SELECT 1 FROM pg_catalog.pg_namespace namespace", + " JOIN pg_catalog.pg_authid schema_owner ON schema_owner.oid = namespace.nspowner", + f" WHERE namespace.nspname = '{schema_name}'", + f" AND schema_owner.rolname NOT IN ({accepted_schema_owners})) THEN", + f" RAISE EXCEPTION 'locked schema owner census is stale for {schema_name}';", + " END IF;", + ] + ) + else: + marker = _managed_provenance_marker( + matrix, + kind="schema", + name=schema_name, + ) + lines.extend( + [ + " IF EXISTS (", + " SELECT 1 FROM pg_catalog.pg_namespace namespace", + " JOIN pg_catalog.pg_authid owner ON owner.oid = namespace.nspowner", + f" WHERE namespace.nspname = '{schema_name}'", + " AND (", + f" pg_catalog.obj_description(namespace.oid, 'pg_namespace') IS DISTINCT FROM '{marker}'", + f" OR owner.rolname IS DISTINCT FROM '{owner}'", + " )", + " ) OR EXISTS (", + " SELECT 1 FROM pg_catalog.pg_depend dependency", + " JOIN pg_catalog.pg_namespace namespace", + " ON namespace.oid = dependency.refobjid", + " WHERE dependency.refclassid = 'pg_catalog.pg_namespace'::regclass", + f" AND namespace.nspname = '{schema_name}'", + " ) THEN", + f" RAISE EXCEPTION 'expected-absent schema collision for {schema_name}';", + " END IF;", + ] + ) + if phase is EnumApplicationDatabaseAclRenderPhase.FULL: + managed_schema_literals = ", ".join( + repr(schema_name) + for schema_name in sorted( + { + schema_name + for schemas in matrix.schema_domains.values() + for schema_name in schemas + } + ) + ) + expected_object_identities = tuple( + sorted( + "|".join( + ( + obj.catalog_kind, + obj.schema_ref, + obj.object_ref, + obj.function_signature or "", + ) + ) + for obj in matrix.observed_objects + ) + ) + expected_object_array = ( + "ARRAY[" + + ", ".join( + _quote_sql_literal(identity) for identity in expected_object_identities + ) + + "]::text[]" + if expected_object_identities + else "ARRAY[]::text[]" + ) + lines.extend( + [ + " SELECT COALESCE(array_agg(catalog_identity), ARRAY[]::text[])", + " INTO actual_objects", + " FROM (", + " SELECT CASE relation.relkind", + " WHEN 'r' THEN 'table'", + " WHEN 'p' THEN 'table'", + " WHEN 'v' THEN 'view'", + " WHEN 'm' THEN 'materialized_view'", + " WHEN 'S' THEN 'sequence'", + " END || '|' || namespace.nspname || '|' ||", + " relation.relname || '|' AS catalog_identity", + " FROM pg_catalog.pg_class relation", + " JOIN pg_catalog.pg_namespace namespace ON namespace.oid = relation.relnamespace", + f" WHERE namespace.nspname IN ({managed_schema_literals})", + " AND relation.relkind IN ('r', 'p', 'v', 'm', 'S')", + " UNION ALL", + " SELECT CASE WHEN procedure.prokind = 'p'", + " THEN 'procedure' ELSE 'function' END || '|' ||", + " namespace.nspname || '|' || procedure.proname || '|' ||", + " '(' || pg_catalog.pg_get_function_identity_arguments(procedure.oid) || ')'", + " FROM pg_catalog.pg_proc procedure", + " JOIN pg_catalog.pg_namespace namespace ON namespace.oid = procedure.pronamespace", + f" WHERE namespace.nspname IN ({managed_schema_literals})", + " AND procedure.prokind IN ('f', 'p')", + " UNION ALL", + " SELECT 'type|' || namespace.nspname || '|' || type.typname || '|'", + " FROM pg_catalog.pg_type type", + " JOIN pg_catalog.pg_namespace namespace ON namespace.oid = type.typnamespace", + " LEFT JOIN pg_catalog.pg_class relation ON relation.oid = type.typrelid", + f" WHERE namespace.nspname IN ({managed_schema_literals})", + " AND type.typisdefined", + " AND ((type.typtype IN ('b', 'd', 'e', 'r', 'm') AND type.typelem = 0)", + " OR (type.typtype = 'c' AND relation.relkind = 'c'))", + " ) locked_object_census;", + f" IF cardinality(actual_objects) <> {len(expected_object_identities)}", + f" OR NOT (actual_objects @> {expected_object_array}", + f" AND actual_objects <@ {expected_object_array}) THEN", + " RAISE EXCEPTION 'locked object census is stale: %', actual_objects;", + " END IF;", + ] + ) + for observed_object in sorted( + matrix.observed_objects, + key=lambda obj: obj.identity, + ): + identity = observed_object.identity + desired_owner = desired_object_owners[identity] + accepted_object_owners = ", ".join( + repr(owner) for owner in sorted({observed_object.owner, desired_owner}) + ) + if observed_object.catalog_kind in { + "table", + "view", + "materialized_view", + "sequence", + }: + relkind_condition = { + "table": "relation.relkind IN ('r', 'p')", + "view": "relation.relkind = 'v'", + "materialized_view": "relation.relkind = 'm'", + "sequence": "relation.relkind = 'S'", + }[observed_object.catalog_kind] + owner_query = [ + " SELECT owner.rolname INTO actual_owner", + " FROM pg_catalog.pg_class relation", + " JOIN pg_catalog.pg_namespace namespace ON namespace.oid = relation.relnamespace", + " JOIN pg_catalog.pg_authid owner ON owner.oid = relation.relowner", + f" WHERE namespace.nspname = '{observed_object.schema_ref}'", + f" AND relation.relname = '{observed_object.object_ref}'", + f" AND {relkind_condition};", + ] + elif observed_object.catalog_kind in {"function", "procedure"}: + prokind = "p" if observed_object.catalog_kind == "procedure" else "f" + owner_query = [ + " SELECT owner.rolname INTO actual_owner", + " FROM pg_catalog.pg_proc procedure", + " JOIN pg_catalog.pg_namespace namespace ON namespace.oid = procedure.pronamespace", + " JOIN pg_catalog.pg_authid owner ON owner.oid = procedure.proowner", + f" WHERE namespace.nspname = '{observed_object.schema_ref}'", + f" AND procedure.proname = '{observed_object.object_ref}'", + f" AND procedure.prokind = '{prokind}'", + " AND '(' || pg_catalog.pg_get_function_identity_arguments(procedure.oid) || ')' = " + f"{_quote_sql_literal(observed_object.function_signature or '')};", + ] + else: + owner_query = [ + " SELECT owner.rolname INTO actual_owner", + " FROM pg_catalog.pg_type type", + " JOIN pg_catalog.pg_namespace namespace ON namespace.oid = type.typnamespace", + " JOIN pg_catalog.pg_authid owner ON owner.oid = type.typowner", + " LEFT JOIN pg_catalog.pg_class relation ON relation.oid = type.typrelid", + f" WHERE namespace.nspname = '{observed_object.schema_ref}'", + f" AND type.typname = '{observed_object.object_ref}'", + " AND type.typisdefined", + " AND ((type.typtype IN ('b', 'd', 'e', 'r', 'm') AND type.typelem = 0)", + " OR (type.typtype = 'c' AND relation.relkind = 'c'));", + ] + lines.extend( + [ + *owner_query, + f" IF actual_owner IS NULL OR actual_owner NOT IN ({accepted_object_owners}) THEN", + " RAISE EXCEPTION 'locked object owner census is stale for " + f"{observed_object.schema_ref}.{observed_object.object_ref}: %', actual_owner;", + " END IF;", + ] + ) + lines.extend(["END", "$acl_evidence_guard$;", ""]) + + for role_name, state in sorted(governed_states.items()): + if not state.manage_attributes: + continue + quoted = _quote_identifier(role_name) + attributes = role_attribute_clause(role_name) + if role_name in globally_absent_roles: + marker = _managed_provenance_marker(matrix, kind="role", name=role_name) + lines.extend( + [ + "DO $acl_create_role$ BEGIN", + f" IF NOT EXISTS (SELECT 1 FROM pg_catalog.pg_authid WHERE rolname = '{role_name}') THEN", # noqa: S608 -- strict identifier + f" CREATE ROLE {quoted} {attributes};", + f" COMMENT ON ROLE {quoted} IS '{marker}';", + " END IF;", + "END $acl_create_role$;", + ] + ) + if phase is EnumApplicationDatabaseAclRenderPhase.FULL: + lines.append(f"ALTER ROLE {quoted} {attributes};") + membership_members = sorted( + set(revocation_principals).union(owners) + - set(matrix.retained_administrative_principals) + ) + governed_parents = sorted( + state.role for state in matrix.governed_role_states if state.manage_memberships + ) + member_literals = ", ".join(repr(name) for name in membership_members) + parent_literals = ", ".join(repr(name) for name in governed_parents) + if phase is EnumApplicationDatabaseAclRenderPhase.FULL: + lines.extend( + [ + "DO $acl_membership$", + "DECLARE membership_record record;", + "BEGIN", + " FOR membership_record IN", + " SELECT parent.rolname AS parent_role,", + " member.rolname AS member_role,", + " grantor.rolname AS grantor_role", + " FROM pg_auth_members membership", + " JOIN pg_roles parent ON parent.oid = membership.roleid", + " JOIN pg_roles member ON member.oid = membership.member", + " JOIN pg_roles grantor ON grantor.oid = membership.grantor", + f" WHERE member.rolname IN ({member_literals})", + f" OR parent.rolname IN ({parent_literals})", + " LOOP", + " IF EXISTS (", + " SELECT 1 FROM pg_catalog.pg_auth_members current_membership", + " JOIN pg_catalog.pg_authid parent ON parent.oid = current_membership.roleid", + " JOIN pg_catalog.pg_authid member ON member.oid = current_membership.member", + " JOIN pg_catalog.pg_authid grantor ON grantor.oid = current_membership.grantor", + " WHERE parent.rolname = membership_record.parent_role", + " AND member.rolname = membership_record.member_role", + " AND grantor.rolname = membership_record.grantor_role", + " ) THEN", + " EXECUTE format('SET LOCAL ROLE %I', membership_record.grantor_role);", + " EXECUTE format(", + " 'REVOKE %I FROM %I GRANTED BY %I CASCADE',", + " membership_record.parent_role,", + " membership_record.member_role,", + " membership_record.grantor_role", + " );", + " EXECUTE 'RESET ROLE';", + " END IF;", + " END LOOP;", + "END", + "$acl_membership$;", + ] + ) + for membership in matrix.allowed_memberships: + lines.append( + f"GRANT {_quote_identifier(membership.role)} TO " + f"{_quote_identifier(membership.member)} WITH ADMIN " + f"{'TRUE' if membership.admin_option else 'FALSE'}, INHERIT " + f"{'TRUE' if membership.inherit_option else 'FALSE'}, SET " + f"{'TRUE' if membership.set_option else 'FALSE'};" + ) + + database_literals = ", ".join( + repr(database) for database in matrix.required_connect_databases + ) + if phase is EnumApplicationDatabaseAclRenderPhase.FULL: + lines.extend( + [ + "DO $acl_database_grantors$", + "DECLARE acl_record record;", + "DECLARE grantee_sql text;", + "BEGIN", + " FOR acl_record IN", + " SELECT database.datname AS database_name,", + " COALESCE(grantee.rolname, 'PUBLIC') AS grantee,", + " grantor.rolname AS grantor, acl.privilege_type", + " FROM pg_catalog.pg_database database", + " CROSS JOIN LATERAL pg_catalog.aclexplode(", + " COALESCE(database.datacl, pg_catalog.acldefault('d', database.datdba))", + " ) acl", + " LEFT JOIN pg_catalog.pg_authid grantee ON grantee.oid = acl.grantee", + " JOIN pg_catalog.pg_authid grantor ON grantor.oid = acl.grantor", + f" WHERE database.datname IN ({database_literals})", + " AND acl.grantee <> database.datdba", + " LOOP", + " grantee_sql := CASE WHEN acl_record.grantee = 'PUBLIC'", + " THEN 'PUBLIC'", + " ELSE format('%I', acl_record.grantee) END;", + " IF EXISTS (", + " SELECT 1 FROM pg_catalog.pg_database current_database_acl", + " CROSS JOIN LATERAL pg_catalog.aclexplode(", + " COALESCE(current_database_acl.datacl,", + " pg_catalog.acldefault('d', current_database_acl.datdba))", + " ) current_acl", + " LEFT JOIN pg_catalog.pg_authid current_grantee ON current_grantee.oid = current_acl.grantee", + " JOIN pg_catalog.pg_authid current_grantor ON current_grantor.oid = current_acl.grantor", + " WHERE current_database_acl.datname = acl_record.database_name", + " AND COALESCE(current_grantee.rolname, 'PUBLIC') = acl_record.grantee", + " AND current_grantor.rolname = acl_record.grantor", + " AND current_acl.privilege_type = acl_record.privilege_type", + " ) THEN", + " EXECUTE format('SET LOCAL ROLE %I', acl_record.grantor);", + " EXECUTE format(", + " 'REVOKE %s ON DATABASE %I FROM %s GRANTED BY %I CASCADE',", + " acl_record.privilege_type, acl_record.database_name,", + " grantee_sql, acl_record.grantor", + " );", + " EXECUTE 'RESET ROLE';", + " END IF;", + " END LOOP;", + "END", + "$acl_database_grantors$;", + ] + ) + + database_rows = [ + row + for row in matrix.rows + if row.object_type is EnumDatabaseGrantObjectType.DATABASE + ] + for physical_database in matrix.required_connect_databases: + connection_grantees = ", ".join( + ["PUBLIC", *(_quote_identifier(name) for name in revocation_principals)] + ) + quoted_database = _quote_identifier(physical_database) + if phase is EnumApplicationDatabaseAclRenderPhase.FULL: + lines.append( + f"REVOKE ALL PRIVILEGES ON DATABASE {quoted_database} FROM " + f"{connection_grantees} CASCADE;" + ) + for principal in matrix.allowed_connect_principals[physical_database]: + lines.append( + f"GRANT CONNECT ON DATABASE {quoted_database} TO " + f"{_quote_identifier(principal)};" + ) + database_grantees = ", ".join( + ["PUBLIC", *(_quote_identifier(name) for name in revocation_principals)] + ) + for physical_database in ( + sorted({row.physical_database for row in database_rows}) + if phase is EnumApplicationDatabaseAclRenderPhase.FULL + else () + ): + quoted_database = _quote_identifier(physical_database) + database_ref = next( + row.database_ref + for row in database_rows + if row.physical_database == physical_database + ) + lines.append( + f"ALTER DATABASE {quoted_database} OWNER TO " + f"{_quote_identifier(matrix.database_owners[database_ref])};" + ) + lines.append( + f"REVOKE ALL PRIVILEGES ON DATABASE {quoted_database} FROM " + f"{database_grantees} CASCADE;" + ) + for row in database_rows: + if row.physical_database != physical_database or not row.privileges: + continue + privileges = ", ".join(p.value for p in row.privileges) + lines.append( + f"GRANT {privileges} ON DATABASE {quoted_database} TO " + f"{_quote_identifier(row.principal)};" + ) + + schema_rows = [ + row + for row in matrix.rows + if row.object_type is EnumDatabaseGrantObjectType.SCHEMA + ] + schema_literals = ", ".join( + repr(schema_name) + for schema_name in sorted( + {"public", *(schema_name for _, schema_name in schema_owners)} + ) + ) + if phase is EnumApplicationDatabaseAclRenderPhase.FULL: + lines.extend( + [ + "DO $acl_schema_grantors$", + "DECLARE acl_record record;", + "DECLARE grantee_sql text;", + "BEGIN", + " FOR acl_record IN", + " SELECT namespace.nspname AS schema_name,", + " COALESCE(grantee.rolname, 'PUBLIC') AS grantee,", + " grantor.rolname AS grantor, acl.privilege_type", + " FROM pg_catalog.pg_namespace namespace", + " CROSS JOIN LATERAL pg_catalog.aclexplode(", + " COALESCE(namespace.nspacl, pg_catalog.acldefault('n', namespace.nspowner))", + " ) acl", + " LEFT JOIN pg_catalog.pg_authid grantee ON grantee.oid = acl.grantee", + " JOIN pg_catalog.pg_authid grantor ON grantor.oid = acl.grantor", + f" WHERE namespace.nspname IN ({schema_literals})", + " AND acl.grantee <> namespace.nspowner", + " LOOP", + " grantee_sql := CASE WHEN acl_record.grantee = 'PUBLIC'", + " THEN 'PUBLIC'", + " ELSE format('%I', acl_record.grantee) END;", + " IF EXISTS (", + " SELECT 1 FROM pg_catalog.pg_namespace current_namespace", + " CROSS JOIN LATERAL pg_catalog.aclexplode(", + " COALESCE(current_namespace.nspacl,", + " pg_catalog.acldefault('n', current_namespace.nspowner))", + " ) current_acl", + " LEFT JOIN pg_catalog.pg_authid current_grantee ON current_grantee.oid = current_acl.grantee", + " JOIN pg_catalog.pg_authid current_grantor ON current_grantor.oid = current_acl.grantor", + " WHERE current_namespace.nspname = acl_record.schema_name", + " AND COALESCE(current_grantee.rolname, 'PUBLIC') = acl_record.grantee", + " AND current_grantor.rolname = acl_record.grantor", + " AND current_acl.privilege_type = acl_record.privilege_type", + " ) THEN", + " EXECUTE format('SET LOCAL ROLE %I', acl_record.grantor);", + " EXECUTE format(", + " 'REVOKE %s ON SCHEMA %I FROM %s GRANTED BY %I CASCADE',", + " acl_record.privilege_type, acl_record.schema_name,", + " grantee_sql, acl_record.grantor", + " );", + " EXECUTE 'RESET ROLE';", + " END IF;", + " END LOOP;", + "END", + "$acl_schema_grantors$;", + ] + ) + for (database_ref, schema_name), owner in sorted(schema_owners.items()): + if schema_name is None: + continue + quoted_schema = _quote_identifier(schema_name) + quoted_owner = _quote_identifier(owner) + if schema_name in matrix.absent_schemas[database_ref]: + marker = _managed_provenance_marker( + matrix, + kind="schema", + name=schema_name, + ) + lines.extend( + [ + "DO $acl_create_schema$ BEGIN", + " IF NOT EXISTS (SELECT 1 FROM pg_catalog.pg_namespace", + f" WHERE nspname = '{schema_name}') THEN", + f" CREATE SCHEMA {quoted_schema} AUTHORIZATION {quoted_owner};", + f" COMMENT ON SCHEMA {quoted_schema} IS '{marker}';", + " END IF;", + "END $acl_create_schema$;", + ] + ) + if phase is EnumApplicationDatabaseAclRenderPhase.FULL: + lines.extend( + [ + f"ALTER SCHEMA {quoted_schema} OWNER TO {quoted_owner};", + f"REVOKE ALL PRIVILEGES ON SCHEMA {quoted_schema} FROM " + f"{database_grantees} CASCADE;", + ] + ) + for row in schema_rows: + if ( + row.database_ref != database_ref + or row.schema_ref != schema_name + or not row.privileges + ): + continue + privileges = ", ".join(p.value for p in row.privileges) + lines.append( + f"GRANT {privileges} ON SCHEMA {quoted_schema} TO " + f"{_quote_identifier(row.principal)};" + ) + if phase is EnumApplicationDatabaseAclRenderPhase.FULL: + lines.append( + f'REVOKE ALL PRIVILEGES ON SCHEMA "public" FROM {database_grantees} CASCADE;' + ) + lines.append("") + + rows_by_object: dict[ + tuple[str, str, EnumDatabaseGrantObjectType, str, str | None], + list[ModelApplicationDatabaseAclRow], + ] = defaultdict(list) + for row in matrix.rows: + if row.object_type in _OBJECT_TYPES: + rows_by_object[ + ( + row.database_ref, + row.schema_ref or "", + row.object_type, + row.object_ref or "", + row.function_signature, + ) + ].append(row) + all_grantees = ", ".join( + ["PUBLIC", *(_quote_identifier(name) for name in revocation_principals)] + ) + ownership_order = { + EnumDatabaseGrantObjectType.TABLE: 0, + EnumDatabaseGrantObjectType.SEQUENCE: 1, + EnumDatabaseGrantObjectType.TYPE: 2, + EnumDatabaseGrantObjectType.FUNCTION: 3, + } + for obj in sorted( + (matrix.objects if phase is EnumApplicationDatabaseAclRenderPhase.FULL else ()), + key=lambda item: ( + ownership_order[item.object_type], + item.database_ref, + item.schema_ref, + item.object_ref, + item.function_signature or "", + ), + ): + owner_keyword, acl_keyword, target = _sql_object_target(obj) + dynamic_target = target.replace("%", "%%") + dynamic_revoke_pattern = ( + f"REVOKE %s ON {acl_keyword} {dynamic_target} FROM %s GRANTED BY %I CASCADE" + ) + if obj.object_type in { + EnumDatabaseGrantObjectType.TABLE, + EnumDatabaseGrantObjectType.SEQUENCE, + }: + default_acl_kind = ( + "s" if obj.object_type is EnumDatabaseGrantObjectType.SEQUENCE else "r" + ) + relkind_condition = { + "table": "object.relkind IN ('r', 'p')", + "view": "object.relkind = 'v'", + "materialized_view": "object.relkind = 'm'", + "sequence": "object.relkind = 'S'", + }[obj.catalog_kind] + catalog_acl_lines = [ + " FROM pg_catalog.pg_class object", + " JOIN pg_catalog.pg_namespace namespace ON namespace.oid = object.relnamespace", + " CROSS JOIN LATERAL pg_catalog.aclexplode(", + f" COALESCE(object.relacl, pg_catalog.acldefault('{default_acl_kind}', object.relowner))", + " ) acl", + " LEFT JOIN pg_catalog.pg_authid grantee ON grantee.oid = acl.grantee", + " JOIN pg_catalog.pg_authid grantor ON grantor.oid = acl.grantor", + f" WHERE namespace.nspname = '{obj.schema_ref}'", + f" AND object.relname = '{obj.object_ref}'", + f" AND {relkind_condition}", + " AND acl.grantee <> object.relowner", + ] + elif obj.object_type is EnumDatabaseGrantObjectType.FUNCTION: + prokind = "p" if obj.catalog_kind == "procedure" else "f" + catalog_acl_lines = [ + " FROM pg_catalog.pg_proc object", + " JOIN pg_catalog.pg_namespace namespace ON namespace.oid = object.pronamespace", + " CROSS JOIN LATERAL pg_catalog.aclexplode(", + " COALESCE(object.proacl, pg_catalog.acldefault('f', object.proowner))", + " ) acl", + " LEFT JOIN pg_catalog.pg_authid grantee ON grantee.oid = acl.grantee", + " JOIN pg_catalog.pg_authid grantor ON grantor.oid = acl.grantor", + f" WHERE namespace.nspname = '{obj.schema_ref}'", + f" AND object.proname = '{obj.object_ref}'", + f" AND object.prokind = '{prokind}'", + " AND '(' || pg_catalog.pg_get_function_identity_arguments(object.oid) || ')' = " + f"{_quote_sql_literal(obj.function_signature or '')}", + " AND acl.grantee <> object.proowner", + ] + else: + catalog_acl_lines = [ + " FROM pg_catalog.pg_type object", + " JOIN pg_catalog.pg_namespace namespace ON namespace.oid = object.typnamespace", + " CROSS JOIN LATERAL pg_catalog.aclexplode(", + " COALESCE(object.typacl, pg_catalog.acldefault('T', object.typowner))", + " ) acl", + " LEFT JOIN pg_catalog.pg_authid grantee ON grantee.oid = acl.grantee", + " JOIN pg_catalog.pg_authid grantor ON grantor.oid = acl.grantor", + f" WHERE namespace.nspname = '{obj.schema_ref}'", + f" AND object.typname = '{obj.object_ref}'", + " AND acl.grantee <> object.typowner", + ] + lines.extend( + [ + "DO $acl_object_grantors$", + "DECLARE acl_record record;", + "DECLARE grantee_sql text;", + "DECLARE temporary_schema_usage boolean;", + "BEGIN", + " FOR acl_record IN", + " SELECT COALESCE(grantee.rolname, 'PUBLIC') AS grantee,", + " grantor.rolname AS grantor, acl.privilege_type", + *catalog_acl_lines, + " LOOP", + " grantee_sql := CASE WHEN acl_record.grantee = 'PUBLIC'", + " THEN 'PUBLIC'", + " ELSE format('%I', acl_record.grantee) END;", + " IF EXISTS (", + " SELECT 1", + *catalog_acl_lines, + " AND COALESCE(grantee.rolname, 'PUBLIC') = acl_record.grantee", + " AND grantor.rolname = acl_record.grantor", + " AND acl.privilege_type = acl_record.privilege_type", + " ) THEN", + " SELECT NOT pg_catalog.has_schema_privilege(", + f" acl_record.grantor, '{obj.schema_ref}', 'USAGE'", + " ) INTO temporary_schema_usage;", + " IF temporary_schema_usage THEN", + " EXECUTE format(", + f" 'GRANT USAGE ON SCHEMA %I TO %I', '{obj.schema_ref}',", + " acl_record.grantor", + " );", + " END IF;", + " EXECUTE format('SET LOCAL ROLE %I', acl_record.grantor);", + " EXECUTE format(", + f" {_quote_sql_literal(dynamic_revoke_pattern)},", + " acl_record.privilege_type, grantee_sql, acl_record.grantor", + " );", + " EXECUTE 'RESET ROLE';", + " IF temporary_schema_usage THEN", + " EXECUTE format(", + f" 'REVOKE USAGE ON SCHEMA %I FROM %I CASCADE', '{obj.schema_ref}',", + " acl_record.grantor", + " );", + " END IF;", + " END IF;", + " END LOOP;", + "END", + "$acl_object_grantors$;", + ] + ) + lines.append( + f"ALTER {owner_keyword} {target} OWNER TO {_quote_identifier(obj.owner)};" + ) + lines.append( + f"REVOKE ALL PRIVILEGES ON {acl_keyword} {target} FROM " + f"{all_grantees} CASCADE;" + ) + if obj.object_type is EnumDatabaseGrantObjectType.TABLE: + lines.extend( + [ + "DO $acl_column_grantors$", + "DECLARE acl_record record;", + "DECLARE grantee_sql text;", + "DECLARE temporary_schema_usage boolean;", + "BEGIN", + " FOR acl_record IN", + " SELECT attribute.attname AS column_name,", + " COALESCE(grantee.rolname, 'PUBLIC') AS grantee,", + " grantor.rolname AS grantor, acl.privilege_type", + " FROM pg_catalog.pg_attribute attribute", + " JOIN pg_catalog.pg_class relation ON relation.oid = attribute.attrelid", + " JOIN pg_catalog.pg_namespace namespace ON namespace.oid = relation.relnamespace", + " CROSS JOIN LATERAL pg_catalog.aclexplode(attribute.attacl) acl", + " LEFT JOIN pg_catalog.pg_authid grantee ON grantee.oid = acl.grantee", + " JOIN pg_catalog.pg_authid grantor ON grantor.oid = acl.grantor", + f" WHERE namespace.nspname = '{obj.schema_ref}'", + f" AND relation.relname = '{obj.object_ref}'", + " AND attribute.attnum > 0 AND NOT attribute.attisdropped", + " AND attribute.attacl IS NOT NULL", + " LOOP", + " grantee_sql := CASE WHEN acl_record.grantee = 'PUBLIC'", + " THEN 'PUBLIC'", + " ELSE format('%I', acl_record.grantee) END;", + " IF EXISTS (", + " SELECT 1 FROM pg_catalog.pg_attribute current_attribute", + " JOIN pg_catalog.pg_class current_relation ON current_relation.oid = current_attribute.attrelid", + " JOIN pg_catalog.pg_namespace current_namespace ON current_namespace.oid = current_relation.relnamespace", + " CROSS JOIN LATERAL pg_catalog.aclexplode(current_attribute.attacl) current_acl", + " LEFT JOIN pg_catalog.pg_authid current_grantee ON current_grantee.oid = current_acl.grantee", + " JOIN pg_catalog.pg_authid current_grantor ON current_grantor.oid = current_acl.grantor", + f" WHERE current_namespace.nspname = '{obj.schema_ref}'", + f" AND current_relation.relname = '{obj.object_ref}'", + " AND current_attribute.attname = acl_record.column_name", + " AND COALESCE(current_grantee.rolname, 'PUBLIC') = acl_record.grantee", + " AND current_grantor.rolname = acl_record.grantor", + " AND current_acl.privilege_type = acl_record.privilege_type", + " ) THEN", + " SELECT NOT pg_catalog.has_schema_privilege(", + f" acl_record.grantor, '{obj.schema_ref}', 'USAGE'", + " ) INTO temporary_schema_usage;", + " IF temporary_schema_usage THEN", + " EXECUTE format(", + f" 'GRANT USAGE ON SCHEMA %I TO %I', '{obj.schema_ref}',", + " acl_record.grantor", + " );", + " END IF;", + " EXECUTE format('SET LOCAL ROLE %I', acl_record.grantor);", + " EXECUTE format(", + " 'REVOKE %s (%I) ON TABLE %I.%I FROM %s GRANTED BY %I CASCADE',", + " acl_record.privilege_type, acl_record.column_name,", + f" '{obj.schema_ref}', '{obj.object_ref}', grantee_sql, acl_record.grantor", + " );", + " EXECUTE 'RESET ROLE';", + " IF temporary_schema_usage THEN", + " EXECUTE format(", + f" 'REVOKE USAGE ON SCHEMA %I FROM %I CASCADE', '{obj.schema_ref}',", + " acl_record.grantor", + " );", + " END IF;", + " END IF;", + " END LOOP;", + "END", + "$acl_column_grantors$;", + "DO $acl_columns$", + "DECLARE column_name text;", + "BEGIN", + " FOR column_name IN", + " SELECT attribute.attname", + " FROM pg_attribute attribute", + " JOIN pg_class relation ON relation.oid = attribute.attrelid", + " JOIN pg_namespace namespace ON namespace.oid = relation.relnamespace", + f" WHERE namespace.nspname = '{obj.schema_ref}'", + f" AND relation.relname = '{obj.object_ref}'", + " AND attribute.attnum > 0 AND NOT attribute.attisdropped", + " LOOP", + " EXECUTE format(", + f" 'REVOKE ALL PRIVILEGES (%I) ON TABLE %I.%I FROM {all_grantees} CASCADE',", + f" column_name, '{obj.schema_ref}', '{obj.object_ref}'", + " );", + " END LOOP;", + "END", + "$acl_columns$;", + ] + ) + for row in rows_by_object[obj.identity]: + if not row.privileges: + continue + privileges = ", ".join(p.value for p in row.privileges) + lines.append( + f"GRANT {privileges} ON {acl_keyword} {target} TO " + f"{_quote_identifier(row.principal)};" + ) + + default_keyword = { + EnumDatabaseGrantObjectType.TABLE: "TABLES", + EnumDatabaseGrantObjectType.SEQUENCE: "SEQUENCES", + EnumDatabaseGrantObjectType.FUNCTION: "FUNCTIONS", + EnumDatabaseGrantObjectType.TYPE: "TYPES", + } + default_owner_scope = {row.owner for row in matrix.default_privileges} + if phase is EnumApplicationDatabaseAclRenderPhase.SCAFFOLD: + # P1 may establish deny-by-default only for roles it creates from exact + # absence evidence. Existing owners' legacy defaults remain untouched. + default_owner_scope.intersection_update(globally_absent_roles) + phase_default_rows = tuple( + row for row in matrix.default_privileges if row.owner in default_owner_scope + ) + global_default_identities = sorted( + {(row.owner, row.object_type) for row in phase_default_rows}, + key=lambda item: (item[0], item[1].value), + ) + default_owner_literals = ", ".join( + _quote_sql_literal(owner) for owner in sorted(default_owner_scope) + ) + managed_default_schema_literals = ", ".join( + _quote_sql_literal(schema_name) + for schema_name in sorted({row.schema_ref for row in phase_default_rows}) + ) + if phase_default_rows: + lines.extend( + [ + "DO $acl_default_grantor_guard$ BEGIN", + " IF EXISTS (", + " SELECT 1 FROM pg_catalog.pg_default_acl defaults", + " JOIN pg_catalog.pg_authid owner ON owner.oid = defaults.defaclrole", + " LEFT JOIN pg_catalog.pg_namespace namespace ON namespace.oid = defaults.defaclnamespace", + " CROSS JOIN LATERAL pg_catalog.aclexplode(defaults.defaclacl) acl", + " LEFT JOIN pg_catalog.pg_authid grantee ON grantee.oid = acl.grantee", + " JOIN pg_catalog.pg_authid grantor ON grantor.oid = acl.grantor", + f" WHERE owner.rolname IN ({default_owner_literals})", + " AND (defaults.defaclnamespace = 0", + f" OR namespace.nspname IN ({managed_default_schema_literals}))", + " AND grantor.oid <> defaults.defaclrole", + " ) THEN", + " RAISE EXCEPTION 'default ACL contains an unsupported alternate grantor';", + " END IF;", + "END $acl_default_grantor_guard$;", + "DO $acl_default_actual_rows$", + "DECLARE acl_record record;", + "DECLARE grantee_sql text;", + "BEGIN", + " FOR acl_record IN", + " SELECT owner.rolname AS owner, namespace.nspname AS schema_name,", + " CASE defaults.defaclobjtype", + " WHEN 'r' THEN 'TABLES'", + " WHEN 'S' THEN 'SEQUENCES'", + " WHEN 'f' THEN 'FUNCTIONS'", + " WHEN 'T' THEN 'TYPES'", + " END AS object_keyword,", + " COALESCE(grantee.rolname, 'PUBLIC') AS grantee,", + " acl.privilege_type", + " FROM pg_catalog.pg_default_acl defaults", + " JOIN pg_catalog.pg_authid owner ON owner.oid = defaults.defaclrole", + " LEFT JOIN pg_catalog.pg_namespace namespace ON namespace.oid = defaults.defaclnamespace", + " CROSS JOIN LATERAL pg_catalog.aclexplode(defaults.defaclacl) acl", + " LEFT JOIN pg_catalog.pg_authid grantee ON grantee.oid = acl.grantee", + f" WHERE owner.rolname IN ({default_owner_literals})", + " AND (defaults.defaclnamespace = 0", + f" OR namespace.nspname IN ({managed_default_schema_literals}))", + " AND acl.grantee <> defaults.defaclrole", + " LOOP", + " grantee_sql := CASE WHEN acl_record.grantee = 'PUBLIC'", + " THEN 'PUBLIC'", + " ELSE format('%I', acl_record.grantee) END;", + " EXECUTE format('SET LOCAL ROLE %I', acl_record.owner);", + " IF acl_record.schema_name IS NULL THEN", + " EXECUTE format(", + " 'ALTER DEFAULT PRIVILEGES FOR ROLE %I REVOKE %s ON %s FROM %s CASCADE',", + " acl_record.owner, acl_record.privilege_type,", + " acl_record.object_keyword, grantee_sql", + " );", + " ELSE", + " EXECUTE format(", + " 'ALTER DEFAULT PRIVILEGES FOR ROLE %I IN SCHEMA %I REVOKE %s ON %s FROM %s CASCADE',", + " acl_record.owner, acl_record.schema_name,", + " acl_record.privilege_type, acl_record.object_keyword, grantee_sql", + " );", + " END IF;", + " EXECUTE 'RESET ROLE';", + " END LOOP;", + "END", + "$acl_default_actual_rows$;", + ] + ) + default_revocation_principals = (PUBLIC_PRINCIPAL, *revocation_principals) + for owner, object_type in global_default_identities: + for principal in default_revocation_principals: + grantee = ( + "PUBLIC" + if principal == PUBLIC_PRINCIPAL + else _quote_identifier(principal) + ) + lines.append( + "ALTER DEFAULT PRIVILEGES FOR ROLE " + f"{_quote_identifier(owner)} REVOKE ALL PRIVILEGES ON " + f"{default_keyword[object_type]} FROM {grantee} CASCADE;" + ) + schema_default_identities = sorted( + {(row.owner, row.schema_ref, row.object_type) for row in phase_default_rows}, + key=lambda item: (item[0], item[1], item[2].value), + ) + for owner, schema_ref, object_type in schema_default_identities: + for principal in default_revocation_principals: + grantee = ( + "PUBLIC" + if principal == PUBLIC_PRINCIPAL + else _quote_identifier(principal) + ) + lines.append( + "ALTER DEFAULT PRIVILEGES FOR ROLE " + f"{_quote_identifier(owner)} IN SCHEMA " + f"{_quote_identifier(schema_ref)} REVOKE ALL PRIVILEGES ON " + f"{default_keyword[object_type]} FROM {grantee} CASCADE;" + ) + lines.append("COMMIT;") + return "\n".join(lines) + "\n" + + +__all__ = [ + "PUBLIC_PRINCIPAL", + "build_application_database_acl_matrix", + "render_application_database_acl_sql", + "validate_application_database_acl_scaffold", + "validate_application_database_acl_matrix", +] diff --git a/src/omnibase_infra/validation/enums/enum_application_database_acl_authorization_scope.py b/src/omnibase_infra/validation/enums/enum_application_database_acl_authorization_scope.py new file mode 100644 index 0000000000..8d0c4caf34 --- /dev/null +++ b/src/omnibase_infra/validation/enums/enum_application_database_acl_authorization_scope.py @@ -0,0 +1,17 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT + +"""Authorization boundary for generated application-database ACL matrices.""" + +from enum import StrEnum, unique + + +@unique +class EnumApplicationDatabaseAclAuthorizationScope(StrEnum): + """Separate deployment-authorized evidence from synthetic proof fixtures.""" + + DEPLOYMENT = "deployment" + SYNTHETIC_PROOF = "synthetic_proof" + + +__all__ = ["EnumApplicationDatabaseAclAuthorizationScope"] diff --git a/src/omnibase_infra/validation/enums/enum_application_database_acl_policy_source_kind.py b/src/omnibase_infra/validation/enums/enum_application_database_acl_policy_source_kind.py new file mode 100644 index 0000000000..a67765ff5c --- /dev/null +++ b/src/omnibase_infra/validation/enums/enum_application_database_acl_policy_source_kind.py @@ -0,0 +1,17 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT + +"""Evidence source kinds accepted by application-database ACL policy.""" + +from enum import StrEnum, unique + + +@unique +class EnumApplicationDatabaseAclPolicySourceKind(StrEnum): + """Distinguish authoritative topology policy from synthetic proof input.""" + + TOPOLOGY_CONTRACT = "topology_contract" + SYNTHETIC_FIXTURE = "synthetic_fixture" + + +__all__ = ["EnumApplicationDatabaseAclPolicySourceKind"] diff --git a/src/omnibase_infra/validation/enums/enum_application_database_acl_render_phase.py b/src/omnibase_infra/validation/enums/enum_application_database_acl_render_phase.py new file mode 100644 index 0000000000..3095361df2 --- /dev/null +++ b/src/omnibase_infra/validation/enums/enum_application_database_acl_render_phase.py @@ -0,0 +1,17 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT + +"""Typed stages of the additive application-database ACL rollout.""" + +from enum import StrEnum, unique + + +@unique +class EnumApplicationDatabaseAclRenderPhase(StrEnum): + """Separate the additive scaffold from materialized-object hardening.""" + + SCAFFOLD = "scaffold" + FULL = "full" + + +__all__ = ["EnumApplicationDatabaseAclRenderPhase"] diff --git a/src/omnibase_infra/validation/enums/enum_application_database_principal_inventory_source_kind.py b/src/omnibase_infra/validation/enums/enum_application_database_principal_inventory_source_kind.py new file mode 100644 index 0000000000..537987fc9e --- /dev/null +++ b/src/omnibase_infra/validation/enums/enum_application_database_principal_inventory_source_kind.py @@ -0,0 +1,17 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT + +"""Evidence source kinds accepted by application-database principal census.""" + +from enum import StrEnum, unique + + +@unique +class EnumApplicationDatabasePrincipalInventorySourceKind(StrEnum): + """Distinguish authorized catalog evidence from synthetic proof input.""" + + AUTHORIZED_CATALOG = "authorized_catalog" + SYNTHETIC_FIXTURE = "synthetic_fixture" + + +__all__ = ["EnumApplicationDatabasePrincipalInventorySourceKind"] diff --git a/src/omnibase_infra/validation/enums/enum_application_inventory_object_kind.py b/src/omnibase_infra/validation/enums/enum_application_inventory_object_kind.py index 0905843a81..48570c0a14 100644 --- a/src/omnibase_infra/validation/enums/enum_application_inventory_object_kind.py +++ b/src/omnibase_infra/validation/enums/enum_application_inventory_object_kind.py @@ -14,8 +14,10 @@ class EnumApplicationInventoryObjectKind(StrEnum): VIEW = "view" MATERIALIZED_VIEW = "materialized_view" FUNCTION = "function" + PROCEDURE = "procedure" SEQUENCE = "sequence" EXTENSION = "extension" + TYPE = "type" __all__ = ["EnumApplicationInventoryObjectKind"] diff --git a/src/omnibase_infra/validation/models/model_application_database_acl_matrix.py b/src/omnibase_infra/validation/models/model_application_database_acl_matrix.py new file mode 100644 index 0000000000..c8d3bce9f5 --- /dev/null +++ b/src/omnibase_infra/validation/models/model_application_database_acl_matrix.py @@ -0,0 +1,362 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT + +"""Typed, generated application-database ACL matrix.""" + +from __future__ import annotations + +import re +from typing import Literal + +from pydantic import BaseModel, ConfigDict, Field, model_validator + +from omnibase_core.enums.enum_database_schema_domain import EnumDatabaseSchemaDomain +from omnibase_infra.validation.enums.enum_application_database_acl_authorization_scope import ( + EnumApplicationDatabaseAclAuthorizationScope, +) +from omnibase_infra.validation.models.model_application_database_acl_object import ( + ModelApplicationDatabaseAclObject, +) +from omnibase_infra.validation.models.model_application_database_acl_row import ( + ModelApplicationDatabaseAclRow, +) +from omnibase_infra.validation.models.model_application_database_acl_source import ( + ModelApplicationDatabaseAclSource, +) +from omnibase_infra.validation.models.model_application_database_catalog_object_evidence import ( + ModelApplicationDatabaseCatalogObjectEvidence, +) +from omnibase_infra.validation.models.model_application_database_default_acl_row import ( + ModelApplicationDatabaseDefaultAclRow, +) +from omnibase_infra.validation.models.model_application_database_observed_role_state import ( + ModelApplicationDatabaseObservedRoleState, +) +from omnibase_infra.validation.models.model_application_database_role_membership import ( + ModelApplicationDatabaseRoleMembership, +) +from omnibase_infra.validation.models.model_application_database_role_state import ( + ModelApplicationDatabaseRoleState, +) + + +class ModelApplicationDatabaseAclMatrix(BaseModel): + """Complete generated role/object/default-privilege projection.""" + + model_config = ConfigDict(frozen=True, extra="forbid") + + schema_version: Literal["1.0"] = "1.0" + authorization_scope: EnumApplicationDatabaseAclAuthorizationScope + scaffold_status: Literal["READY", "BLOCKED"] + scaffold_blockers: tuple[str, ...] = () + status: Literal["READY", "BLOCKED"] + sources: tuple[ModelApplicationDatabaseAclSource, ...] = Field(..., min_length=1) + verified_evidence_source_keys: tuple[str, ...] = () + declared_principals: dict[str, tuple[str, ...]] + observed_principals: dict[str, tuple[str, ...]] + absent_principals: dict[str, tuple[str, ...]] + observed_owner_roles: tuple[str, ...] + absent_owner_roles: tuple[str, ...] + observed_role_states: tuple[ModelApplicationDatabaseObservedRoleState, ...] + governed_role_states: tuple[ModelApplicationDatabaseRoleState, ...] + retained_administrative_principals: tuple[str, ...] + database_owners: dict[str, str] + required_connect_databases: tuple[str, ...] + observed_connect_database_owners: dict[str, str] + allowed_connect_principals: dict[str, tuple[str, ...]] + observed_connect_principals: dict[str, tuple[str, ...]] + absent_connect_principals: dict[str, tuple[str, ...]] + schema_domains: dict[str, dict[str, EnumDatabaseSchemaDomain]] + observed_schema_owners: dict[str, dict[str, str]] + absent_schemas: dict[str, tuple[str, ...]] + principal_domains: dict[str, tuple[EnumDatabaseSchemaDomain, ...]] + allowed_memberships: tuple[ModelApplicationDatabaseRoleMembership, ...] + observed_objects: tuple[ModelApplicationDatabaseCatalogObjectEvidence, ...] + objects: tuple[ModelApplicationDatabaseAclObject, ...] + rows: tuple[ModelApplicationDatabaseAclRow, ...] + default_privileges: tuple[ModelApplicationDatabaseDefaultAclRow, ...] + blockers: tuple[str, ...] = () + excluded_objects: tuple[str, ...] = () + + @model_validator(mode="after") + def validate_matrix(self) -> ModelApplicationDatabaseAclMatrix: + """Keep the artifact deterministic, unique, and honest about blockers.""" + source_keys = [source.source_key for source in self.sources] + if len(set(source_keys)) != len(source_keys): + raise ValueError("ACL matrix source keys must be unique") + if len(set(self.verified_evidence_source_keys)) != len( + self.verified_evidence_source_keys + ): + raise ValueError("verified evidence source keys must be unique") + source_by_key = {source.source_key: source for source in self.sources} + unknown_verified = sorted( + set(self.verified_evidence_source_keys) - set(source_by_key) + ) + if unknown_verified: + raise ValueError( + f"verified evidence contains unknown source keys: {unknown_verified!r}" + ) + invalid_verified = sorted( + source_key + for source_key in self.verified_evidence_source_keys + if source_by_key[source_key].purpose + not in {"catalog_result_evidence", "activity_result_evidence"} + ) + if invalid_verified: + raise ValueError( + "only catalog/activity result blobs can be semantically verified: " + f"{invalid_verified!r}" + ) + if ( + self.authorization_scope + is EnumApplicationDatabaseAclAuthorizationScope.DEPLOYMENT + and (self.status == "READY" or self.scaffold_status == "READY") + ): + locked_result_keys = { + source.source_key + for source in self.sources + if source.purpose + in {"catalog_result_evidence", "activity_result_evidence"} + } + if not locked_result_keys or locked_result_keys != set( + self.verified_evidence_source_keys + ): + raise ValueError( + "READY deployment phase requires every locked catalog/activity " + "result source to be semantically verified" + ) + object_ids = [item.identity for item in self.objects] + if len(set(object_ids)) != len(object_ids): + raise ValueError("ACL matrix object identities must be unique") + row_ids = [row.identity for row in self.rows] + if len(set(row_ids)) != len(row_ids): + raise ValueError("ACL matrix row identities must be unique") + default_ids = [ + ( + row.owner, + row.database_ref, + row.schema_ref, + row.object_type, + row.grantee, + ) + for row in self.default_privileges + ] + if len(set(default_ids)) != len(default_ids): + raise ValueError("Default ACL row identities must be unique") + membership_ids = [item.identity for item in self.allowed_memberships] + if len(set(membership_ids)) != len(membership_ids): + raise ValueError("Role membership identities must be unique") + if set(self.declared_principals) != set(self.observed_principals) or set( + self.declared_principals + ) != set(self.absent_principals): + raise ValueError( + "declared/observed/absent principal database keys disagree" + ) + if set(self.schema_domains) != set(self.declared_principals): + raise ValueError("schema_domains and principal database keys disagree") + if set(self.observed_schema_owners) != set(self.schema_domains) or set( + self.absent_schemas + ) != set(self.schema_domains): + raise ValueError("schema presence/absence database keys are incomplete") + for database_ref, schemas in self.schema_domains.items(): + observed_schemas = set(self.observed_schema_owners[database_ref]) + absent_schemas = set(self.absent_schemas[database_ref]) + if observed_schemas & absent_schemas: + raise ValueError( + f"{database_ref}: schema presence/absence evidence overlaps" + ) + if self.scaffold_status == "READY" and set(schemas) != ( + observed_schemas.union(absent_schemas) + ): + raise ValueError( + f"{database_ref}: READY scaffold schema evidence is incomplete" + ) + observed_object_ids = [obj.identity for obj in self.observed_objects] + if len(set(observed_object_ids)) != len(observed_object_ids): + raise ValueError("observed catalog object identities must be unique") + expected_object_ids = { + ( + obj.catalog_kind, + obj.schema_ref, + obj.object_ref, + obj.function_signature or "", + ) + for obj in self.objects + } + if self.status == "READY" and set(observed_object_ids) != expected_object_ids: + raise ValueError( + "READY matrix requires exact live-catalog object identity coverage" + ) + if len(set(self.required_connect_databases)) != len( + self.required_connect_databases + ): + raise ValueError("required_connect_databases must be unique") + invalid_databases = sorted( + database + for database in self.required_connect_databases + if re.fullmatch(r"[a-z_][a-z0-9_]*", database) is None + ) + if invalid_databases: + raise ValueError( + f"required_connect_databases contain unsafe names: {invalid_databases!r}" + ) + if set(self.allowed_connect_principals) != set( + self.observed_connect_principals + ) or set(self.allowed_connect_principals) != set( + self.absent_connect_principals + ): + raise ValueError("allowed/observed/absent CONNECT database keys disagree") + if set(self.observed_connect_database_owners) != set( + self.allowed_connect_principals + ): + raise ValueError( + "observed CONNECT owner and principal database keys disagree" + ) + if not set(self.allowed_connect_principals) <= set( + self.required_connect_databases + ): + raise ValueError("CONNECT policies contain unrequired databases") + if self.status == "READY" and set(self.allowed_connect_principals) != set( + self.required_connect_databases + ): + raise ValueError("READY matrix requires CONNECT policy for every database") + for database, allowed in self.allowed_connect_principals.items(): + observed = self.observed_connect_principals[database] + absent = self.absent_connect_principals[database] + if set(observed) & set(absent): + raise ValueError( + f"{database}: CONNECT presence and absence evidence overlap" + ) + if not set(allowed) <= set(observed).union(absent): + raise ValueError( + f"{database}: allowed CONNECT principals lack presence/absence evidence" + ) + globally_observed = { + principal + for principals in ( + *self.observed_principals.values(), + *self.observed_connect_principals.values(), + self.observed_owner_roles, + tuple(self.observed_connect_database_owners.values()), + ) + for principal in principals + } + globally_absent = { + principal + for principals in ( + *self.absent_principals.values(), + *self.absent_connect_principals.values(), + self.absent_owner_roles, + ) + for principal in principals + } + global_evidence_conflicts = sorted(globally_observed & globally_absent) + if global_evidence_conflicts: + raise ValueError( + "cluster-global role presence/absence evidence conflicts: " + f"{global_evidence_conflicts!r}" + ) + managed_owner_evidence = set(self.observed_owner_roles).union( + self.absent_owner_roles + ) + workload_evidence = { + principal + for principals in ( + *self.declared_principals.values(), + *self.observed_principals.values(), + *self.absent_principals.values(), + *self.allowed_connect_principals.values(), + *self.observed_connect_principals.values(), + *self.absent_connect_principals.values(), + ) + for principal in principals + } + role_kind_overlap = sorted(managed_owner_evidence & workload_evidence) + if role_kind_overlap: + raise ValueError( + "managed owner and workload role evidence overlap: " + f"{role_kind_overlap!r}" + ) + invalid_owner_evidence = sorted( + role + for role in managed_owner_evidence.union( + self.observed_connect_database_owners.values() + ) + if re.fullmatch(r"[a-z_][a-z0-9_]*", role) is None + ) + if invalid_owner_evidence: + raise ValueError( + f"owner evidence contains unsafe role names: {invalid_owner_evidence!r}" + ) + desired_managed_owners = ( + set(self.database_owners.values()) + .union(obj.owner for obj in self.objects) + .union(row.owner for row in self.default_privileges) + ) + if self.scaffold_status == "READY" and not desired_managed_owners <= ( + managed_owner_evidence + ): + raise ValueError( + "READY scaffold managed owners lack presence/absence evidence: " + f"{sorted(desired_managed_owners - managed_owner_evidence)!r}" + ) + governed_roles = [state.role for state in self.governed_role_states] + if len(set(governed_roles)) != len(governed_roles): + raise ValueError("governed role states must have unique role names") + if self.scaffold_status == "READY" and not set(governed_roles) <= ( + globally_observed.union(globally_absent) + ): + raise ValueError( + "READY scaffold governed roles lack presence/absence evidence" + ) + observed_state_roles = [state.role for state in self.observed_role_states] + if len(set(observed_state_roles)) != len(observed_state_roles): + raise ValueError("observed role states must have unique role names") + observed_principal_roles = { + principal + for principals in ( + *self.observed_principals.values(), + *self.observed_connect_principals.values(), + self.observed_owner_roles, + ) + for principal in principals + } + if set(observed_state_roles) != observed_principal_roles: + raise ValueError( + "observed role states must cover the global observed principal and " + "managed-owner census" + ) + retained_admins = set(self.retained_administrative_principals) + if len(retained_admins) != len(self.retained_administrative_principals): + raise ValueError("retained administrative principals must be unique") + if not retained_admins <= observed_principal_roles: + raise ValueError( + "retained administrative principals must be in the observed census" + ) + if retained_admins & set(governed_roles): + raise ValueError( + "retained administrative principals cannot be governed roles" + ) + if not set(self.database_owners) <= set(self.declared_principals): + raise ValueError("database_owners contain unknown database keys") + if self.status == "READY" and set(self.database_owners) != set( + self.declared_principals + ): + raise ValueError("READY matrix requires an owner for every database") + if any( + len(set(principals)) != len(principals) + for principals in ( + *self.declared_principals.values(), + *self.observed_principals.values(), + *self.absent_principals.values(), + ) + ): + raise ValueError("principal collections must be unique") + if (self.status == "READY") != (not self.blockers): + raise ValueError("READY status and blockers disagree") + if (self.scaffold_status == "READY") != (not self.scaffold_blockers): + raise ValueError("READY scaffold_status and scaffold_blockers disagree") + return self + + +__all__ = ["ModelApplicationDatabaseAclMatrix"] diff --git a/src/omnibase_infra/validation/models/model_application_database_acl_object.py b/src/omnibase_infra/validation/models/model_application_database_acl_object.py new file mode 100644 index 0000000000..dade9127bc --- /dev/null +++ b/src/omnibase_infra/validation/models/model_application_database_acl_object.py @@ -0,0 +1,85 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT + +"""Concrete owned object in a generated application-database ACL matrix.""" + +from __future__ import annotations + +from typing import Literal + +from pydantic import BaseModel, ConfigDict, Field, model_validator + +from omnibase_core.enums.enum_database_grant_object_type import ( + EnumDatabaseGrantObjectType, +) +from omnibase_core.enums.enum_database_schema_domain import EnumDatabaseSchemaDomain +from omnibase_infra.validation.types.type_application_database_function_signature import ( + ApplicationDatabaseFunctionSignature, +) + + +class ModelApplicationDatabaseAclObject(BaseModel): + """One concrete database object projected from typed ownership evidence.""" + + model_config = ConfigDict(frozen=True, extra="forbid") + + database_ref: str = Field(..., min_length=1) + physical_database: str = Field(..., min_length=1) + schema_ref: str = Field(..., min_length=1) + domain: EnumDatabaseSchemaDomain + object_type: EnumDatabaseGrantObjectType + object_ref: str = Field(..., min_length=1) + catalog_kind: Literal[ + "table", + "view", + "materialized_view", + "sequence", + "function", + "procedure", + "type", + ] + owner: str = Field(..., min_length=1) + owner_declaration: str = Field(..., min_length=1) + target_materialized: bool + function_signature: ApplicationDatabaseFunctionSignature | None = None + source_keys: tuple[str, ...] = Field(..., min_length=1) + + @model_validator(mode="after") + def validate_catalog_identity(self) -> ModelApplicationDatabaseAclObject: + """Tie the grant target to one exact PostgreSQL catalog object shape.""" + expected_object_type = { + "table": EnumDatabaseGrantObjectType.TABLE, + "view": EnumDatabaseGrantObjectType.TABLE, + "materialized_view": EnumDatabaseGrantObjectType.TABLE, + "sequence": EnumDatabaseGrantObjectType.SEQUENCE, + "function": EnumDatabaseGrantObjectType.FUNCTION, + "procedure": EnumDatabaseGrantObjectType.FUNCTION, + "type": EnumDatabaseGrantObjectType.TYPE, + }[self.catalog_kind] + if self.object_type is not expected_object_type: + raise ValueError( + f"catalog_kind={self.catalog_kind!r} requires " + f"object_type={expected_object_type.value!r}" + ) + is_routine = self.catalog_kind in {"function", "procedure"} + if not is_routine and self.function_signature is not None: + raise ValueError( + "function_signature is only valid for function/procedure catalog kinds" + ) + return self + + @property + def identity( + self, + ) -> tuple[str, str, EnumDatabaseGrantObjectType, str, str | None]: + """Return the exact PostgreSQL object identity, including overloads.""" + return ( + self.database_ref, + self.schema_ref, + self.object_type, + self.object_ref, + self.function_signature, + ) + + +__all__ = ["ModelApplicationDatabaseAclObject"] diff --git a/src/omnibase_infra/validation/models/model_application_database_acl_policy.py b/src/omnibase_infra/validation/models/model_application_database_acl_policy.py new file mode 100644 index 0000000000..b71a4e3b62 --- /dev/null +++ b/src/omnibase_infra/validation/models/model_application_database_acl_policy.py @@ -0,0 +1,131 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT + +"""Independent typed domain policy for application database principals.""" + +from __future__ import annotations + +import re +from typing import Literal + +from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator + +from omnibase_core.enums.enum_database_schema_domain import EnumDatabaseSchemaDomain +from omnibase_infra.validation.enums.enum_application_database_acl_policy_source_kind import ( + EnumApplicationDatabaseAclPolicySourceKind, +) +from omnibase_infra.validation.models.model_application_database_connection_policy import ( + ModelApplicationDatabaseConnectionPolicy, +) +from omnibase_infra.validation.models.model_application_database_role_state import ( + ModelApplicationDatabaseRoleState, +) + +_SQL_IDENTIFIER = re.compile(r"^[a-z_][a-z0-9_]*$") + + +class ModelApplicationDatabaseAclPolicy(BaseModel): + """Allowed schema domains declared independently from grants being checked.""" + + model_config = ConfigDict(frozen=True, extra="forbid") + + schema_version: Literal["1.0"] = "1.0" + database_ref: str = Field(..., min_length=1) + physical_database: str = Field(..., min_length=1) + completion_status: str = Field(..., min_length=1) + source_kind: EnumApplicationDatabaseAclPolicySourceKind + principal_domains: dict[str, tuple[EnumDatabaseSchemaDomain, ...]] = Field( + ..., min_length=1 + ) + database_owner_role: str = Field(..., pattern=r"^[a-z_][a-z0-9_]*$") + migration_principal: str = Field(..., pattern=r"^[a-z_][a-z0-9_]*$") + migration_owner_roles: tuple[str, ...] = Field(..., min_length=1) + governed_role_states: tuple[ModelApplicationDatabaseRoleState, ...] = Field( + ..., + min_length=1, + ) + retained_administrative_principals: tuple[str, ...] = () + connection_policies: tuple[ModelApplicationDatabaseConnectionPolicy, ...] = Field( + ..., min_length=1 + ) + reason: str = Field(..., min_length=1) + + @field_validator("principal_domains") + @classmethod + def validate_principal_refs( + cls, + value: dict[str, tuple[EnumDatabaseSchemaDomain, ...]], + ) -> dict[str, tuple[EnumDatabaseSchemaDomain, ...]]: + """Require safe principals and unique, nonempty domain declarations.""" + invalid = sorted( + principal + for principal in value + if _SQL_IDENTIFIER.fullmatch(principal) is None + ) + if invalid: + raise ValueError( + f"principal_domains contain unsafe identifiers: {invalid!r}" + ) + return value + + @field_validator("migration_owner_roles") + @classmethod + def validate_migration_owner_roles(cls, values: tuple[str, ...]) -> tuple[str, ...]: + """Require unique canonical owner-role identifiers.""" + if len(set(values)) != len(values): + raise ValueError("migration_owner_roles must be unique") + invalid = sorted( + value for value in values if _SQL_IDENTIFIER.fullmatch(value) is None + ) + if invalid: + raise ValueError( + f"migration_owner_roles contain unsafe identifiers: {invalid!r}" + ) + return values + + @field_validator("retained_administrative_principals") + @classmethod + def validate_retained_administrative_principals( + cls, + values: tuple[str, ...], + ) -> tuple[str, ...]: + """Require an explicit, unique list of untouched administrative roles.""" + if len(set(values)) != len(values): + raise ValueError("retained administrative principals must be unique") + invalid = sorted( + value for value in values if _SQL_IDENTIFIER.fullmatch(value) is None + ) + if invalid: + raise ValueError( + "retained administrative principals contain unsafe identifiers: " + f"{invalid!r}" + ) + return values + + @model_validator(mode="after") + def validate_domains(self) -> ModelApplicationDatabaseAclPolicy: + """Reject empty or duplicate domain declarations.""" + invalid = sorted( + principal + for principal, domains in self.principal_domains.items() + if not domains or len(set(domains)) != len(domains) + ) + if invalid: + raise ValueError( + f"principal_domains must be nonempty and unique for {invalid!r}" + ) + policy_refs = [policy.database_ref for policy in self.connection_policies] + physical_databases = [ + policy.physical_database for policy in self.connection_policies + ] + if len(set(policy_refs)) != len(policy_refs): + raise ValueError("connection policy database_refs must be unique") + if len(set(physical_databases)) != len(physical_databases): + raise ValueError("connection policy physical databases must be unique") + governed_roles = [state.role for state in self.governed_role_states] + if len(set(governed_roles)) != len(governed_roles): + raise ValueError("governed role states must have unique role names") + return self + + +__all__ = ["ModelApplicationDatabaseAclPolicy"] diff --git a/src/omnibase_infra/validation/models/model_application_database_acl_row.py b/src/omnibase_infra/validation/models/model_application_database_acl_row.py new file mode 100644 index 0000000000..f9f6a1b603 --- /dev/null +++ b/src/omnibase_infra/validation/models/model_application_database_acl_row.py @@ -0,0 +1,82 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT + +"""Explicit principal-target cell in an application-database ACL matrix.""" + +from __future__ import annotations + +from pydantic import BaseModel, ConfigDict, Field, model_validator + +from omnibase_core.enums.enum_database_grant_object_type import ( + EnumDatabaseGrantObjectType, +) +from omnibase_core.enums.enum_database_privilege import EnumDatabasePrivilege +from omnibase_infra.validation.types.type_application_database_function_signature import ( + ApplicationDatabaseFunctionSignature, +) + + +class ModelApplicationDatabaseAclRow(BaseModel): + """One explicit principal/target cell; empty privileges mean deny.""" + + model_config = ConfigDict(frozen=True, extra="forbid") + + principal: str = Field(..., min_length=1) + database_ref: str = Field(..., min_length=1) + physical_database: str = Field(..., min_length=1) + object_type: EnumDatabaseGrantObjectType + schema_ref: str | None = None + object_ref: str | None = None + function_signature: ApplicationDatabaseFunctionSignature | None = None + privileges: tuple[EnumDatabasePrivilege, ...] = () + + @model_validator(mode="after") + def validate_target(self) -> ModelApplicationDatabaseAclRow: + """Require an exact target shape and reject duplicate privileges.""" + if len(set(self.privileges)) != len(self.privileges): + raise ValueError("ACL row privileges must be unique") + if self.object_type is EnumDatabaseGrantObjectType.DATABASE: + if ( + self.schema_ref is not None + or self.object_ref is not None + or self.function_signature is not None + ): + raise ValueError("DATABASE ACL rows cannot name schema/object") + elif self.object_type is EnumDatabaseGrantObjectType.SCHEMA: + if ( + self.schema_ref is None + or self.object_ref is not None + or self.function_signature is not None + ): + raise ValueError("SCHEMA ACL rows require schema and no object") + elif self.schema_ref is None or self.object_ref is None: + raise ValueError("Object ACL rows require schema and object") + elif ( + self.object_type is not EnumDatabaseGrantObjectType.FUNCTION + and self.function_signature is not None + ): + raise ValueError("Only FUNCTION ACL rows can carry function_signature") + return self + + @property + def identity( + self, + ) -> tuple[ + str, + str, + EnumDatabaseGrantObjectType, + str | None, + str | None, + str | None, + ]: + return ( + self.principal, + self.database_ref, + self.object_type, + self.schema_ref, + self.object_ref, + self.function_signature, + ) + + +__all__ = ["ModelApplicationDatabaseAclRow"] diff --git a/src/omnibase_infra/validation/models/model_application_database_acl_source.py b/src/omnibase_infra/validation/models/model_application_database_acl_source.py new file mode 100644 index 0000000000..66824059cb --- /dev/null +++ b/src/omnibase_infra/validation/models/model_application_database_acl_source.py @@ -0,0 +1,52 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT + +"""Immutable source record for a generated application-database ACL matrix.""" + +from __future__ import annotations + +from pathlib import PurePosixPath +from typing import Literal + +from pydantic import BaseModel, ConfigDict, Field, field_validator + + +class ModelApplicationDatabaseAclSource(BaseModel): + """One immutable contract or evidence blob used to generate the matrix.""" + + model_config = ConfigDict(frozen=True, extra="forbid") + + source_key: str = Field(..., pattern=r"^[a-z][a-z0-9_]*$") + repository: str = Field( + ..., + pattern=r"^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$", + ) + revision: str = Field(..., pattern=r"^[0-9a-f]{40}$") + path: str = Field(..., pattern=r"^[A-Za-z0-9_./-]+$") + sha256: str = Field(..., pattern=r"^[0-9a-f]{64}$") + purpose: Literal[ + "topology", + "relation_inventory", + "service_ownership", + "rendered_topology", + "typed_loader", + "legacy_fixture", + "principal_inventory", + "acl_policy", + "catalog_query_evidence", + "catalog_result_evidence", + "activity_query_evidence", + "activity_result_evidence", + ] + + @field_validator("path") + @classmethod + def validate_relative_path(cls, value: str) -> str: + """Reject absolute, parent-traversing, or noncanonical source paths.""" + path = PurePosixPath(value) + if path.is_absolute() or ".." in path.parts or "." in path.parts: + raise ValueError("source path must be canonical and repository-relative") + return value + + +__all__ = ["ModelApplicationDatabaseAclSource"] diff --git a/src/omnibase_infra/validation/models/model_application_database_activity_evidence.py b/src/omnibase_infra/validation/models/model_application_database_activity_evidence.py new file mode 100644 index 0000000000..30339377ac --- /dev/null +++ b/src/omnibase_infra/validation/models/model_application_database_activity_evidence.py @@ -0,0 +1,36 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT + +"""Durable full-day activity evidence for an application database.""" + +from __future__ import annotations + +from datetime import datetime, timedelta + +from pydantic import AwareDatetime, BaseModel, ConfigDict, Field, model_validator + + +class ModelApplicationDatabaseActivityEvidence(BaseModel): + """Hash-addressed query/result evidence covering at least 24 hours.""" + + model_config = ConfigDict(frozen=True, extra="forbid") + + window_started_at: AwareDatetime + window_ended_at: AwareDatetime + query_sha256: str = Field(..., pattern=r"^[0-9a-f]{64}$") + result_sha256: str = Field(..., pattern=r"^[0-9a-f]{64}$") + query_source_key: str = Field(..., pattern=r"^[a-z][a-z0-9_]*$") + result_source_key: str = Field(..., pattern=r"^[a-z][a-z0-9_]*$") + observation_count: int = Field(..., ge=0) + + @model_validator(mode="after") + def validate_full_day_window(self) -> ModelApplicationDatabaseActivityEvidence: + """Require an ordered interval spanning a complete day.""" + started_at = datetime.fromisoformat(self.window_started_at.isoformat()) + ended_at = datetime.fromisoformat(self.window_ended_at.isoformat()) + if ended_at - started_at < timedelta(hours=24): + raise ValueError("activity evidence window must span at least 24 hours") + return self + + +__all__ = ["ModelApplicationDatabaseActivityEvidence"] diff --git a/src/omnibase_infra/validation/models/model_application_database_activity_principal_observation.py b/src/omnibase_infra/validation/models/model_application_database_activity_principal_observation.py new file mode 100644 index 0000000000..9ab2a078c0 --- /dev/null +++ b/src/omnibase_infra/validation/models/model_application_database_activity_principal_observation.py @@ -0,0 +1,18 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT + +"""One activity observation in an application-database evidence result.""" + +from pydantic import BaseModel, ConfigDict, Field + + +class ModelApplicationDatabaseActivityPrincipalObservation(BaseModel): + """One exact ``(datname, usename)`` pair with its sample count.""" + + model_config = ConfigDict(frozen=True, extra="forbid") + + principal: str = Field(..., pattern=r"^[a-z_][a-z0-9_]*$") + observation_count: int = Field(..., ge=1) + + +__all__ = ["ModelApplicationDatabaseActivityPrincipalObservation"] diff --git a/src/omnibase_infra/validation/models/model_application_database_activity_result_evidence.py b/src/omnibase_infra/validation/models/model_application_database_activity_result_evidence.py new file mode 100644 index 0000000000..71e9fa7baa --- /dev/null +++ b/src/omnibase_infra/validation/models/model_application_database_activity_result_evidence.py @@ -0,0 +1,55 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT + +"""Typed full-day application-database activity-result evidence.""" + +from __future__ import annotations + +from datetime import datetime, timedelta +from typing import Literal + +from pydantic import AwareDatetime, BaseModel, ConfigDict, Field, model_validator + +from omnibase_infra.validation.models.model_application_database_activity_principal_observation import ( + ModelApplicationDatabaseActivityPrincipalObservation, +) + + +class ModelApplicationDatabaseActivityResultEvidence(BaseModel): + """Canonical full-day activity-result content for one database.""" + + model_config = ConfigDict(frozen=True, extra="forbid") + + schema_version: Literal["1.0"] = "1.0" + database_ref: str = Field(..., pattern=r"^[a-z_][a-z0-9_]*$") + physical_database: str = Field(..., pattern=r"^[a-z_][a-z0-9_]*$") + window_started_at: AwareDatetime + window_ended_at: AwareDatetime + activity_query_sha256: str = Field(..., pattern=r"^[0-9a-f]{64}$") + observation_count: int = Field(..., ge=0) + active_principals: tuple[ + ModelApplicationDatabaseActivityPrincipalObservation, + ..., + ] + + @model_validator(mode="after") + def validate_full_day_window( + self, + ) -> ModelApplicationDatabaseActivityResultEvidence: + """Reject unordered or partial-day result windows.""" + started_at = datetime.fromisoformat(self.window_started_at.isoformat()) + ended_at = datetime.fromisoformat(self.window_ended_at.isoformat()) + if ended_at - started_at < timedelta(hours=24): + raise ValueError("activity result window must span at least 24 hours") + principals = [row.principal for row in self.active_principals] + if len(set(principals)) != len(principals): + raise ValueError("activity result principal pairs must be unique") + observed_count = sum(row.observation_count for row in self.active_principals) + if observed_count != self.observation_count: + raise ValueError( + "activity result observation_count must equal exact pair-row counts" + ) + return self + + +__all__ = ["ModelApplicationDatabaseActivityResultEvidence"] diff --git a/src/omnibase_infra/validation/models/model_application_database_catalog_object_evidence.py b/src/omnibase_infra/validation/models/model_application_database_catalog_object_evidence.py new file mode 100644 index 0000000000..f7326bf7ff --- /dev/null +++ b/src/omnibase_infra/validation/models/model_application_database_catalog_object_evidence.py @@ -0,0 +1,59 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT + +"""Exact live-catalog identity and owner for one managed-schema object.""" + +from __future__ import annotations + +from typing import Literal + +from pydantic import BaseModel, ConfigDict, Field, model_validator + +from omnibase_infra.validation.types.type_application_database_function_signature import ( + ApplicationDatabaseFunctionSignature, +) + + +class ModelApplicationDatabaseCatalogObjectEvidence(BaseModel): + """Current object identity used by the transaction-start catalog guard.""" + + model_config = ConfigDict(frozen=True, extra="forbid") + + schema_ref: str = Field(..., pattern=r"^[a-z_][a-z0-9_]*$") + catalog_kind: Literal[ + "table", + "view", + "materialized_view", + "sequence", + "function", + "procedure", + "type", + ] + object_ref: str = Field(..., pattern=r"^[a-z_][a-z0-9_]*$") + function_signature: ApplicationDatabaseFunctionSignature | None = None + owner: str = Field(..., pattern=r"^[a-z_][a-z0-9_]*$") + + @model_validator(mode="after") + def validate_signature_shape( + self, + ) -> ModelApplicationDatabaseCatalogObjectEvidence: + """Require exact signatures only for routines.""" + routine = self.catalog_kind in {"function", "procedure"} + if routine != (self.function_signature is not None): + raise ValueError( + "catalog routine evidence requires a signature and non-routines forbid it" + ) + return self + + @property + def identity(self) -> tuple[str, str, str, str]: + """Return the stable live-catalog identity.""" + return ( + self.catalog_kind, + self.schema_ref, + self.object_ref, + self.function_signature or "", + ) + + +__all__ = ["ModelApplicationDatabaseCatalogObjectEvidence"] diff --git a/src/omnibase_infra/validation/models/model_application_database_catalog_result_evidence.py b/src/omnibase_infra/validation/models/model_application_database_catalog_result_evidence.py new file mode 100644 index 0000000000..20d55798a6 --- /dev/null +++ b/src/omnibase_infra/validation/models/model_application_database_catalog_result_evidence.py @@ -0,0 +1,148 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT + +"""Typed application-database catalog-result evidence.""" + +from __future__ import annotations + +import re +from typing import Literal + +from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator + +from omnibase_infra.validation.models.model_application_database_catalog_object_evidence import ( + ModelApplicationDatabaseCatalogObjectEvidence, +) +from omnibase_infra.validation.models.model_application_database_observed_role_state import ( + ModelApplicationDatabaseObservedRoleState, +) + +_SQL_IDENTIFIER = re.compile(r"^[a-z_][a-z0-9_]*$") + + +class ModelApplicationDatabaseCatalogResultEvidence(BaseModel): + """Canonical catalog-result content bound to an immutable source blob.""" + + model_config = ConfigDict(frozen=True, extra="forbid") + + schema_version: Literal["1.0"] = "1.0" + database_ref: str = Field(..., pattern=r"^[a-z_][a-z0-9_]*$") + physical_database: str = Field(..., pattern=r"^[a-z_][a-z0-9_]*$") + completion_status: str = Field(..., min_length=1) + catalog_parity_status: str = Field(..., min_length=1) + catalog_query_sha256: str = Field(..., pattern=r"^[0-9a-f]{64}$") + database_owner_role: str = Field(..., pattern=r"^[a-z_][a-z0-9_]*$") + principal_refs: tuple[str, ...] = Field(..., min_length=1) + absent_principal_refs: tuple[str, ...] = () + owner_refs: tuple[str, ...] = () + absent_owner_refs: tuple[str, ...] = () + observed_role_states: tuple[ModelApplicationDatabaseObservedRoleState, ...] + observed_schema_owners: dict[str, str] = Field(default_factory=dict) + absent_schema_refs: tuple[str, ...] = () + observed_objects: tuple[ModelApplicationDatabaseCatalogObjectEvidence, ...] = () + + @field_validator( + "principal_refs", + "absent_principal_refs", + "owner_refs", + "absent_owner_refs", + "absent_schema_refs", + ) + @classmethod + def validate_role_refs(cls, values: tuple[str, ...]) -> tuple[str, ...]: + """Require unique, safely quotable role names in result content.""" + if len(set(values)) != len(values): + raise ValueError("catalog evidence role references must be unique") + invalid = sorted( + value for value in values if _SQL_IDENTIFIER.fullmatch(value) is None + ) + if invalid: + raise ValueError( + f"catalog evidence contains unsafe role references: {invalid!r}" + ) + return values + + @model_validator(mode="after") + def validate_role_census( + self, + ) -> ModelApplicationDatabaseCatalogResultEvidence: + """Keep positive, negative, workload, and managed-owner evidence disjoint.""" + principal_overlap = set(self.principal_refs) & set(self.absent_principal_refs) + if principal_overlap: + raise ValueError( + "catalog principal presence/absence evidence overlaps: " + f"{sorted(principal_overlap)!r}" + ) + owner_overlap = set(self.owner_refs) & set(self.absent_owner_refs) + if owner_overlap: + raise ValueError( + "catalog owner presence/absence evidence overlaps: " + f"{sorted(owner_overlap)!r}" + ) + role_kind_overlap = set(self.principal_refs).union( + self.absent_principal_refs + ) & set(self.owner_refs).union(self.absent_owner_refs) + if role_kind_overlap: + raise ValueError( + "catalog principal and managed-owner evidence overlaps: " + f"{sorted(role_kind_overlap)!r}" + ) + state_roles = [state.role for state in self.observed_role_states] + expected_state_roles = set(self.principal_refs).union(self.owner_refs) + if ( + len(set(state_roles)) != len(state_roles) + or set(state_roles) != expected_state_roles + ): + raise ValueError( + "catalog observed role states must cover the exact principal and " + "managed-owner census" + ) + invalid_schema_owners = sorted( + schema + for schema, owner in self.observed_schema_owners.items() + if _SQL_IDENTIFIER.fullmatch(schema) is None + or _SQL_IDENTIFIER.fullmatch(owner) is None + ) + if invalid_schema_owners: + raise ValueError( + "catalog observed schema owners contain unsafe identifiers: " + f"{invalid_schema_owners!r}" + ) + schema_overlap = set(self.observed_schema_owners) & set(self.absent_schema_refs) + if schema_overlap: + raise ValueError( + "catalog schema presence/absence evidence overlaps: " + f"{sorted(schema_overlap)!r}" + ) + object_identities = [obj.identity for obj in self.observed_objects] + if len(set(object_identities)) != len(object_identities): + raise ValueError("catalog observed object identities must be unique") + unknown_object_schemas = sorted( + {obj.schema_ref for obj in self.observed_objects} + - set(self.observed_schema_owners) + ) + if unknown_object_schemas: + raise ValueError( + "catalog objects require observed schema-owner evidence: " + f"{unknown_object_schemas!r}" + ) + classified_present_roles = ( + set(self.principal_refs) + .union(self.owner_refs) + .union({self.database_owner_role}) + ) + unclassified_catalog_owners = sorted( + set(self.observed_schema_owners.values()).union( + obj.owner for obj in self.observed_objects + ) + - classified_present_roles + ) + if unclassified_catalog_owners: + raise ValueError( + "catalog schema/object owners must be classified in the present " + f"role census: {unclassified_catalog_owners!r}" + ) + return self + + +__all__ = ["ModelApplicationDatabaseCatalogResultEvidence"] diff --git a/src/omnibase_infra/validation/models/model_application_database_connection_policy.py b/src/omnibase_infra/validation/models/model_application_database_connection_policy.py new file mode 100644 index 0000000000..7996ddad85 --- /dev/null +++ b/src/omnibase_infra/validation/models/model_application_database_connection_policy.py @@ -0,0 +1,44 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT + +"""Explicit CONNECT policy for one PostgreSQL database.""" + +from __future__ import annotations + +import re + +from pydantic import BaseModel, ConfigDict, Field, field_validator + +_SQL_IDENTIFIER = re.compile(r"^[a-z_][a-z0-9_]*$") + + +class ModelApplicationDatabaseConnectionPolicy(BaseModel): + """Principals allowed to connect to one protected physical database.""" + + model_config = ConfigDict(frozen=True, extra="forbid") + + database_ref: str = Field(..., pattern=r"^[a-z_][a-z0-9_]*$") + physical_database: str = Field(..., pattern=r"^[a-z_][a-z0-9_]*$") + observed_database_owner_role: str = Field( + ..., + pattern=r"^[a-z_][a-z0-9_]*$", + ) + allowed_principals: tuple[str, ...] = Field(..., min_length=1) + + @field_validator("allowed_principals") + @classmethod + def validate_allowed_principals(cls, values: tuple[str, ...]) -> tuple[str, ...]: + """Require a unique, safely quotable allowlist.""" + if len(set(values)) != len(values): + raise ValueError("allowed_principals must be unique") + invalid = sorted( + value for value in values if _SQL_IDENTIFIER.fullmatch(value) is None + ) + if invalid: + raise ValueError( + f"allowed_principals contain unsafe identifiers: {invalid!r}" + ) + return values + + +__all__ = ["ModelApplicationDatabaseConnectionPolicy"] diff --git a/src/omnibase_infra/validation/models/model_application_database_default_acl_row.py b/src/omnibase_infra/validation/models/model_application_database_default_acl_row.py new file mode 100644 index 0000000000..a1d5ac3a01 --- /dev/null +++ b/src/omnibase_infra/validation/models/model_application_database_default_acl_row.py @@ -0,0 +1,37 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT + +"""Future-object privilege cell in an application-database ACL matrix.""" + +from __future__ import annotations + +from typing import Literal + +from pydantic import BaseModel, ConfigDict, Field + +from omnibase_core.enums.enum_database_grant_object_type import ( + EnumDatabaseGrantObjectType, +) +from omnibase_core.enums.enum_database_privilege import EnumDatabasePrivilege + + +class ModelApplicationDatabaseDefaultAclRow(BaseModel): + """One future-object privilege cell for an actual schema owner.""" + + model_config = ConfigDict(frozen=True, extra="forbid") + + owner: str = Field(..., min_length=1) + database_ref: str = Field(..., min_length=1) + physical_database: str = Field(..., min_length=1) + schema_ref: str = Field(..., min_length=1) + object_type: Literal[ + EnumDatabaseGrantObjectType.TABLE, + EnumDatabaseGrantObjectType.SEQUENCE, + EnumDatabaseGrantObjectType.FUNCTION, + EnumDatabaseGrantObjectType.TYPE, + ] + grantee: str = Field(..., min_length=1) + privileges: tuple[EnumDatabasePrivilege, ...] = () + + +__all__ = ["ModelApplicationDatabaseDefaultAclRow"] diff --git a/src/omnibase_infra/validation/models/model_application_database_observed_role_state.py b/src/omnibase_infra/validation/models/model_application_database_observed_role_state.py new file mode 100644 index 0000000000..b14877b83d --- /dev/null +++ b/src/omnibase_infra/validation/models/model_application_database_observed_role_state.py @@ -0,0 +1,24 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT + +"""Catalog-observed attributes for an application-database principal role.""" + +from pydantic import BaseModel, ConfigDict, Field + + +class ModelApplicationDatabaseObservedRoleState(BaseModel): + """Catalog-observed attributes for a present principal role.""" + + model_config = ConfigDict(frozen=True, extra="forbid") + + role: str = Field(..., pattern=r"^[a-z_][a-z0-9_]*$") + login: bool + superuser: bool + bypass_rls: bool + create_database: bool + create_role: bool + replication: bool + inherit: bool + + +__all__ = ["ModelApplicationDatabaseObservedRoleState"] diff --git a/src/omnibase_infra/validation/models/model_application_database_principal_inventory.py b/src/omnibase_infra/validation/models/model_application_database_principal_inventory.py new file mode 100644 index 0000000000..b4f7dca269 --- /dev/null +++ b/src/omnibase_infra/validation/models/model_application_database_principal_inventory.py @@ -0,0 +1,216 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT + +"""Typed principal census for an application database ACL matrix.""" + +from __future__ import annotations + +import re +from typing import Literal + +from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator + +from omnibase_infra.validation.enums.enum_application_database_principal_inventory_source_kind import ( + EnumApplicationDatabasePrincipalInventorySourceKind, +) +from omnibase_infra.validation.models.model_application_database_activity_evidence import ( + ModelApplicationDatabaseActivityEvidence, +) +from omnibase_infra.validation.models.model_application_database_catalog_object_evidence import ( + ModelApplicationDatabaseCatalogObjectEvidence, +) +from omnibase_infra.validation.models.model_application_database_observed_role_state import ( + ModelApplicationDatabaseObservedRoleState, +) + +_SQL_IDENTIFIER = re.compile(r"^[a-z_][a-z0-9_]*$") + + +class ModelApplicationDatabasePrincipalInventory(BaseModel): + """Exact observed non-owner principal universe for one database.""" + + model_config = ConfigDict(frozen=True, extra="forbid") + + schema_version: Literal["1.0"] = "1.0" + database_ref: str = Field(..., min_length=1) + physical_database: str = Field(..., min_length=1) + completion_status: str = Field(..., min_length=1) + catalog_parity_status: str = Field(..., min_length=1) + source_kind: EnumApplicationDatabasePrincipalInventorySourceKind + database_owner_role: str = Field(..., pattern=r"^[a-z_][a-z0-9_]*$") + principal_refs: tuple[str, ...] = Field(..., min_length=1) + absent_principal_refs: tuple[str, ...] = () + owner_refs: tuple[str, ...] = () + absent_owner_refs: tuple[str, ...] = () + observed_role_states: tuple[ModelApplicationDatabaseObservedRoleState, ...] + activity_principal_refs: tuple[str, ...] = () + observed_schema_owners: dict[str, str] = Field(default_factory=dict) + absent_schema_refs: tuple[str, ...] = () + observed_objects: tuple[ModelApplicationDatabaseCatalogObjectEvidence, ...] = () + live_database_read: bool + activity_evidence: ModelApplicationDatabaseActivityEvidence | None = None + catalog_query_sha256: str | None = Field( + default=None, + pattern=r"^[0-9a-f]{64}$", + ) + catalog_result_sha256: str | None = Field( + default=None, + pattern=r"^[0-9a-f]{64}$", + ) + catalog_query_source_key: str | None = Field( + default=None, + pattern=r"^[a-z][a-z0-9_]*$", + ) + catalog_result_source_key: str | None = Field( + default=None, + pattern=r"^[a-z][a-z0-9_]*$", + ) + reason: str = Field(..., min_length=1) + + @field_validator( + "principal_refs", + "absent_principal_refs", + "owner_refs", + "absent_owner_refs", + "activity_principal_refs", + "absent_schema_refs", + ) + @classmethod + def validate_principal_refs(cls, values: tuple[str, ...]) -> tuple[str, ...]: + """Reject duplicates and identifiers that cannot be safely quoted.""" + if len(set(values)) != len(values): + raise ValueError("principal_refs must be unique") + invalid = sorted( + value for value in values if _SQL_IDENTIFIER.fullmatch(value) is None + ) + if invalid: + raise ValueError(f"principal_refs contain unsafe identifiers: {invalid!r}") + return values + + @model_validator(mode="after") + def validate_provenance(self) -> ModelApplicationDatabasePrincipalInventory: + """Keep synthetic and authorized-catalog evidence distinguishable.""" + overlap = set(self.principal_refs) & set(self.absent_principal_refs) + if overlap: + raise ValueError( + f"principal presence and absence evidence overlap: {sorted(overlap)!r}" + ) + owner_overlap = set(self.owner_refs) & set(self.absent_owner_refs) + if owner_overlap: + raise ValueError( + f"owner presence and absence evidence overlap: {sorted(owner_overlap)!r}" + ) + role_kind_overlap = set(self.principal_refs).union( + self.absent_principal_refs + ) & set(self.owner_refs).union(self.absent_owner_refs) + if role_kind_overlap: + raise ValueError( + f"principal and owner evidence overlap: {sorted(role_kind_overlap)!r}" + ) + state_roles = [state.role for state in self.observed_role_states] + if len(set(state_roles)) != len(state_roles): + raise ValueError("observed role states must have unique role names") + expected_state_roles = set(self.principal_refs).union(self.owner_refs) + if set(state_roles) != expected_state_roles: + raise ValueError( + "observed role states must cover the exact present principal and " + "managed-owner census" + ) + classified_activity_roles = ( + set(self.principal_refs) + .union(self.owner_refs) + .union({self.database_owner_role}) + ) + if not set(self.activity_principal_refs) <= classified_activity_roles: + raise ValueError( + "activity principals must be classified as present principals, " + "managed owners, or the observed database owner" + ) + invalid_schema_owners = sorted( + schema + for schema, owner in self.observed_schema_owners.items() + if _SQL_IDENTIFIER.fullmatch(schema) is None + or _SQL_IDENTIFIER.fullmatch(owner) is None + ) + if invalid_schema_owners: + raise ValueError( + "observed schema owners contain unsafe identifiers: " + f"{invalid_schema_owners!r}" + ) + schema_overlap = set(self.observed_schema_owners) & set(self.absent_schema_refs) + if schema_overlap: + raise ValueError( + "schema presence and absence evidence overlap: " + f"{sorted(schema_overlap)!r}" + ) + object_identities = [obj.identity for obj in self.observed_objects] + if len(set(object_identities)) != len(object_identities): + raise ValueError("observed catalog object identities must be unique") + unknown_object_schemas = sorted( + {obj.schema_ref for obj in self.observed_objects} + - set(self.observed_schema_owners) + ) + if unknown_object_schemas: + raise ValueError( + "observed objects require present schema-owner evidence: " + f"{unknown_object_schemas!r}" + ) + classified_present_roles = ( + set(self.principal_refs) + .union(self.owner_refs) + .union({self.database_owner_role}) + ) + unclassified_catalog_owners = sorted( + set(self.observed_schema_owners.values()).union( + obj.owner for obj in self.observed_objects + ) + - classified_present_roles + ) + if unclassified_catalog_owners: + raise ValueError( + "observed schema/object owners must be classified in the present " + f"role census: {unclassified_catalog_owners!r}" + ) + if ( + self.source_kind + is EnumApplicationDatabasePrincipalInventorySourceKind.AUTHORIZED_CATALOG + and not self.live_database_read + ): + raise ValueError("authorized_catalog requires live_database_read=true") + if self.source_kind is ( + EnumApplicationDatabasePrincipalInventorySourceKind.AUTHORIZED_CATALOG + ) and ( + self.activity_evidence is None + or self.catalog_query_sha256 is None + or self.catalog_result_sha256 is None + or self.catalog_query_source_key is None + or self.catalog_result_source_key is None + ): + raise ValueError( + "authorized_catalog requires durable activity and catalog query/result provenance" + ) + if ( + self.source_kind + is EnumApplicationDatabasePrincipalInventorySourceKind.SYNTHETIC_FIXTURE + and self.live_database_read + ): + raise ValueError("synthetic_fixture cannot claim a live database read") + if self.source_kind is ( + EnumApplicationDatabasePrincipalInventorySourceKind.SYNTHETIC_FIXTURE + ) and any( + item is not None + for item in ( + self.activity_evidence, + self.catalog_query_sha256, + self.catalog_result_sha256, + self.catalog_query_source_key, + self.catalog_result_source_key, + ) + ): + raise ValueError( + "synthetic_fixture cannot carry authorized-catalog provenance" + ) + return self + + +__all__ = ["ModelApplicationDatabasePrincipalInventory"] diff --git a/src/omnibase_infra/validation/models/model_application_database_role_membership.py b/src/omnibase_infra/validation/models/model_application_database_role_membership.py new file mode 100644 index 0000000000..ebd5be2b47 --- /dev/null +++ b/src/omnibase_infra/validation/models/model_application_database_role_membership.py @@ -0,0 +1,28 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT + +"""Explicit permitted role membership in an application database ACL matrix.""" + +from __future__ import annotations + +from pydantic import BaseModel, ConfigDict, Field + + +class ModelApplicationDatabaseRoleMembership(BaseModel): + """One exact PostgreSQL role membership and its PG16 option state.""" + + model_config = ConfigDict(frozen=True, extra="forbid") + + database_ref: str = Field(..., pattern=r"^[a-z_][a-z0-9_]*$") + role: str = Field(..., pattern=r"^[a-z_][a-z0-9_]*$") + member: str = Field(..., pattern=r"^[a-z_][a-z0-9_]*$") + admin_option: bool = False + inherit_option: bool = False + set_option: bool = True + + @property + def identity(self) -> tuple[str, str, str]: + return (self.database_ref, self.role, self.member) + + +__all__ = ["ModelApplicationDatabaseRoleMembership"] diff --git a/src/omnibase_infra/validation/models/model_application_database_role_state.py b/src/omnibase_infra/validation/models/model_application_database_role_state.py new file mode 100644 index 0000000000..67f9123db5 --- /dev/null +++ b/src/omnibase_infra/validation/models/model_application_database_role_state.py @@ -0,0 +1,31 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT + +"""Explicit desired state for an ACL-governed PostgreSQL role.""" + +from __future__ import annotations + +from typing import Literal + +from pydantic import BaseModel, ConfigDict, Field + + +class ModelApplicationDatabaseRoleState(BaseModel): + """Role attributes that an ACL policy explicitly authorizes changing.""" + + model_config = ConfigDict(frozen=True, extra="forbid") + + role: str = Field(..., pattern=r"^[a-z_][a-z0-9_]*$") + role_kind: Literal["owner", "workload", "migration", "external_connect"] + manage_attributes: bool = True + manage_memberships: bool = True + login: bool + superuser: Literal[False] = False + bypass_rls: Literal[False] = False + create_database: Literal[False] = False + create_role: Literal[False] = False + replication: Literal[False] = False + inherit: Literal[False] = False + + +__all__ = ["ModelApplicationDatabaseRoleState"] diff --git a/src/omnibase_infra/validation/models/model_application_inventory_relation.py b/src/omnibase_infra/validation/models/model_application_inventory_relation.py index 6a9da716d1..83b81973ce 100644 --- a/src/omnibase_infra/validation/models/model_application_inventory_relation.py +++ b/src/omnibase_infra/validation/models/model_application_inventory_relation.py @@ -12,6 +12,9 @@ from omnibase_infra.validation.models.model_internal_tenant_column_transform import ( ModelInternalTenantColumnTransform, ) +from omnibase_infra.validation.types.type_application_database_function_signature import ( + ApplicationDatabaseFunctionSignature, +) class ModelApplicationInventoryRelation(BaseModel): @@ -39,6 +42,7 @@ class ModelApplicationInventoryRelation(BaseModel): dependent_objects: tuple[str, ...] = () dsn_consumers: tuple[str, ...] = () foreign_keys: tuple[str, ...] = () + function_signature: ApplicationDatabaseFunctionSignature | None = None grants: tuple[str, ...] = () indexes: tuple[str, ...] = () keys: tuple[str, ...] = () diff --git a/src/omnibase_infra/validation/models/model_application_inventory_relation_counts.py b/src/omnibase_infra/validation/models/model_application_inventory_relation_counts.py index b194c6531b..60d2e2d283 100644 --- a/src/omnibase_infra/validation/models/model_application_inventory_relation_counts.py +++ b/src/omnibase_infra/validation/models/model_application_inventory_relation_counts.py @@ -15,8 +15,10 @@ class ModelApplicationInventoryRelationCounts(BaseModel): view: int = Field(..., ge=0) materialized_view: int = Field(default=0, ge=0) function: int = Field(..., ge=0) + procedure: int | None = Field(default=None, ge=0) sequence: int = Field(..., ge=0) extension: int = Field(..., ge=0) + type: int | None = Field(default=None, ge=0) __all__ = ["ModelApplicationInventoryRelationCounts"] diff --git a/src/omnibase_infra/validation/models/model_application_relation_evidence_inventory.py b/src/omnibase_infra/validation/models/model_application_relation_evidence_inventory.py index 3d81ce9bd9..075f4eb320 100644 --- a/src/omnibase_infra/validation/models/model_application_relation_evidence_inventory.py +++ b/src/omnibase_infra/validation/models/model_application_relation_evidence_inventory.py @@ -48,7 +48,7 @@ def validate_relation_counts(self) -> "ModelApplicationRelationEvidenceInventory mismatches = { kind: (declared_count, observed.get(kind, 0)) for kind, declared_count in declared.items() - if declared_count != observed.get(kind, 0) + if declared_count is not None and declared_count != observed.get(kind, 0) } if mismatches: raise ValueError( diff --git a/src/omnibase_infra/validation/models/model_database_object_evidence.py b/src/omnibase_infra/validation/models/model_database_object_evidence.py index bea1d6d38b..29f03da330 100644 --- a/src/omnibase_infra/validation/models/model_database_object_evidence.py +++ b/src/omnibase_infra/validation/models/model_database_object_evidence.py @@ -9,6 +9,9 @@ from omnibase_infra.validation.enums.enum_application_database_object_kind import ( EnumApplicationDatabaseObjectKind, ) +from omnibase_infra.validation.types.type_application_database_function_signature import ( + ApplicationDatabaseFunctionSignature, +) class ModelDatabaseObjectEvidence(BaseModel): @@ -23,6 +26,9 @@ class ModelDatabaseObjectEvidence(BaseModel): domain: EnumDatabaseSchemaDomain owner_declaration: str = Field(..., min_length=1) readers: tuple[str, ...] = () + writers: tuple[str, ...] = () + current_schemas: tuple[str, ...] = () + function_signature: ApplicationDatabaseFunctionSignature | None = None @field_validator("kind", mode="before") @classmethod diff --git a/src/omnibase_infra/validation/models/model_migration_ownership_manifest.py b/src/omnibase_infra/validation/models/model_migration_ownership_manifest.py index 1b09024679..f4a22a830f 100644 --- a/src/omnibase_infra/validation/models/model_migration_ownership_manifest.py +++ b/src/omnibase_infra/validation/models/model_migration_ownership_manifest.py @@ -32,6 +32,8 @@ class ModelMigrationOwnershipManifest(BaseModel): schema_version: str = Field(..., min_length=1) service: str = Field(..., min_length=1) owner_declaration: str | None = Field(default=None, min_length=1) + current_physical_database: str | None = Field(default=None, min_length=1) + materialized_physical_databases: tuple[str, ...] = () target_database_ref: str = Field(..., min_length=1) db_io: ModelDbOwnershipSubcontract relation_evidence: tuple[ModelRelationEvidence, ...] = () diff --git a/src/omnibase_infra/validation/models/model_relation_evidence.py b/src/omnibase_infra/validation/models/model_relation_evidence.py index 3b9baac865..2138bc5f49 100644 --- a/src/omnibase_infra/validation/models/model_relation_evidence.py +++ b/src/omnibase_infra/validation/models/model_relation_evidence.py @@ -20,9 +20,12 @@ class ModelRelationEvidence(BaseModel): kind: EnumApplicationRelationKind database_ref: str | None = None schema: str | None = None # type: ignore[assignment] + current_schemas: tuple[str, ...] = () domain: EnumDatabaseSchemaDomain owner_declaration: str = Field(..., min_length=1) readers: tuple[str, ...] = () + writers: tuple[str, ...] = () + dependent_objects: tuple[str, ...] = () @field_validator("kind", mode="before") @classmethod diff --git a/src/omnibase_infra/validation/models/model_retained_live_census.py b/src/omnibase_infra/validation/models/model_retained_live_census.py index 91843ff0df..e74790452f 100644 --- a/src/omnibase_infra/validation/models/model_retained_live_census.py +++ b/src/omnibase_infra/validation/models/model_retained_live_census.py @@ -13,6 +13,11 @@ class ModelRetainedLiveCensus(BaseModel): observed_base_tables: int | None = Field(default=None, ge=0) observed_views_and_materialized_views: int | None = Field(default=None, ge=0) + observed_sequences: int | None = Field(default=None, ge=0) + observed_functions: int | None = Field(default=None, ge=0) + observed_procedures: int | None = Field(default=None, ge=0) + observed_types: int | None = Field(default=None, ge=0) + observed_extensions: int | None = Field(default=None, ge=0) parity_status: str | None = None reason: str | None = None diff --git a/src/omnibase_infra/validation/types/__init__.py b/src/omnibase_infra/validation/types/__init__.py new file mode 100644 index 0000000000..36de0c4eed --- /dev/null +++ b/src/omnibase_infra/validation/types/__init__.py @@ -0,0 +1,4 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT + +"""Reusable strict validation types.""" diff --git a/src/omnibase_infra/validation/types/type_application_database_function_signature.py b/src/omnibase_infra/validation/types/type_application_database_function_signature.py new file mode 100644 index 0000000000..8862a6ad7e --- /dev/null +++ b/src/omnibase_infra/validation/types/type_application_database_function_signature.py @@ -0,0 +1,85 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT + +"""Safe PostgreSQL routine identity-signature type.""" + +from __future__ import annotations + +from typing import Annotated + +from pydantic import AfterValidator + +_UNQUOTED_CHARACTERS = frozenset( + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.$ []," +) + + +def _validate_function_signature(value: str) -> str: + """Reject target-list escapes while retaining catalog identity arguments.""" + if len(value) < 2 or value[0] != "(" or value[-1] != ")": + raise ValueError("function_signature must have one outer argument list") + + body = value[1:-1] + if not body: + return value + + arguments: list[str] = [] + current: list[str] = [] + quoted = False + index = 0 + while index < len(body): + character = body[index] + if quoted: + if character in {"\n", "\r", "\x00"}: + raise ValueError( + "function_signature quoted identifiers cannot contain controls" + ) + if character == '"': + if index + 1 < len(body) and body[index + 1] == '"': + current.extend(('"', '"')) + index += 2 + continue + quoted = False + current.append(character) + index += 1 + continue + + if character == '"': + quoted = True + current.append(character) + elif character in {"(", ")"}: + raise ValueError("function_signature cannot contain nested argument lists") + elif character == ",": + argument = "".join(current).strip() + if not argument: + raise ValueError("function_signature arguments cannot be empty") + arguments.append(argument) + current = [] + elif character not in _UNQUOTED_CHARACTERS: + raise ValueError( + f"function_signature contains unsafe character {character!r}" + ) + else: + current.append(character) + index += 1 + + if quoted: + raise ValueError("function_signature contains an unterminated identifier") + final_argument = "".join(current).strip() + if not final_argument: + raise ValueError("function_signature arguments cannot be empty") + arguments.append(final_argument) + if any( + "[" in argument.replace("[]", "") or "]" in argument.replace("[]", "") + for argument in arguments + ): + raise ValueError("function_signature array brackets must be complete [] pairs") + return value + + +type ApplicationDatabaseFunctionSignature = Annotated[ + str, + AfterValidator(_validate_function_signature), +] + +__all__ = ["ApplicationDatabaseFunctionSignature"] diff --git a/tests/ci/test_application_database_acl_contract.py b/tests/ci/test_application_database_acl_contract.py new file mode 100644 index 0000000000..f246dbc714 --- /dev/null +++ b/tests/ci/test_application_database_acl_contract.py @@ -0,0 +1,124 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT + +"""Static contract for the pinned generated application ACL candidate.""" + +from __future__ import annotations + +from pathlib import Path + +import yaml + +from omnibase_core.enums.enum_database_grant_object_type import ( + EnumDatabaseGrantObjectType, +) +from omnibase_infra.validation.application_database_acl import ( + PUBLIC_PRINCIPAL, + validate_application_database_acl_matrix, +) +from omnibase_infra.validation.models.model_application_database_acl_matrix import ( + ModelApplicationDatabaseAclMatrix, + ModelApplicationDatabaseAclSource, +) + +_ROOT = Path(__file__).parents[2] +_PROOF = _ROOT / "docker" / "application-acl-proof" + + +def _candidate() -> ModelApplicationDatabaseAclMatrix: + return ModelApplicationDatabaseAclMatrix.model_validate( + yaml.safe_load( + (_PROOF / "generated" / "candidate-matrix.yaml").read_text(encoding="utf-8") + ) + ) + + +def test_candidate_is_a_complete_fail_closed_projection_of_locked_sources() -> None: + lock = yaml.safe_load((_PROOF / "source-lock.yaml").read_text(encoding="utf-8")) + locked_sources = tuple( + ModelApplicationDatabaseAclSource.model_validate(source) + for source in lock["sources"] + ) + matrix = _candidate() + + assert set(matrix.sources) == set(locked_sources) + assert matrix.status == "BLOCKED" + assert matrix.scaffold_status == "BLOCKED" + assert matrix.scaffold_blockers + assert len(matrix.objects) == 112 + assert len(matrix.rows) == 5 * (1 + 3 + len(matrix.objects)) + assert len(matrix.default_privileges) == 3 * 4 * 5 + assert matrix.declared_principals == { + "application": ( + "app_dashboard", + "omninode_runtime", + "onex_api", + "tenant_projection_writer", + ) + } + assert matrix.observed_principals == {"application": ()} + assert matrix.absent_principals == {"application": ()} + assert set(matrix.required_connect_databases) == { + "keycloak", + "omnibase_infra", + "omnidash_analytics", + "omninode_cloud", + "omniclaude", + "omniintelligence", + "omnimemory", + "umami", + } + assert not matrix.allowed_connect_principals + assert not matrix.observed_connect_principals + assert not matrix.absent_connect_principals + assert not matrix.observed_connect_database_owners + violations = validate_application_database_acl_matrix(matrix) + assert violations + assert any("cross-domain" in violation for violation in violations) + assert any("not materialized" in violation for violation in violations) + assert all( + f"ACL policy violation: {violation}" in matrix.blockers + for violation in violations + ) + assert not matrix.database_owners + assert not matrix.allowed_memberships + assert all(not row.privileges for row in matrix.default_privileges) + assert all( + not row.privileges for row in matrix.rows if row.principal == PUBLIC_PRINCIPAL + ) + + +def test_candidate_retains_real_blockers_and_never_emits_blocked_sql() -> None: + matrix = _candidate() + blocker_text = "\n".join(matrix.blockers) + + assert "full_day_datname_usename_activity='blocked'" in blocker_text + assert "live_catalog_parity='blocked'" in blocker_text + assert "schema 'unresolved'" in blocker_text + assert "no authoritative repository DDL" in blocker_text + assert "principal_inventory" in blocker_text + assert "acl_policy" in blocker_text + assert "relation_counts.type is not inventoried" in blocker_text + assert "relation_counts.procedure is not inventoried" in blocker_text + assert "requires exactly one CONNECT policy" in blocker_text + assert "full object ACL rendering is gated" in blocker_text + assert "explicit function_signature" in blocker_text + assert not (_PROOF / "generated" / "application-acl.sql").exists() + + +def test_matrix_spans_every_required_object_and_default_privilege_kind() -> None: + matrix = _candidate() + + assert {obj.object_type for obj in matrix.objects} == { + EnumDatabaseGrantObjectType.TABLE, + EnumDatabaseGrantObjectType.SEQUENCE, + EnumDatabaseGrantObjectType.FUNCTION, + } + # No source head declares a type object, but future TYPE privileges are still + # deny-by-default for every actual owner and workload principal. + assert {row.object_type for row in matrix.default_privileges} == { + EnumDatabaseGrantObjectType.TABLE, + EnumDatabaseGrantObjectType.SEQUENCE, + EnumDatabaseGrantObjectType.FUNCTION, + EnumDatabaseGrantObjectType.TYPE, + } diff --git a/tests/fixtures/application_database_acl/acl-policy-postgres16.yaml b/tests/fixtures/application_database_acl/acl-policy-postgres16.yaml new file mode 100644 index 0000000000..25ff4d7cf2 --- /dev/null +++ b/tests/fixtures/application_database_acl/acl-policy-postgres16.yaml @@ -0,0 +1,74 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT + +schema_version: "1.0" +database_ref: application +physical_database: omnidash_analytics +completion_status: verified +source_kind: synthetic_fixture +principal_domains: + onex_api: [TENANT, PLATFORM_CATALOG] + tenant_projection_writer: [TENANT] + app_dashboard: [TENANT, PLATFORM_CATALOG] + omninode_runtime: [OMNINODE_INTERNAL] +database_owner_role: owner_platform_catalog +migration_principal: db_migrator +migration_owner_roles: + - owner_onex_tenant + - owner_omninode_internal + - owner_platform_catalog +governed_role_states: + - {role: app_dashboard, role_kind: workload, login: true} + - {role: db_migrator, role_kind: migration, login: false} + - {role: keycloak_service, role_kind: external_connect, login: true, manage_attributes: false} + - {role: omninode_runtime, role_kind: workload, login: true} + - {role: omnibase_infra_service, role_kind: external_connect, login: true, manage_attributes: false} + - {role: omniclaude_service, role_kind: external_connect, login: true, manage_attributes: false} + - {role: omniintelligence_service, role_kind: external_connect, login: true, manage_attributes: false} + - {role: omnimemory_service, role_kind: external_connect, login: true, manage_attributes: false} + - {role: omninode_cloud_service, role_kind: external_connect, login: true, manage_attributes: false} + - {role: onex_api, role_kind: workload, login: true} + - {role: owner_omninode_internal, role_kind: owner, login: false} + - {role: owner_onex_tenant, role_kind: owner, login: false} + - {role: owner_platform_catalog, role_kind: owner, login: false} + - {role: tenant_projection_writer, role_kind: workload, login: true} + - {role: umami_service, role_kind: external_connect, login: true, manage_attributes: false} +retained_administrative_principals: [rls_admin] +connection_policies: + - database_ref: keycloak + physical_database: keycloak + observed_database_owner_role: postgres + allowed_principals: [keycloak_service] + - database_ref: omnibase_infra + physical_database: omnibase_infra + observed_database_owner_role: postgres + allowed_principals: [omnibase_infra_service] + - database_ref: application + physical_database: omnidash_analytics + observed_database_owner_role: app_dashboard + allowed_principals: + - app_dashboard + - omninode_runtime + - onex_api + - tenant_projection_writer + - database_ref: omninode_cloud + physical_database: omninode_cloud + observed_database_owner_role: postgres + allowed_principals: [omninode_cloud_service] + - database_ref: omniclaude + physical_database: omniclaude + observed_database_owner_role: postgres + allowed_principals: [omniclaude_service] + - database_ref: omniintelligence + physical_database: omniintelligence + observed_database_owner_role: postgres + allowed_principals: [omniintelligence_service] + - database_ref: omnimemory + physical_database: omnimemory + observed_database_owner_role: postgres + allowed_principals: [omnimemory_service] + - database_ref: umami + physical_database: umami + observed_database_owner_role: postgres + allowed_principals: [umami_service] +reason: Independent eight-database CONNECT and application-domain policy. diff --git a/tests/fixtures/application_database_acl/acl-policy.yaml b/tests/fixtures/application_database_acl/acl-policy.yaml new file mode 100644 index 0000000000..afc0610c11 --- /dev/null +++ b/tests/fixtures/application_database_acl/acl-policy.yaml @@ -0,0 +1,39 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT + +schema_version: "1.0" +database_ref: application +physical_database: omnidash_analytics +completion_status: verified +source_kind: synthetic_fixture +principal_domains: + onex_api: [TENANT, PLATFORM_CATALOG] + tenant_projection_writer: [TENANT] + app_dashboard: [TENANT, PLATFORM_CATALOG] + omninode_runtime: [OMNINODE_INTERNAL] +database_owner_role: owner_platform_catalog +migration_principal: db_migrator +migration_owner_roles: + - owner_onex_tenant + - owner_omninode_internal + - owner_platform_catalog +governed_role_states: + - {role: app_dashboard, role_kind: workload, login: true} + - {role: db_migrator, role_kind: migration, login: false} + - {role: omninode_runtime, role_kind: workload, login: true} + - {role: onex_api, role_kind: workload, login: true} + - {role: owner_omninode_internal, role_kind: owner, login: false} + - {role: owner_onex_tenant, role_kind: owner, login: false} + - {role: owner_platform_catalog, role_kind: owner, login: false} + - {role: tenant_projection_writer, role_kind: workload, login: true} +retained_administrative_principals: [rls_admin] +connection_policies: + - database_ref: application + physical_database: omnidash_analytics + observed_database_owner_role: app_dashboard + allowed_principals: + - app_dashboard + - omninode_runtime + - onex_api + - tenant_projection_writer +reason: Independent domain policy for the wholly synthetic ACL proof. diff --git a/tests/fixtures/application_database_acl/inventory.yaml b/tests/fixtures/application_database_acl/inventory.yaml new file mode 100644 index 0000000000..7bb59dfc37 --- /dev/null +++ b/tests/fixtures/application_database_acl/inventory.yaml @@ -0,0 +1,257 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT + +schema_version: "1.0" +ticket: synthetic-proof +database_ref: application +physical_seed_database: omnidash_analytics +ownership_authority: typed synthetic ACL proof inventory +inventory_projection: generated; never an ownership allowlist +completion_status: verified +relation_counts: + table: 5 + view: 1 + materialized_view: 1 + function: 7 + procedure: 1 + sequence: 1 + extension: 0 + type: 5 +relations: + - name: tenant_accounts + kind: table + target_schema: tenant + current_schema: [tenant] + domain: TENANT + owner_declaration: service:onex_api + readers: [onex-api] + writers: [onex-api] + classification_evidence: synthetic control-plane fixture + classification_status: classified + migration_root: proof + - name: delegation_events + kind: table + target_schema: tenant + current_schema: [tenant] + domain: TENANT + owner_declaration: node_projection_delegation + readers: [app-dashboard] + writers: [node_projection_delegation] + classification_evidence: synthetic tenant projection fixture + classification_status: classified + migration_root: proof + - name: partitioned_events + kind: table + target_schema: tenant + current_schema: [tenant] + domain: TENANT + owner_declaration: node_projection_delegation + readers: [] + writers: [] + classification_evidence: synthetic partitioned-table fixture + classification_status: classified + migration_root: proof + - name: runtime_state + kind: table + target_schema: omninode_internal + current_schema: [omninode_internal] + domain: OMNINODE_INTERNAL + owner_declaration: node_runtime_state_projection + readers: [node_runtime_state_projection] + writers: [node_runtime_state_projection] + classification_evidence: synthetic internal fixture + classification_status: classified + migration_root: proof + - name: plan_tiers + kind: table + target_schema: platform_catalog + current_schema: [platform_catalog] + domain: PLATFORM_CATALOG + owner_declaration: service:onex_api + readers: [onex-api, app-dashboard] + writers: [] + classification_evidence: synthetic catalog fixture + classification_status: classified + migration_root: proof + - name: delegation_events_id_seq + kind: sequence + target_schema: tenant + current_schema: [tenant] + domain: TENANT + owner_declaration: node_projection_delegation + writers: [node_projection_delegation] + classification_evidence: synthetic sequence fixture + classification_status: classified + migration_root: proof + - name: delegation_event_count + kind: function + target_schema: tenant + current_schema: [tenant] + domain: TENANT + owner_declaration: node_projection_delegation + readers: [app-dashboard] + function_signature: "()" + classification_evidence: synthetic function fixture + classification_status: classified + migration_root: proof + - name: hostile_signature + kind: function + target_schema: tenant + current_schema: [tenant] + domain: TENANT + owner_declaration: service:onex_api + function_signature: '("arg''name%" integer)' + classification_evidence: synthetic quoted routine-identity fixture + classification_status: classified + migration_root: proof + - name: record_delegation + kind: procedure + target_schema: tenant + current_schema: [tenant] + domain: TENANT + owner_declaration: node_projection_delegation + writers: [node_projection_delegation] + function_signature: "(IN p_payload text)" + classification_evidence: synthetic procedure fixture + classification_status: classified + migration_root: proof + - name: tenant_account_names + kind: view + target_schema: tenant + current_schema: [tenant] + domain: TENANT + owner_declaration: service:onex_api + readers: [app-dashboard] + classification_evidence: synthetic view fixture + classification_status: classified + migration_root: proof + - name: plan_tier_snapshot + kind: materialized_view + target_schema: platform_catalog + current_schema: [platform_catalog] + domain: PLATFORM_CATALOG + owner_declaration: service:onex_api + readers: [app-dashboard] + classification_evidence: synthetic materialized-view fixture + classification_status: classified + migration_root: proof + - name: account_ref + kind: type + target_schema: tenant + current_schema: [tenant] + domain: TENANT + owner_declaration: service:onex_api + readers: [onex-api] + classification_evidence: synthetic composite-type fixture + classification_status: classified + migration_root: proof + - name: account_id_span + kind: type + target_schema: tenant + current_schema: [tenant] + domain: TENANT + owner_declaration: service:onex_api + readers: [onex-api] + classification_evidence: synthetic range-type fixture + classification_status: classified + migration_root: proof + - name: account_id_span_set + kind: type + target_schema: tenant + current_schema: [tenant] + domain: TENANT + owner_declaration: service:onex_api + readers: [onex-api] + classification_evidence: synthetic multirange-type fixture + classification_status: classified + migration_root: proof + - name: account_id_span + kind: function + target_schema: tenant + current_schema: [tenant] + domain: TENANT + owner_declaration: service:onex_api + function_signature: "(bigint, bigint)" + classification_evidence: synthetic range-constructor fixture + classification_status: classified + migration_root: proof + - name: account_id_span + kind: function + target_schema: tenant + current_schema: [tenant] + domain: TENANT + owner_declaration: service:onex_api + function_signature: "(bigint, bigint, text)" + classification_evidence: synthetic range-constructor fixture + classification_status: classified + migration_root: proof + - name: account_id_span_set + kind: function + target_schema: tenant + current_schema: [tenant] + domain: TENANT + owner_declaration: service:onex_api + function_signature: "()" + classification_evidence: synthetic multirange-constructor fixture + classification_status: classified + migration_root: proof + - name: account_id_span_set + kind: function + target_schema: tenant + current_schema: [tenant] + domain: TENANT + owner_declaration: service:onex_api + function_signature: "(VARIADIC tenant.account_id_span[])" + classification_evidence: synthetic multirange-constructor fixture + classification_status: classified + migration_root: proof + - name: account_id_span_set + kind: function + target_schema: tenant + current_schema: [tenant] + domain: TENANT + owner_declaration: service:onex_api + function_signature: "(tenant.account_id_span)" + classification_evidence: synthetic multirange-constructor fixture + classification_status: classified + migration_root: proof + - name: runtime_status + kind: type + target_schema: omninode_internal + current_schema: [omninode_internal] + domain: OMNINODE_INTERNAL + owner_declaration: node_runtime_state_projection + readers: [node_runtime_state_projection] + classification_evidence: synthetic type fixture + classification_status: classified + migration_root: proof + - name: runtime_code + kind: type + target_schema: omninode_internal + current_schema: [omninode_internal] + domain: OMNINODE_INTERNAL + owner_declaration: node_runtime_state_projection + readers: [node_runtime_state_projection] + classification_evidence: synthetic domain-type fixture + classification_status: classified + migration_root: proof +blocked_relations: [] +retained_live_census: + observed_base_tables: 5 + observed_views_and_materialized_views: 2 + observed_sequences: 1 + observed_functions: 7 + observed_procedures: 1 + observed_types: 5 + observed_extensions: 0 + parity_status: verified + reason: synthetic inventory is exact +runtime_evidence: + dsn_key_provenance: {} + full_day_datname_usename_activity: + status: verified + reason: synthetic proof has no live activity claim + credentials_captured: false + live_catalog_parity: + status: verified + reason: synthetic object seed is exact diff --git a/tests/fixtures/application_database_acl/principal-inventories-external.yaml b/tests/fixtures/application_database_acl/principal-inventories-external.yaml new file mode 100644 index 0000000000..3b937d80e7 --- /dev/null +++ b/tests/fixtures/application_database_acl/principal-inventories-external.yaml @@ -0,0 +1,108 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT + +- schema_version: "1.0" + database_ref: keycloak + physical_database: keycloak + completion_status: verified + catalog_parity_status: verified + source_kind: synthetic_fixture + database_owner_role: postgres + principal_refs: &all_external_principals + - app_dashboard + - external_connect_parent + - keycloak_service + - omnibase_infra_service + - omniclaude_service + - omniintelligence_service + - omnimemory_service + - omninode_cloud_service + - omninode_runtime + - onex_api + - rls_admin + - tenant_projection_writer + - umami_service + - untrusted_login + observed_role_states: &all_external_role_states + - {role: app_dashboard, login: true, superuser: false, bypass_rls: false, create_database: false, create_role: true, replication: false, inherit: true} + - {role: external_connect_parent, login: false, superuser: false, bypass_rls: true, create_database: false, create_role: false, replication: false, inherit: true} + - {role: keycloak_service, login: true, superuser: false, bypass_rls: false, create_database: false, create_role: false, replication: false, inherit: false} + - {role: omnibase_infra_service, login: true, superuser: false, bypass_rls: false, create_database: false, create_role: false, replication: false, inherit: false} + - {role: omniclaude_service, login: true, superuser: false, bypass_rls: false, create_database: false, create_role: false, replication: false, inherit: false} + - {role: omniintelligence_service, login: true, superuser: false, bypass_rls: false, create_database: false, create_role: false, replication: false, inherit: false} + - {role: omnimemory_service, login: true, superuser: false, bypass_rls: false, create_database: false, create_role: false, replication: false, inherit: false} + - {role: omninode_cloud_service, login: true, superuser: false, bypass_rls: false, create_database: false, create_role: false, replication: false, inherit: false} + - {role: omninode_runtime, login: true, superuser: false, bypass_rls: false, create_database: false, create_role: false, replication: true, inherit: true} + - {role: onex_api, login: true, superuser: false, bypass_rls: false, create_database: true, create_role: false, replication: false, inherit: true} + - {role: rls_admin, login: false, superuser: false, bypass_rls: true, create_database: false, create_role: false, replication: false, inherit: true} + - {role: tenant_projection_writer, login: true, superuser: false, bypass_rls: true, create_database: false, create_role: false, replication: false, inherit: true} + - {role: umami_service, login: true, superuser: false, bypass_rls: false, create_database: false, create_role: false, replication: false, inherit: false} + - {role: untrusted_login, login: true, superuser: false, bypass_rls: false, create_database: false, create_role: false, replication: false, inherit: true} + live_database_read: false + reason: Exact synthetic cluster-role census for Keycloak CONNECT isolation. +- schema_version: "1.0" + database_ref: omnibase_infra + physical_database: omnibase_infra + completion_status: verified + catalog_parity_status: verified + source_kind: synthetic_fixture + database_owner_role: postgres + principal_refs: *all_external_principals + observed_role_states: *all_external_role_states + live_database_read: false + reason: Exact synthetic cluster-role census for omnibase_infra CONNECT isolation. +- schema_version: "1.0" + database_ref: omninode_cloud + physical_database: omninode_cloud + completion_status: verified + catalog_parity_status: verified + source_kind: synthetic_fixture + database_owner_role: postgres + principal_refs: *all_external_principals + observed_role_states: *all_external_role_states + live_database_read: false + reason: Exact synthetic cluster-role census for omninode_cloud CONNECT isolation. +- schema_version: "1.0" + database_ref: omniclaude + physical_database: omniclaude + completion_status: verified + catalog_parity_status: verified + source_kind: synthetic_fixture + database_owner_role: postgres + principal_refs: *all_external_principals + observed_role_states: *all_external_role_states + live_database_read: false + reason: Exact synthetic cluster-role census for omniclaude CONNECT isolation. +- schema_version: "1.0" + database_ref: omniintelligence + physical_database: omniintelligence + completion_status: verified + catalog_parity_status: verified + source_kind: synthetic_fixture + database_owner_role: postgres + principal_refs: *all_external_principals + observed_role_states: *all_external_role_states + live_database_read: false + reason: Exact synthetic cluster-role census for omniintelligence CONNECT isolation. +- schema_version: "1.0" + database_ref: omnimemory + physical_database: omnimemory + completion_status: verified + catalog_parity_status: verified + source_kind: synthetic_fixture + database_owner_role: postgres + principal_refs: *all_external_principals + observed_role_states: *all_external_role_states + live_database_read: false + reason: Exact synthetic cluster-role census for omnimemory CONNECT isolation. +- schema_version: "1.0" + database_ref: umami + physical_database: umami + completion_status: verified + catalog_parity_status: verified + source_kind: synthetic_fixture + database_owner_role: postgres + principal_refs: *all_external_principals + observed_role_states: *all_external_role_states + live_database_read: false + reason: Exact synthetic cluster-role census for umami CONNECT isolation. diff --git a/tests/fixtures/application_database_acl/principal-inventory-postgres16.yaml b/tests/fixtures/application_database_acl/principal-inventory-postgres16.yaml new file mode 100644 index 0000000000..9e174d1b79 --- /dev/null +++ b/tests/fixtures/application_database_acl/principal-inventory-postgres16.yaml @@ -0,0 +1,61 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT + +schema_version: "1.0" +database_ref: application +physical_database: omnidash_analytics +completion_status: verified +catalog_parity_status: verified +source_kind: synthetic_fixture +database_owner_role: app_dashboard +principal_refs: + - app_dashboard + - db_migrator + - omninode_runtime + - onex_api + - rls_admin + - tenant_projection_writer + - untrusted_login +owner_refs: + - owner_omninode_internal + - owner_onex_tenant + - owner_platform_catalog +observed_role_states: + - {role: app_dashboard, login: true, superuser: false, bypass_rls: false, create_database: false, create_role: true, replication: false, inherit: true} + - {role: db_migrator, login: false, superuser: false, bypass_rls: false, create_database: false, create_role: false, replication: false, inherit: true} + - {role: omninode_runtime, login: true, superuser: false, bypass_rls: false, create_database: false, create_role: false, replication: true, inherit: true} + - {role: onex_api, login: true, superuser: false, bypass_rls: false, create_database: true, create_role: false, replication: false, inherit: true} + - {role: rls_admin, login: false, superuser: false, bypass_rls: true, create_database: false, create_role: false, replication: false, inherit: true} + - {role: tenant_projection_writer, login: true, superuser: false, bypass_rls: true, create_database: false, create_role: false, replication: false, inherit: true} + - {role: untrusted_login, login: true, superuser: false, bypass_rls: false, create_database: false, create_role: false, replication: false, inherit: true} + - {role: owner_omninode_internal, login: false, superuser: false, bypass_rls: false, create_database: false, create_role: false, replication: false, inherit: true} + - {role: owner_onex_tenant, login: false, superuser: false, bypass_rls: false, create_database: false, create_role: false, replication: false, inherit: true} + - {role: owner_platform_catalog, login: false, superuser: false, bypass_rls: false, create_database: false, create_role: false, replication: false, inherit: true} +observed_schema_owners: + tenant: app_dashboard + omninode_internal: tenant_projection_writer + platform_catalog: onex_api +observed_objects: + - {schema_ref: tenant, catalog_kind: table, object_ref: tenant_accounts, owner: onex_api} + - {schema_ref: tenant, catalog_kind: table, object_ref: delegation_events, owner: app_dashboard} + - {schema_ref: tenant, catalog_kind: table, object_ref: partitioned_events, owner: onex_api} + - {schema_ref: tenant, catalog_kind: sequence, object_ref: delegation_events_id_seq, owner: app_dashboard} + - {schema_ref: tenant, catalog_kind: function, object_ref: delegation_event_count, function_signature: "()", owner: app_dashboard} + - {schema_ref: tenant, catalog_kind: function, object_ref: hostile_signature, function_signature: '("arg''name%" integer)', owner: app_dashboard} + - {schema_ref: tenant, catalog_kind: procedure, object_ref: record_delegation, function_signature: "(IN p_payload text)", owner: app_dashboard} + - {schema_ref: tenant, catalog_kind: view, object_ref: tenant_account_names, owner: app_dashboard} + - {schema_ref: tenant, catalog_kind: type, object_ref: account_ref, owner: onex_api} + - {schema_ref: tenant, catalog_kind: type, object_ref: account_id_span, owner: onex_api} + - {schema_ref: tenant, catalog_kind: type, object_ref: account_id_span_set, owner: onex_api} + - {schema_ref: tenant, catalog_kind: function, object_ref: account_id_span, function_signature: "(bigint, bigint)", owner: onex_api} + - {schema_ref: tenant, catalog_kind: function, object_ref: account_id_span, function_signature: "(bigint, bigint, text)", owner: onex_api} + - {schema_ref: tenant, catalog_kind: function, object_ref: account_id_span_set, function_signature: "()", owner: onex_api} + - {schema_ref: tenant, catalog_kind: function, object_ref: account_id_span_set, function_signature: "(VARIADIC tenant.account_id_span[])", owner: onex_api} + - {schema_ref: tenant, catalog_kind: function, object_ref: account_id_span_set, function_signature: "(tenant.account_id_span)", owner: onex_api} + - {schema_ref: omninode_internal, catalog_kind: type, object_ref: runtime_status, owner: omninode_runtime} + - {schema_ref: omninode_internal, catalog_kind: type, object_ref: runtime_code, owner: omninode_runtime} + - {schema_ref: omninode_internal, catalog_kind: table, object_ref: runtime_state, owner: tenant_projection_writer} + - {schema_ref: platform_catalog, catalog_kind: table, object_ref: plan_tiers, owner: onex_api} + - {schema_ref: platform_catalog, catalog_kind: materialized_view, object_ref: plan_tier_snapshot, owner: onex_api} +live_database_read: false +reason: Exact relevant-principal census for the synthetic application database. diff --git a/tests/fixtures/application_database_acl/principal-inventory.yaml b/tests/fixtures/application_database_acl/principal-inventory.yaml new file mode 100644 index 0000000000..d34cc21883 --- /dev/null +++ b/tests/fixtures/application_database_acl/principal-inventory.yaml @@ -0,0 +1,61 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT + +schema_version: "1.0" +database_ref: application +physical_database: omnidash_analytics +completion_status: verified +catalog_parity_status: verified +source_kind: synthetic_fixture +database_owner_role: app_dashboard +principal_refs: + - app_dashboard + - db_migrator + - omninode_runtime + - onex_api + - rls_admin + - tenant_projection_writer + - untrusted_login +owner_refs: + - owner_omninode_internal + - owner_onex_tenant + - owner_platform_catalog +observed_role_states: + - {role: app_dashboard, login: true, superuser: false, bypass_rls: false, create_database: false, create_role: false, replication: false, inherit: false} + - {role: db_migrator, login: false, superuser: false, bypass_rls: false, create_database: false, create_role: false, replication: false, inherit: false} + - {role: omninode_runtime, login: true, superuser: false, bypass_rls: false, create_database: false, create_role: false, replication: false, inherit: false} + - {role: onex_api, login: true, superuser: false, bypass_rls: false, create_database: false, create_role: false, replication: false, inherit: false} + - {role: rls_admin, login: false, superuser: false, bypass_rls: true, create_database: false, create_role: false, replication: false, inherit: true} + - {role: tenant_projection_writer, login: true, superuser: false, bypass_rls: false, create_database: false, create_role: false, replication: false, inherit: false} + - {role: untrusted_login, login: true, superuser: false, bypass_rls: false, create_database: false, create_role: false, replication: false, inherit: true} + - {role: owner_omninode_internal, login: false, superuser: false, bypass_rls: false, create_database: false, create_role: false, replication: false, inherit: false} + - {role: owner_onex_tenant, login: false, superuser: false, bypass_rls: false, create_database: false, create_role: false, replication: false, inherit: false} + - {role: owner_platform_catalog, login: false, superuser: false, bypass_rls: false, create_database: false, create_role: false, replication: false, inherit: false} +observed_schema_owners: + tenant: app_dashboard + omninode_internal: tenant_projection_writer + platform_catalog: onex_api +observed_objects: + - {schema_ref: tenant, catalog_kind: table, object_ref: tenant_accounts, owner: onex_api} + - {schema_ref: tenant, catalog_kind: table, object_ref: delegation_events, owner: app_dashboard} + - {schema_ref: tenant, catalog_kind: table, object_ref: partitioned_events, owner: onex_api} + - {schema_ref: tenant, catalog_kind: sequence, object_ref: delegation_events_id_seq, owner: app_dashboard} + - {schema_ref: tenant, catalog_kind: function, object_ref: delegation_event_count, function_signature: "()", owner: app_dashboard} + - {schema_ref: tenant, catalog_kind: function, object_ref: hostile_signature, function_signature: '("arg''name%" integer)', owner: app_dashboard} + - {schema_ref: tenant, catalog_kind: procedure, object_ref: record_delegation, function_signature: "(IN p_payload text)", owner: app_dashboard} + - {schema_ref: tenant, catalog_kind: view, object_ref: tenant_account_names, owner: app_dashboard} + - {schema_ref: tenant, catalog_kind: type, object_ref: account_ref, owner: onex_api} + - {schema_ref: tenant, catalog_kind: type, object_ref: account_id_span, owner: onex_api} + - {schema_ref: tenant, catalog_kind: type, object_ref: account_id_span_set, owner: onex_api} + - {schema_ref: tenant, catalog_kind: function, object_ref: account_id_span, function_signature: "(bigint, bigint)", owner: onex_api} + - {schema_ref: tenant, catalog_kind: function, object_ref: account_id_span, function_signature: "(bigint, bigint, text)", owner: onex_api} + - {schema_ref: tenant, catalog_kind: function, object_ref: account_id_span_set, function_signature: "()", owner: onex_api} + - {schema_ref: tenant, catalog_kind: function, object_ref: account_id_span_set, function_signature: "(VARIADIC tenant.account_id_span[])", owner: onex_api} + - {schema_ref: tenant, catalog_kind: function, object_ref: account_id_span_set, function_signature: "(tenant.account_id_span)", owner: onex_api} + - {schema_ref: omninode_internal, catalog_kind: type, object_ref: runtime_status, owner: omninode_runtime} + - {schema_ref: omninode_internal, catalog_kind: type, object_ref: runtime_code, owner: omninode_runtime} + - {schema_ref: omninode_internal, catalog_kind: table, object_ref: runtime_state, owner: tenant_projection_writer} + - {schema_ref: platform_catalog, catalog_kind: table, object_ref: plan_tiers, owner: onex_api} + - {schema_ref: platform_catalog, catalog_kind: materialized_view, object_ref: plan_tier_snapshot, owner: onex_api} +live_database_read: false +reason: Exact role census for the wholly synthetic PostgreSQL 16 ACL proof. diff --git a/tests/fixtures/application_database_acl/topology.yaml b/tests/fixtures/application_database_acl/topology.yaml new file mode 100644 index 0000000000..ea63e9e0d0 --- /dev/null +++ b/tests/fixtures/application_database_acl/topology.yaml @@ -0,0 +1,116 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT + +schema_version: "2.0" +services: {} +presets: {} +active_preset: null +databases: + application: + physical_name: omnidash_analytics + schemas: + tenant: {domain: TENANT, owner: owner_onex_tenant} + omninode_internal: {domain: OMNINODE_INTERNAL, owner: owner_omninode_internal} + platform_catalog: {domain: PLATFORM_CATALOG, owner: owner_platform_catalog} + owners: + owner_onex_tenant: {login: false} + owner_omninode_internal: {login: false} + owner_platform_catalog: {login: false} + principals: + onex_api: + login: true + bypass_rls: false + grants: + - {object_type: DATABASE, privileges: [CONNECT]} + - {object_type: SCHEMA, schema: tenant, privileges: [USAGE]} + - {object_type: SCHEMA, schema: platform_catalog, privileges: [USAGE]} + - object_type: TABLE + schema: tenant + objects: [tenant_accounts] + privileges: [SELECT, INSERT, UPDATE] + - object_type: TYPE + schema: tenant + objects: [account_id_span, account_id_span_set, account_ref] + privileges: [USAGE] + - object_type: TABLE + schema: platform_catalog + objects: [plan_tiers] + privileges: [SELECT] + tenant_projection_writer: + login: true + bypass_rls: false + grants: + - {object_type: DATABASE, privileges: [CONNECT]} + - {object_type: SCHEMA, schema: tenant, privileges: [USAGE]} + - object_type: TABLE + schema: tenant + objects: [delegation_events] + privileges: [SELECT, INSERT, UPDATE] + - object_type: SEQUENCE + schema: tenant + objects: [delegation_events_id_seq] + privileges: [USAGE] + - object_type: FUNCTION + schema: tenant + objects: [record_delegation] + privileges: [EXECUTE] + app_dashboard: + login: true + bypass_rls: false + grants: + - {object_type: DATABASE, privileges: [CONNECT]} + - {object_type: SCHEMA, schema: tenant, privileges: [USAGE]} + - {object_type: SCHEMA, schema: platform_catalog, privileges: [USAGE]} + - object_type: TABLE + schema: tenant + objects: [delegation_events, tenant_account_names] + privileges: [SELECT] + - object_type: TABLE + schema: platform_catalog + objects: [plan_tier_snapshot, plan_tiers] + privileges: [SELECT] + - object_type: FUNCTION + schema: tenant + objects: [delegation_event_count] + privileges: [EXECUTE] + omninode_runtime: + login: true + bypass_rls: false + grants: + - {object_type: DATABASE, privileges: [CONNECT]} + - {object_type: SCHEMA, schema: omninode_internal, privileges: [USAGE]} + - object_type: TABLE + schema: omninode_internal + objects: [runtime_state] + privileges: [SELECT, INSERT, UPDATE] + - object_type: TYPE + schema: omninode_internal + objects: [runtime_code, runtime_status] + privileges: [USAGE] + bindings: + onex_api: + database_ref: application + principal: onex_api + dsn_env: OMNINODE_CLOUD_DB_URL + tenant_projection: + database_ref: application + principal: tenant_projection_writer + dsn_env: OMNIDASH_ANALYTICS_DB_URL + app_dashboard: + database_ref: application + principal: app_dashboard + dsn_env: DATABASE_URL + omninode_runtime_service: + database_ref: application + principal: omninode_runtime + dsn_env: OMNINODE_INTERNAL_DB_URL + migration_stream: omnibase_infra.application + checksum_ledgers: + canonical: + schema: platform_catalog + relation: schema_migrations + stream_column: migration_stream + domain_column: domain + version_column: version + checksum_column: checksum + checksum_ledger: canonical diff --git a/tests/integration/test_application_acl_postgres16_proof.py b/tests/integration/test_application_acl_postgres16_proof.py new file mode 100644 index 0000000000..98a50eb233 --- /dev/null +++ b/tests/integration/test_application_acl_postgres16_proof.py @@ -0,0 +1,61 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT +"""Rebuilt PostgreSQL 16 integration proof for the generated ACL matrix.""" + +from __future__ import annotations + +import os +import shutil +import subprocess +from pathlib import Path + +import pytest + +_ROOT = Path(__file__).parents[2] +_COMPOSE = _ROOT / "docker" / "application-acl-proof" / "compose.yml" +_HAS_DOCKER = shutil.which("docker") is not None + + +@pytest.mark.slow +@pytest.mark.skipif(not _HAS_DOCKER, reason="Requires a Docker engine") +def test_rebuilt_postgres16_acl_and_rollback_proof() -> None: + project_name = f"application-acl-proof-{os.getpid()}" + command = [ + "docker", + "compose", + "-p", + project_name, + "-f", + str(_COMPOSE), + ] + result = subprocess.run( + [ + *command, + "up", + "--build", + "--abort-on-container-exit", + "--exit-code-from", + "proof", + ], + cwd=_ROOT, + capture_output=True, + text=True, + timeout=1_500, + check=False, + ) + try: + assert result.returncode == 0, result.stdout + result.stderr + output = result.stdout + result.stderr + assert "acl_phase=scaffold_wrong_database_guard status=PASS" in output + assert "acl_phase=scaffold_fresh_additive_round_trip status=PASS" in output + assert "acl_phase=rollback_atomic_failure" in output + assert "acl_status=PASS postgres_major=16" in output + finally: + subprocess.run( + [*command, "down", "--volumes", "--remove-orphans"], + cwd=_ROOT, + capture_output=True, + text=True, + timeout=120, + check=False, + ) diff --git a/tests/unit/contracts/test_protocol_ownership.py b/tests/unit/contracts/test_protocol_ownership.py index 7f806c4cc7..9caf3a8840 100644 --- a/tests/unit/contracts/test_protocol_ownership.py +++ b/tests/unit/contracts/test_protocol_ownership.py @@ -131,6 +131,7 @@ "ProtocolSecretResolverMetrics": "runtime/secret_resolver.py", "ProtocolDbTableCatalogConnection": "runtime/auto_wiring/protocol_db_table_catalog_connection.py", # [RUNTIME] OMN-15418 narrow asyncpg catalog-query boundary for typed table ownership validation "ProtocolProjectionTenantBindingResolver": "runtime/projection_tenant_authority.py", # [DI] OMN-15421 signer-scope-to-tenant authority binding injected at the verification boundary + "ProtocolApplicationDatabaseRoleAttributeState": "validation/application_database_acl.py", # [DI] OMN-15355 shared read-only role-attribute shape for generated ACL policy and observed catalog state "ProtocolHandleable": "runtime/auto_wiring/handler_wiring.py", # [RUNTIME] OMN-7656 auto-wiring dispatch "ProtocolDelegationDispatchPort": "runtime/protocols/protocol_delegation_dispatch_port.py", # [RUNTIME] OMN-E0 delegation dispatch port interface — infra-internal, narrows dispatch surface for handler injection # OMN-13445: the 5 ProtocolLocalRuntime* protocols relocated to diff --git a/tests/unit/validation/test_application_database_acl.py b/tests/unit/validation/test_application_database_acl.py new file mode 100644 index 0000000000..4a6497555e --- /dev/null +++ b/tests/unit/validation/test_application_database_acl.py @@ -0,0 +1,1413 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT + +"""Generated application-database ACL matrix tests.""" + +from __future__ import annotations + +from datetime import UTC, datetime, timedelta, timezone +from pathlib import Path + +import pytest +import yaml +from pydantic import ValidationError + +from omnibase_core.enums.enum_database_grant_object_type import ( + EnumDatabaseGrantObjectType, +) +from omnibase_core.enums.enum_database_privilege import EnumDatabasePrivilege +from omnibase_core.models.core.model_deployment_topology import ModelDeploymentTopology +from omnibase_infra.validation.application_database_acl import ( + PUBLIC_PRINCIPAL, + build_application_database_acl_matrix, + render_application_database_acl_sql, + validate_application_database_acl_matrix, + validate_application_database_acl_scaffold, + validate_application_database_principal_evidence, +) +from omnibase_infra.validation.enums.enum_application_database_acl_authorization_scope import ( + EnumApplicationDatabaseAclAuthorizationScope, +) +from omnibase_infra.validation.enums.enum_application_database_acl_render_phase import ( + EnumApplicationDatabaseAclRenderPhase, +) +from omnibase_infra.validation.models.model_application_database_acl_matrix import ( + ModelApplicationDatabaseAclMatrix, + ModelApplicationDatabaseAclSource, +) +from omnibase_infra.validation.models.model_application_database_acl_object import ( + ModelApplicationDatabaseAclObject, +) +from omnibase_infra.validation.models.model_application_database_acl_policy import ( + ModelApplicationDatabaseAclPolicy, +) +from omnibase_infra.validation.models.model_application_database_acl_row import ( + ModelApplicationDatabaseAclRow, +) +from omnibase_infra.validation.models.model_application_database_activity_result_evidence import ( + ModelApplicationDatabaseActivityResultEvidence, +) +from omnibase_infra.validation.models.model_application_database_catalog_result_evidence import ( + ModelApplicationDatabaseCatalogResultEvidence, +) +from omnibase_infra.validation.models.model_application_database_principal_inventory import ( + ModelApplicationDatabasePrincipalInventory, +) +from omnibase_infra.validation.models.model_application_relation_evidence_inventory import ( + ModelApplicationRelationEvidenceInventory, +) +from omnibase_infra.validation.models.model_migration_ownership_manifest import ( + ModelMigrationOwnershipManifest, +) + +pytestmark = pytest.mark.unit + +_FIXTURES = Path(__file__).parents[2] / "fixtures" / "application_database_acl" + + +def _source(source_id: str, purpose: str) -> ModelApplicationDatabaseAclSource: + return ModelApplicationDatabaseAclSource.model_validate( + { + "source_key": source_id, + "repository": "synthetic/proof", + "revision": "a" * 40, + "path": f"proof/{source_id}.yaml", + "sha256": "b" * 64, + "purpose": purpose, + } + ) + + +def _inventory() -> ModelApplicationRelationEvidenceInventory: + return ModelApplicationRelationEvidenceInventory.model_validate( + yaml.safe_load((_FIXTURES / "inventory.yaml").read_text(encoding="utf-8")) + ) + + +def _principal_inventory() -> ModelApplicationDatabasePrincipalInventory: + return ModelApplicationDatabasePrincipalInventory.model_validate( + yaml.safe_load( + (_FIXTURES / "principal-inventory.yaml").read_text(encoding="utf-8") + ) + ) + + +def _acl_policy() -> ModelApplicationDatabaseAclPolicy: + return ModelApplicationDatabaseAclPolicy.model_validate( + yaml.safe_load((_FIXTURES / "acl-policy.yaml").read_text(encoding="utf-8")) + ) + + +def _authorized_inventory( + *, + active_principals: tuple[str, ...] = ("app_dashboard",), + observation_count: int = 1, +) -> ModelApplicationDatabasePrincipalInventory: + payload = _principal_inventory().model_dump(mode="json") + started = datetime(2026, 7, 28, tzinfo=UTC) + payload.update( + { + "source_kind": "authorized_catalog", + "live_database_read": True, + "catalog_query_sha256": "1" * 64, + "catalog_result_sha256": "2" * 64, + "catalog_query_source_key": "catalog_query", + "catalog_result_source_key": "catalog_result", + "activity_principal_refs": list(active_principals), + "activity_evidence": { + "window_started_at": started.isoformat(), + "window_ended_at": (started + timedelta(hours=24)).isoformat(), + "query_sha256": "3" * 64, + "result_sha256": "4" * 64, + "query_source_key": "activity_query", + "result_source_key": "activity_result", + "observation_count": observation_count, + }, + } + ) + return ModelApplicationDatabasePrincipalInventory.model_validate(payload) + + +def _complete_sources() -> tuple[ModelApplicationDatabaseAclSource, ...]: + return ( + _source("topology", "topology"), + _source("inventory", "relation_inventory"), + _source("principal_inventory", "principal_inventory"), + _source("acl_policy", "acl_policy"), + ) + + +def _matrix() -> ModelApplicationDatabaseAclMatrix: + return build_application_database_acl_matrix( + topology=ModelDeploymentTopology.from_yaml(_FIXTURES / "topology.yaml"), + sources=_complete_sources(), + relation_inventories={"inventory": _inventory()}, + service_manifests={}, + principal_inventories={"principal_inventory": _principal_inventory()}, + acl_policies={"acl_policy": _acl_policy()}, + authorization_scope=EnumApplicationDatabaseAclAuthorizationScope.SYNTHETIC_PROOF, + ) + + +def test_matrix_covers_every_principal_object_and_future_acl_cell() -> None: + matrix = _matrix() + + assert matrix.status == "READY" + assert not matrix.blockers + assert len(matrix.objects) == 21 + # PUBLIC plus the exact seven-principal synthetic census across all targets. + assert len(matrix.rows) == 8 * (1 + 3 + 21) + # Three owners/schemas x four kinds x the complete eight-grantee universe. + assert len(matrix.default_privileges) == 3 * 4 * 8 + assert matrix.required_connect_databases == ("omnidash_analytics",) + assert matrix.allowed_connect_principals == { + "omnidash_analytics": ( + "app_dashboard", + "omninode_runtime", + "onex_api", + "tenant_projection_writer", + ) + } + partitioned = next( + obj for obj in matrix.objects if obj.object_ref == "partitioned_events" + ) + assert partitioned.catalog_kind == "table" + assert not validate_application_database_acl_matrix(matrix) + + +def test_renderer_emits_exact_objects_and_deny_by_default_future_acls() -> None: + sql = render_application_database_acl_sql( + _matrix(), + allow_synthetic_proof=True, + ) + + assert sql.splitlines()[sql.splitlines().index("\\set ON_ERROR_STOP on") + 1] == ( + "BEGIN;" + ) + assert sql.rstrip().endswith("COMMIT;") + assert "LOCK TABLE pg_catalog.pg_depend IN SHARE MODE;" in sql + assert 'REVOKE ALL PRIVILEGES ON DATABASE "omnidash_analytics" FROM PUBLIC' in sql + assert ( + 'ALTER DATABASE "omnidash_analytics" OWNER TO "owner_platform_catalog";' in sql + ) + database_revoke = next( + line + for line in sql.splitlines() + if line.startswith("REVOKE ALL PRIVILEGES ON DATABASE") + ) + assert '"untrusted_login"' in database_revoke + assert 'CREATE ROLE "untrusted_login"' not in sql + assert 'ALTER ROLE "untrusted_login"' not in sql + assert 'ALTER ROLE "rls_admin"' not in sql + assert ( + 'ALTER TABLE "tenant"."delegation_events" OWNER TO "owner_onex_tenant";' in sql + ) + assert ( + 'ALTER TABLE "tenant"."partitioned_events" OWNER TO "owner_onex_tenant";' in sql + ) + assert sql.index( + 'ALTER TABLE "tenant"."delegation_events" OWNER TO "owner_onex_tenant";' + ) < sql.index( + 'ALTER SEQUENCE "tenant"."delegation_events_id_seq" OWNER TO ' + '"owner_onex_tenant";' + ) + assert ( + 'GRANT SELECT ON TABLE "tenant"."delegation_events" TO "app_dashboard";' in sql + ) + assert 'ALTER VIEW "tenant"."tenant_account_names" OWNER TO' in sql + assert ( + 'GRANT SELECT ON TABLE "tenant"."tenant_account_names" TO "app_dashboard";' + ) in sql + assert ( + 'GRANT "owner_onex_tenant" TO "db_migrator" WITH ADMIN FALSE, ' + "INHERIT FALSE, SET TRUE;" + ) in sql + assert "ALL TABLES IN SCHEMA" not in sql + assert "ALL SEQUENCES IN SCHEMA" not in sql + assert ( + 'ALTER DEFAULT PRIVILEGES FOR ROLE "owner_onex_tenant" ' + "REVOKE ALL PRIVILEGES ON FUNCTIONS FROM PUBLIC CASCADE;" + ) in sql + assert ( + 'ALTER DEFAULT PRIVILEGES FOR ROLE "owner_onex_tenant" IN SCHEMA ' + '"tenant" REVOKE ALL PRIVILEGES ON FUNCTIONS FROM PUBLIC CASCADE;' + ) in sql + assert ( + "'(\"arg''name%\" integer)'" in sql + and '"hostile_signature"("arg\'name%" integer)' in sql + and '"hostile_signature"("arg\'\'name%%" integer)' in sql + ) + assert "defaults.defaclnamespace = 0" in sql + assert ( + "OR namespace.nspname IN ('omninode_internal', 'platform_catalog', 'tenant')" + in sql + ) + + +def test_scaffold_renders_while_nonmaterialized_full_phase_stays_blocked() -> None: + ready = _matrix() + staged = ready.model_copy( + update={ + "status": "BLOCKED", + "blockers": ("target objects are not materialized",), + "objects": tuple( + obj.model_copy(update={"target_materialized": False}) + for obj in ready.objects + ), + } + ) + + assert staged.scaffold_status == "READY" + assert not validate_application_database_acl_scaffold(staged) + scaffold = render_application_database_acl_sql( + staged, + allow_synthetic_proof=True, + phase=EnumApplicationDatabaseAclRenderPhase.SCAFFOLD, + ) + assert "-- Render phase: scaffold" in scaffold + assert "current_database()" in scaffold + assert "locked schema census is stale: expected present schema tenant" in scaffold + assert 'ALTER SCHEMA "tenant"' not in scaffold + assert 'REVOKE ALL PRIVILEGES ON SCHEMA "public"' not in scaffold + assert 'REVOKE ALL PRIVILEGES ON DATABASE "omnidash_analytics"' not in scaffold + assert "ALTER DEFAULT PRIVILEGES" not in scaffold + assert "ALTER TABLE " not in scaffold + assert "GRANT SELECT ON TABLE " not in scaffold + with pytest.raises(ValueError, match="Cannot render blocked ACL matrix"): + render_application_database_acl_sql(staged, allow_synthetic_proof=True) + + +def test_scaffold_creates_policy_declared_role_with_exact_absence_evidence() -> None: + payload = _principal_inventory().model_dump(mode="json") + payload["principal_refs"].remove("omninode_runtime") + payload["absent_principal_refs"] = ["omninode_runtime"] + payload["observed_role_states"] = [ + state + for state in payload["observed_role_states"] + if state["role"] != "omninode_runtime" + ] + for obj in payload["observed_objects"]: + if obj["owner"] == "omninode_runtime": + obj["owner"] = "app_dashboard" + inventory = ModelApplicationDatabasePrincipalInventory.model_validate(payload) + matrix = build_application_database_acl_matrix( + topology=ModelDeploymentTopology.from_yaml(_FIXTURES / "topology.yaml"), + sources=_complete_sources(), + relation_inventories={"inventory": _inventory()}, + service_manifests={}, + principal_inventories={"principal_inventory": inventory}, + acl_policies={"acl_policy": _acl_policy()}, + authorization_scope=EnumApplicationDatabaseAclAuthorizationScope.SYNTHETIC_PROOF, + ) + + assert matrix.status == "READY", matrix.blockers + assert matrix.absent_principals == {"application": ("omninode_runtime",)} + rendered = render_application_database_acl_sql( + matrix, + allow_synthetic_proof=True, + phase=EnumApplicationDatabaseAclRenderPhase.SCAFFOLD, + ) + assert 'CREATE ROLE "omninode_runtime" LOGIN' in rendered + + +@pytest.mark.parametrize("unsafe_role", ["app_dashboard", "owner_onex_tenant"]) +def test_unsafe_existing_roles_block_only_additive_scaffold( + unsafe_role: str, +) -> None: + payload = _principal_inventory().model_dump(mode="json") + for state in payload["observed_role_states"]: + if state["role"] == unsafe_role: + state["create_role"] = True + break + inventory = ModelApplicationDatabasePrincipalInventory.model_validate(payload) + + matrix = build_application_database_acl_matrix( + topology=ModelDeploymentTopology.from_yaml(_FIXTURES / "topology.yaml"), + sources=_complete_sources(), + relation_inventories={"inventory": _inventory()}, + service_manifests={}, + principal_inventories={"principal_inventory": inventory}, + acl_policies={"acl_policy": _acl_policy()}, + authorization_scope=( + EnumApplicationDatabaseAclAuthorizationScope.SYNTHETIC_PROOF + ), + ) + + assert matrix.status == "READY", matrix.blockers + assert matrix.scaffold_status == "BLOCKED" + assert any(unsafe_role in blocker for blocker in matrix.scaffold_blockers) + full_sql = render_application_database_acl_sql( + matrix, + allow_synthetic_proof=True, + ) + assert f'ALTER ROLE "{unsafe_role}"' in full_sql + with pytest.raises(ValueError, match="blocked ACL scaffold"): + render_application_database_acl_sql( + matrix, + allow_synthetic_proof=True, + phase=EnumApplicationDatabaseAclRenderPhase.SCAFFOLD, + ) + + +def test_cluster_global_role_presence_cannot_conflict_with_absence_evidence() -> None: + payload = _matrix().model_dump(mode="json") + payload["absent_principals"] = {"application": ["service_only_role"]} + payload["observed_connect_principals"]["omnidash_analytics"].append( + "service_only_role" + ) + + with pytest.raises(ValidationError, match="cluster-global role presence/absence"): + ModelApplicationDatabaseAclMatrix.model_validate(payload) + + +def test_seeded_public_owner_cross_domain_ddl_and_future_grant_controls_fail() -> None: + matrix = _matrix() + rows = list(matrix.rows) + public_database = next( + row + for row in rows + if row.principal == PUBLIC_PRINCIPAL + and row.object_type is EnumDatabaseGrantObjectType.DATABASE + ) + rows[rows.index(public_database)] = public_database.model_copy( + update={"privileges": (EnumDatabasePrivilege.CONNECT,)} + ) + internal_on_tenant = next( + row + for row in rows + if row.principal == "omninode_runtime" and row.object_ref == "delegation_events" + ) + rows[rows.index(internal_on_tenant)] = internal_on_tenant.model_copy( + update={"privileges": (EnumDatabasePrivilege.SELECT,)} + ) + dashboard_schema = next( + row + for row in rows + if row.principal == "app_dashboard" + and row.object_type is EnumDatabaseGrantObjectType.SCHEMA + and row.schema_ref == "tenant" + ) + rows[rows.index(dashboard_schema)] = dashboard_schema.model_copy( + update={ + "privileges": ( + EnumDatabasePrivilege.USAGE, + EnumDatabasePrivilege.CREATE, + ) + } + ) + objects = list(matrix.objects) + objects[0] = objects[0].model_copy(update={"owner": "app_dashboard"}) + defaults = list(matrix.default_privileges) + dashboard_default = next( + row + for row in defaults + if row.grantee == "app_dashboard" + and row.object_type is EnumDatabaseGrantObjectType.TABLE + ) + defaults[defaults.index(dashboard_default)] = dashboard_default.model_copy( + update={"privileges": (EnumDatabasePrivilege.SELECT,)} + ) + red = matrix.model_copy( + update={ + "objects": tuple(objects), + "rows": tuple(rows), + "default_privileges": tuple(defaults), + } + ) + + violations = validate_application_database_acl_matrix(red) + + assert any("PUBLIC has" in violation for violation in violations) + assert any("cross-domain" in violation for violation in violations) + assert any("DDL privilege" in violation for violation in violations) + assert any("owns" in violation for violation in violations) + assert any("broad future" in violation for violation in violations) + + +def test_topology_cross_domain_grant_is_blocked_by_independent_policy() -> None: + topology = ModelDeploymentTopology.from_yaml(_FIXTURES / "topology.yaml") + database = topology.databases["application"] + runtime = database.principals["omninode_runtime"] + dashboard = database.principals["app_dashboard"] + tenant_usage = next( + grant + for grant in dashboard.grants + if grant.object_type is EnumDatabaseGrantObjectType.SCHEMA + and grant.schema == "tenant" + ) + tenant_read = next( + grant + for grant in dashboard.grants + if grant.object_type is EnumDatabaseGrantObjectType.TABLE + and "delegation_events" in grant.objects + ) + principals = dict(database.principals) + principals["omninode_runtime"] = runtime.model_copy( + update={"grants": (*runtime.grants, tenant_usage, tenant_read)} + ) + topology = topology.model_copy( + update={ + "databases": { + "application": database.model_copy(update={"principals": principals}) + } + } + ) + + matrix = build_application_database_acl_matrix( + topology=topology, + sources=_complete_sources(), + relation_inventories={"inventory": _inventory()}, + service_manifests={}, + principal_inventories={"principal_inventory": _principal_inventory()}, + acl_policies={"acl_policy": _acl_policy()}, + authorization_scope=EnumApplicationDatabaseAclAuthorizationScope.SYNTHETIC_PROOF, + ) + + assert matrix.status == "BLOCKED" + assert any("cross-domain" in blocker for blocker in matrix.blockers) + assert any( + "cross-domain" in violation + for violation in validate_application_database_acl_matrix(matrix) + ) + with pytest.raises(ValueError, match="Cannot render blocked ACL matrix"): + render_application_database_acl_sql(matrix) + + +def test_authorized_principal_inventory_requires_full_day_activity() -> None: + principal_inventory = _principal_inventory().model_copy( + update={ + "source_kind": "authorized_catalog", + "live_database_read": True, + "activity_evidence": None, + "catalog_query_sha256": None, + "catalog_result_sha256": None, + } + ) + matrix = build_application_database_acl_matrix( + topology=ModelDeploymentTopology.from_yaml(_FIXTURES / "topology.yaml"), + sources=_complete_sources(), + relation_inventories={"inventory": _inventory()}, + service_manifests={}, + principal_inventories={"principal_inventory": principal_inventory}, + acl_policies={"acl_policy": _acl_policy()}, + authorization_scope=EnumApplicationDatabaseAclAuthorizationScope.DEPLOYMENT, + ) + + assert matrix.status == "BLOCKED" + assert any("full-day" in blocker for blocker in matrix.blockers) + + +def test_incomplete_inventory_blocks_sql_without_fabricating_activity() -> None: + inventory = _inventory().model_copy( + update={"completion_status": "blocked_pending_live_catalog_and_activity"} + ) + matrix = build_application_database_acl_matrix( + topology=ModelDeploymentTopology.from_yaml(_FIXTURES / "topology.yaml"), + sources=_complete_sources(), + relation_inventories={"inventory": inventory}, + service_manifests={}, + principal_inventories={"principal_inventory": _principal_inventory()}, + acl_policies={"acl_policy": _acl_policy()}, + authorization_scope=EnumApplicationDatabaseAclAuthorizationScope.SYNTHETIC_PROOF, + ) + + assert matrix.status == "BLOCKED" + assert any("completion_status" in blocker for blocker in matrix.blockers) + with pytest.raises(ValueError, match="Cannot render blocked ACL matrix"): + render_application_database_acl_sql(matrix) + + +def test_missing_type_count_is_incomplete_not_silently_zero() -> None: + payload = yaml.safe_load((_FIXTURES / "inventory.yaml").read_text(encoding="utf-8")) + del payload["relation_counts"]["type"] + inventory = ModelApplicationRelationEvidenceInventory.model_validate(payload) + matrix = build_application_database_acl_matrix( + topology=ModelDeploymentTopology.from_yaml(_FIXTURES / "topology.yaml"), + sources=_complete_sources(), + relation_inventories={"inventory": inventory}, + service_manifests={}, + principal_inventories={"principal_inventory": _principal_inventory()}, + acl_policies={"acl_policy": _acl_policy()}, + authorization_scope=EnumApplicationDatabaseAclAuthorizationScope.SYNTHETIC_PROOF, + ) + + assert inventory.relation_counts.type is None + assert matrix.status == "BLOCKED" + assert any( + "relation_counts.type is not inventoried" in item for item in matrix.blockers + ) + + +def test_missing_procedure_count_is_incomplete_not_silently_zero() -> None: + payload = yaml.safe_load((_FIXTURES / "inventory.yaml").read_text(encoding="utf-8")) + del payload["relation_counts"]["procedure"] + inventory = ModelApplicationRelationEvidenceInventory.model_validate(payload) + matrix = build_application_database_acl_matrix( + topology=ModelDeploymentTopology.from_yaml(_FIXTURES / "topology.yaml"), + sources=_complete_sources(), + relation_inventories={"inventory": inventory}, + service_manifests={}, + principal_inventories={"principal_inventory": _principal_inventory()}, + acl_policies={"acl_policy": _acl_policy()}, + authorization_scope=EnumApplicationDatabaseAclAuthorizationScope.SYNTHETIC_PROOF, + ) + + assert inventory.relation_counts.procedure is None + assert matrix.status == "BLOCKED" + assert any( + "relation_counts.procedure is not inventoried" in item + for item in matrix.blockers + ) + + +def test_relation_inventory_requires_explicit_ready_retained_census_status() -> None: + payload = yaml.safe_load((_FIXTURES / "inventory.yaml").read_text(encoding="utf-8")) + payload["retained_live_census"]["parity_status"] = None + inventory = ModelApplicationRelationEvidenceInventory.model_validate(payload) + matrix = build_application_database_acl_matrix( + topology=ModelDeploymentTopology.from_yaml(_FIXTURES / "topology.yaml"), + sources=_complete_sources(), + relation_inventories={"inventory": inventory}, + service_manifests={}, + principal_inventories={"principal_inventory": _principal_inventory()}, + acl_policies={"acl_policy": _acl_policy()}, + authorization_scope=( + EnumApplicationDatabaseAclAuthorizationScope.SYNTHETIC_PROOF + ), + ) + + assert matrix.status == "BLOCKED" + assert any("retained_live_census=None" in blocker for blocker in matrix.blockers) + + +def test_ready_relation_inventory_blocks_retained_count_mismatch() -> None: + payload = yaml.safe_load((_FIXTURES / "inventory.yaml").read_text(encoding="utf-8")) + payload["retained_live_census"]["observed_base_tables"] += 1 + inventory = ModelApplicationRelationEvidenceInventory.model_validate(payload) + matrix = build_application_database_acl_matrix( + topology=ModelDeploymentTopology.from_yaml(_FIXTURES / "topology.yaml"), + sources=_complete_sources(), + relation_inventories={"inventory": inventory}, + service_manifests={}, + principal_inventories={"principal_inventory": _principal_inventory()}, + acl_policies={"acl_policy": _acl_policy()}, + authorization_scope=( + EnumApplicationDatabaseAclAuthorizationScope.SYNTHETIC_PROOF + ), + ) + + assert matrix.status == "BLOCKED" + assert any( + "retained_live_census.observed_base_tables=6 " + "does not match exact typed rows=5" in blocker + for blocker in matrix.blockers + ) + + +def test_topology_object_grant_without_typed_ownership_is_a_blocker() -> None: + topology = ModelDeploymentTopology.from_yaml(_FIXTURES / "topology.yaml") + database = topology.databases["application"] + principal = database.principals["app_dashboard"] + grant = principal.grants[-1].model_copy(update={"objects": ("phantom_type",)}) + principals = dict(database.principals) + principals["app_dashboard"] = principal.model_copy( + update={"grants": (*principal.grants, grant)} + ) + topology = topology.model_copy( + update={ + "databases": { + "application": database.model_copy(update={"principals": principals}) + } + } + ) + + matrix = build_application_database_acl_matrix( + topology=topology, + sources=_complete_sources(), + relation_inventories={"inventory": _inventory()}, + service_manifests={}, + principal_inventories={"principal_inventory": _principal_inventory()}, + acl_policies={"acl_policy": _acl_policy()}, + authorization_scope=EnumApplicationDatabaseAclAuthorizationScope.SYNTHETIC_PROOF, + ) + + assert matrix.status == "BLOCKED" + assert any("targets no typed ownership object" in item for item in matrix.blockers) + + +def test_missing_ownership_sources_and_objects_block_sql() -> None: + matrix = build_application_database_acl_matrix( + topology=ModelDeploymentTopology.from_yaml(_FIXTURES / "topology.yaml"), + sources=(_source("topology", "topology"),), + relation_inventories={}, + service_manifests={}, + principal_inventories={}, + acl_policies={}, + authorization_scope=EnumApplicationDatabaseAclAuthorizationScope.SYNTHETIC_PROOF, + ) + + assert matrix.status == "BLOCKED" + assert any("typed ownership evidence source" in item for item in matrix.blockers) + assert any("zero database objects" in item for item in matrix.blockers) + assert any("no typed ownership objects" in item for item in matrix.blockers) + with pytest.raises(ValueError, match="Cannot render blocked ACL matrix"): + render_application_database_acl_sql(matrix) + + +def test_function_without_signature_blocks_even_without_execute_grant() -> None: + topology = ModelDeploymentTopology.from_yaml(_FIXTURES / "topology.yaml") + database = topology.databases["application"] + dashboard = database.principals["app_dashboard"] + principals = dict(database.principals) + principals["app_dashboard"] = dashboard.model_copy( + update={ + "grants": tuple( + grant + for grant in dashboard.grants + if grant.object_type is not EnumDatabaseGrantObjectType.FUNCTION + ) + } + ) + topology = topology.model_copy( + update={ + "databases": { + "application": database.model_copy(update={"principals": principals}) + } + } + ) + inventory = _inventory() + relations = tuple( + relation.model_copy(update={"function_signature": None}) + if relation.kind.value == "function" + else relation + for relation in inventory.relations + ) + matrix = build_application_database_acl_matrix( + topology=topology, + sources=_complete_sources(), + relation_inventories={ + "inventory": inventory.model_copy(update={"relations": relations}) + }, + service_manifests={}, + principal_inventories={"principal_inventory": _principal_inventory()}, + acl_policies={"acl_policy": _acl_policy()}, + authorization_scope=EnumApplicationDatabaseAclAuthorizationScope.SYNTHETIC_PROOF, + ) + + assert matrix.status == "BLOCKED" + assert any( + "require an explicit function_signature" in item for item in matrix.blockers + ) + with pytest.raises(ValueError, match="Cannot render blocked ACL matrix"): + render_application_database_acl_sql(matrix) + + +def test_overloaded_functions_keep_exact_identities_and_block_ambiguous_grant() -> None: + inventory = _inventory() + function = next( + relation + for relation in inventory.relations + if relation.kind.value == "function" + ) + overloaded = function.model_copy(update={"function_signature": "(uuid)"}) + relation_counts = inventory.relation_counts.model_copy(update={"function": 2}) + inventory = inventory.model_copy( + update={ + "relations": (*inventory.relations, overloaded), + "relation_counts": relation_counts, + } + ) + + matrix = build_application_database_acl_matrix( + topology=ModelDeploymentTopology.from_yaml(_FIXTURES / "topology.yaml"), + sources=_complete_sources(), + relation_inventories={"inventory": inventory}, + service_manifests={}, + principal_inventories={"principal_inventory": _principal_inventory()}, + acl_policies={"acl_policy": _acl_policy()}, + authorization_scope=EnumApplicationDatabaseAclAuthorizationScope.SYNTHETIC_PROOF, + ) + + overloads = [ + obj for obj in matrix.objects if obj.object_ref == "delegation_event_count" + ] + assert {obj.function_signature for obj in overloads} == {"()", "(uuid)"} + assert matrix.status == "BLOCKED" + assert any("overload-specific targeting" in item for item in matrix.blockers) + assert not any( + row.privileges + for row in matrix.rows + if row.object_ref == "delegation_event_count" + ) + + +def test_duplicate_exact_authoritative_evidence_is_blocked() -> None: + matrix = build_application_database_acl_matrix( + topology=ModelDeploymentTopology.from_yaml(_FIXTURES / "topology.yaml"), + sources=( + *_complete_sources(), + _source("inventory_duplicate", "relation_inventory"), + ), + relation_inventories={ + "inventory": _inventory(), + "inventory_duplicate": _inventory(), + }, + service_manifests={}, + principal_inventories={"principal_inventory": _principal_inventory()}, + acl_policies={"acl_policy": _acl_policy()}, + authorization_scope=EnumApplicationDatabaseAclAuthorizationScope.SYNTHETIC_PROOF, + ) + + assert matrix.status == "BLOCKED" + assert any( + "duplicate authoritative ownership declaration" in blocker + for blocker in matrix.blockers + ) + + +def test_function_signature_rejects_executable_sql_tokens() -> None: + function = next( + obj + for obj in _matrix().objects + if obj.object_type is EnumDatabaseGrantObjectType.FUNCTION + ) + + with pytest.raises(ValidationError, match="function_signature"): + ModelApplicationDatabaseAclObject.model_validate( + { + **function.model_dump(), + "function_signature": "(); DROP TABLE tenant.delegation_events; --", + } + ) + + +@pytest.mark.parametrize( + ("object_type", "catalog_kind"), + [ + (EnumDatabaseGrantObjectType.TABLE, "function"), + (EnumDatabaseGrantObjectType.FUNCTION, "type"), + (EnumDatabaseGrantObjectType.TYPE, "table"), + ], +) +def test_acl_object_rejects_mismatched_catalog_target_shapes( + object_type: EnumDatabaseGrantObjectType, + catalog_kind: str, +) -> None: + table = next( + obj + for obj in _matrix().objects + if obj.catalog_kind == "table" and obj.function_signature is None + ) + payload = table.model_dump() + payload.update( + { + "object_type": object_type, + "catalog_kind": catalog_kind, + "function_signature": "()" if catalog_kind == "function" else None, + } + ) + + with pytest.raises(ValidationError, match="requires object_type"): + ModelApplicationDatabaseAclObject.model_validate(payload) + + +def test_nonroutine_acl_object_rejects_function_signature() -> None: + table = next(obj for obj in _matrix().objects if obj.catalog_kind == "table") + with pytest.raises(ValidationError, match="only valid"): + ModelApplicationDatabaseAclObject.model_validate( + {**table.model_dump(), "function_signature": "()"} + ) + + +@pytest.mark.parametrize( + "signature", + [ + '(), "other_function"()', + '(uuid), "other_function"()', + '(uuid)) , "other_function"((', + ], +) +def test_function_signature_rejects_target_list_escape(signature: str) -> None: + matrix = _matrix() + function = next( + obj + for obj in matrix.objects + if obj.object_type is EnumDatabaseGrantObjectType.FUNCTION + ) + function_row = next( + row + for row in matrix.rows + if row.object_type is EnumDatabaseGrantObjectType.FUNCTION + ) + + with pytest.raises(ValidationError, match="function_signature"): + ModelApplicationDatabaseAclObject.model_validate( + {**function.model_dump(), "function_signature": signature} + ) + with pytest.raises(ValidationError, match="function_signature"): + ModelApplicationDatabaseAclRow.model_validate( + {**function_row.model_dump(), "function_signature": signature} + ) + + +def test_current_source_schema_cannot_be_rendered_as_materialized_target() -> None: + inventory = _inventory() + relation = inventory.relations[0].model_copy(update={"current_schema": ("public",)}) + matrix = build_application_database_acl_matrix( + topology=ModelDeploymentTopology.from_yaml(_FIXTURES / "topology.yaml"), + sources=_complete_sources(), + relation_inventories={ + "inventory": inventory.model_copy( + update={"relations": (relation, *inventory.relations[1:])} + ) + }, + service_manifests={}, + principal_inventories={"principal_inventory": _principal_inventory()}, + acl_policies={"acl_policy": _acl_policy()}, + authorization_scope=EnumApplicationDatabaseAclAuthorizationScope.SYNTHETIC_PROOF, + ) + + assert matrix.status == "BLOCKED" + assert any( + "full object ACL rendering is gated" in blocker for blocker in matrix.blockers + ) + with pytest.raises(ValueError, match="Cannot render blocked ACL matrix"): + render_application_database_acl_sql(matrix, allow_synthetic_proof=True) + + +def test_additive_source_and_target_schema_coexistence_is_materialized() -> None: + inventory = _inventory() + relation = inventory.relations[0].model_copy( + update={"current_schema": ("public", "tenant")} + ) + matrix = build_application_database_acl_matrix( + topology=ModelDeploymentTopology.from_yaml(_FIXTURES / "topology.yaml"), + sources=_complete_sources(), + relation_inventories={ + "inventory": inventory.model_copy( + update={"relations": (relation, *inventory.relations[1:])} + ) + }, + service_manifests={}, + principal_inventories={"principal_inventory": _principal_inventory()}, + acl_policies={"acl_policy": _acl_policy()}, + authorization_scope=EnumApplicationDatabaseAclAuthorizationScope.SYNTHETIC_PROOF, + ) + + assert matrix.status == "READY" + target = next(obj for obj in matrix.objects if obj.object_ref == relation.name) + assert target.target_materialized + + +def test_full_matrix_rejects_an_object_on_the_wrong_physical_database() -> None: + matrix = _matrix() + objects = list(matrix.objects) + objects[0] = objects[0].model_copy(update={"physical_database": "wrong_database"}) + malformed = matrix.model_copy(update={"objects": tuple(objects)}) + + violations = validate_application_database_acl_scaffold( + malformed, + require_safe_existing_roles=False, + ) + assert any("physical database target disagrees" in item for item in violations) + with pytest.raises(ValueError, match="physical database target disagrees"): + render_application_database_acl_sql( + malformed, + allow_synthetic_proof=True, + ) + + +@pytest.mark.parametrize( + ("field", "value"), + [ + ("source_key", "topology\nDROP_TABLE"), + ("repository", "synthetic/proof\n--"), + ("path", "proof/topology.yaml\n--"), + ], +) +def test_source_metadata_rejects_sql_comment_line_breaks( + field: str, + value: str, +) -> None: + payload = _source("topology", "topology").model_dump() + payload[field] = value + + with pytest.raises(ValidationError): + ModelApplicationDatabaseAclSource.model_validate(payload) + + +def test_synthetic_matrix_requires_explicit_proof_render_authorization() -> None: + with pytest.raises(ValueError, match="explicit allow_synthetic_proof=true"): + render_application_database_acl_sql(_matrix()) + + deployment = build_application_database_acl_matrix( + topology=ModelDeploymentTopology.from_yaml(_FIXTURES / "topology.yaml"), + sources=_complete_sources(), + relation_inventories={"inventory": _inventory()}, + service_manifests={}, + principal_inventories={"principal_inventory": _principal_inventory()}, + acl_policies={"acl_policy": _acl_policy()}, + authorization_scope=EnumApplicationDatabaseAclAuthorizationScope.DEPLOYMENT, + ) + assert deployment.status == "BLOCKED" + assert any("deployment authorization" in item for item in deployment.blockers) + assert any( + "explicit eight-database CONNECT inventory" in item + for item in deployment.blockers + ) + + +def test_deployment_cannot_narrow_connect_scope_to_topology_database() -> None: + matrix = build_application_database_acl_matrix( + topology=ModelDeploymentTopology.from_yaml(_FIXTURES / "topology.yaml"), + sources=_complete_sources(), + relation_inventories={"inventory": _inventory()}, + service_manifests={}, + principal_inventories={"principal_inventory": _principal_inventory()}, + acl_policies={"acl_policy": _acl_policy()}, + authorization_scope=EnumApplicationDatabaseAclAuthorizationScope.DEPLOYMENT, + required_connect_databases=("omnidash_analytics",), + ) + + assert matrix.status == "BLOCKED" + assert any( + "approved eight-database scope" in blocker for blocker in matrix.blockers + ) + with pytest.raises(ValueError, match="Cannot render blocked ACL matrix"): + render_application_database_acl_sql(matrix) + + +def test_authorized_catalog_provenance_requires_durable_complete_day() -> None: + payload = _principal_inventory().model_dump(mode="json") + payload.update( + { + "source_kind": "authorized_catalog", + "live_database_read": True, + "catalog_query_sha256": "1" * 64, + "catalog_result_sha256": "2" * 64, + "catalog_query_source_key": "catalog_query", + "catalog_result_source_key": "catalog_result", + "activity_principal_refs": ["app_dashboard"], + } + ) + started = datetime(2026, 7, 28, tzinfo=UTC) + payload["activity_evidence"] = { + "window_started_at": started.isoformat(), + "window_ended_at": (started + timedelta(hours=23, minutes=59)).isoformat(), + "query_sha256": "3" * 64, + "result_sha256": "4" * 64, + "query_source_key": "activity_query", + "result_source_key": "activity_result", + "observation_count": 1, + } + + with pytest.raises(ValidationError, match="at least 24 hours"): + ModelApplicationDatabasePrincipalInventory.model_validate(payload) + + payload["activity_evidence"]["window_ended_at"] = ( + started + timedelta(hours=24) + ).isoformat() + inventory = ModelApplicationDatabasePrincipalInventory.model_validate(payload) + assert inventory.activity_evidence is not None + + +def test_authorized_catalog_accepts_a_complete_zero_activity_window() -> None: + inventory = _authorized_inventory( + active_principals=(), + observation_count=0, + ) + assert inventory.activity_principal_refs == () + assert inventory.activity_evidence is not None + assert inventory.activity_evidence.observation_count == 0 + + activity = ModelApplicationDatabaseActivityResultEvidence.model_validate( + { + "database_ref": inventory.database_ref, + "physical_database": inventory.physical_database, + "window_started_at": inventory.activity_evidence.window_started_at, + "window_ended_at": inventory.activity_evidence.window_ended_at, + "activity_query_sha256": inventory.activity_evidence.query_sha256, + "observation_count": 0, + "active_principals": [], + } + ) + assert activity.active_principals == () + + +def test_parsed_catalog_and_activity_results_must_semantically_match_inventory() -> ( + None +): + inventory = _authorized_inventory() + assert inventory.activity_evidence is not None + catalog_payload = { + "database_ref": inventory.database_ref, + "physical_database": inventory.physical_database, + "completion_status": inventory.completion_status, + "catalog_parity_status": inventory.catalog_parity_status, + "catalog_query_sha256": inventory.catalog_query_sha256, + "database_owner_role": inventory.database_owner_role, + "principal_refs": inventory.principal_refs, + "absent_principal_refs": inventory.absent_principal_refs, + "owner_refs": inventory.owner_refs, + "absent_owner_refs": inventory.absent_owner_refs, + "observed_role_states": inventory.observed_role_states, + "observed_schema_owners": inventory.observed_schema_owners, + "absent_schema_refs": inventory.absent_schema_refs, + "observed_objects": inventory.observed_objects, + } + activity_payload = { + "database_ref": inventory.database_ref, + "physical_database": inventory.physical_database, + "window_started_at": inventory.activity_evidence.window_started_at, + "window_ended_at": inventory.activity_evidence.window_ended_at, + "activity_query_sha256": inventory.activity_evidence.query_sha256, + "observation_count": 1, + "active_principals": [{"principal": "app_dashboard", "observation_count": 1}], + } + catalog = ModelApplicationDatabaseCatalogResultEvidence.model_validate( + catalog_payload + ) + activity = ModelApplicationDatabaseActivityResultEvidence.model_validate( + activity_payload + ) + assert not validate_application_database_principal_evidence( + inventory, + catalog, + activity, + ) + + catalog_payload["physical_database"] = "wrong_database" + activity_payload["active_principals"] = [ + {"principal": "onex_api", "observation_count": 1} + ] + violations = validate_application_database_principal_evidence( + inventory, + ModelApplicationDatabaseCatalogResultEvidence.model_validate(catalog_payload), + ModelApplicationDatabaseActivityResultEvidence.model_validate(activity_payload), + ) + assert "catalog result physical_database disagrees with inventory" in violations + assert "activity result active principals disagree with inventory" in violations + + +@pytest.mark.parametrize("owner_surface", ["schema", "object"]) +def test_catalog_evidence_rejects_unclassified_present_owners( + owner_surface: str, +) -> None: + payload = _principal_inventory().model_dump(mode="json") + if owner_surface == "schema": + payload["observed_schema_owners"]["tenant"] = "unclassified_owner" + else: + payload["observed_objects"][0]["owner"] = "unclassified_owner" + + with pytest.raises(ValidationError, match="classified in the present role census"): + ModelApplicationDatabasePrincipalInventory.model_validate(payload) + + +def test_deployment_catalog_hashes_require_locked_evidence_blobs() -> None: + payload = _principal_inventory().model_dump(mode="json") + started = datetime(2026, 7, 28, tzinfo=UTC) + payload.update( + { + "source_kind": "authorized_catalog", + "live_database_read": True, + "catalog_query_sha256": "1" * 64, + "catalog_result_sha256": "2" * 64, + "catalog_query_source_key": "catalog_query", + "catalog_result_source_key": "catalog_result", + "activity_principal_refs": ["app_dashboard"], + "activity_evidence": { + "window_started_at": started.isoformat(), + "window_ended_at": (started + timedelta(hours=24)).isoformat(), + "query_sha256": "3" * 64, + "result_sha256": "4" * 64, + "query_source_key": "activity_query", + "result_source_key": "activity_result", + "observation_count": 1, + }, + } + ) + inventory = ModelApplicationDatabasePrincipalInventory.model_validate(payload) + + matrix = build_application_database_acl_matrix( + topology=ModelDeploymentTopology.from_yaml(_FIXTURES / "topology.yaml"), + sources=_complete_sources(), + relation_inventories={"inventory": _inventory()}, + service_manifests={}, + principal_inventories={"principal_inventory": inventory}, + acl_policies={"acl_policy": _acl_policy()}, + authorization_scope=EnumApplicationDatabaseAclAuthorizationScope.DEPLOYMENT, + required_connect_databases=("omnidash_analytics",), + ) + + assert matrix.scaffold_status == "BLOCKED" + assert any( + "evidence source 'catalog_query' is absent from the immutable source lock" + in blocker + for blocker in matrix.scaffold_blockers + ) + + +def test_full_ready_deployment_cannot_bypass_semantic_result_verification() -> None: + payload = _matrix().model_dump(mode="json") + payload.update( + { + "authorization_scope": "deployment", + "scaffold_status": "BLOCKED", + "scaffold_blockers": ["unsafe existing role requires FULL hardening"], + "status": "READY", + "blockers": [], + "sources": [ + *payload["sources"], + _source( + "catalog_result", + "catalog_result_evidence", + ).model_dump(mode="json"), + ], + "verified_evidence_source_keys": [], + } + ) + + with pytest.raises(ValidationError, match="READY deployment phase"): + ModelApplicationDatabaseAclMatrix.model_validate(payload) + + +def test_schema_only_cross_domain_grant_is_blocked() -> None: + topology = ModelDeploymentTopology.from_yaml(_FIXTURES / "topology.yaml") + database = topology.databases["application"] + dashboard = database.principals["app_dashboard"] + internal_schema_usage = next( + grant + for grant in database.principals["omninode_runtime"].grants + if grant.object_type is EnumDatabaseGrantObjectType.SCHEMA + ) + principals = dict(database.principals) + principals["app_dashboard"] = dashboard.model_copy( + update={"grants": (*dashboard.grants, internal_schema_usage)} + ) + topology = topology.model_copy( + update={ + "databases": { + "application": database.model_copy(update={"principals": principals}) + } + } + ) + + matrix = build_application_database_acl_matrix( + topology=topology, + sources=_complete_sources(), + relation_inventories={"inventory": _inventory()}, + service_manifests={}, + principal_inventories={"principal_inventory": _principal_inventory()}, + acl_policies={"acl_policy": _acl_policy()}, + authorization_scope=EnumApplicationDatabaseAclAuthorizationScope.SYNTHETIC_PROOF, + ) + + assert matrix.status == "BLOCKED" + assert any("cross-domain" in item for item in matrix.blockers) + + +def test_runtime_trigger_privilege_is_blocked() -> None: + topology = ModelDeploymentTopology.from_yaml(_FIXTURES / "topology.yaml") + database = topology.databases["application"] + api = database.principals["onex_api"] + tenant_accounts = next( + grant + for grant in api.grants + if grant.object_type is EnumDatabaseGrantObjectType.TABLE + and "tenant_accounts" in grant.objects + ) + trigger = tenant_accounts.model_copy( + update={"privileges": (EnumDatabasePrivilege.TRIGGER,)} + ) + principals = dict(database.principals) + principals["onex_api"] = api.model_copy(update={"grants": (*api.grants, trigger)}) + topology = topology.model_copy( + update={ + "databases": { + "application": database.model_copy(update={"principals": principals}) + } + } + ) + + matrix = build_application_database_acl_matrix( + topology=topology, + sources=_complete_sources(), + relation_inventories={"inventory": _inventory()}, + service_manifests={}, + principal_inventories={"principal_inventory": _principal_inventory()}, + acl_policies={"acl_policy": _acl_policy()}, + authorization_scope=EnumApplicationDatabaseAclAuthorizationScope.SYNTHETIC_PROOF, + ) + + assert matrix.status == "BLOCKED" + assert any("DDL privilege" in item for item in matrix.blockers) + + +def test_service_db_io_table_requires_exact_bidirectional_evidence() -> None: + fixture = ( + Path(__file__).parents[2] + / "fixtures" + / "application_relation_ownership" + / "service-owner.yaml" + ) + payload = yaml.safe_load(fixture.read_text(encoding="utf-8")) + payload.update( + { + "completion_status": "verified", + "retained_live_census": { + "observed_base_tables": 1, + "observed_views_and_materialized_views": 2, + "parity_status": "verified", + }, + "runtime_evidence": { + "full_day_datname_usename_activity": { + "status": "verified", + "reason": "synthetic fixture", + }, + "live_catalog_parity": { + "status": "verified", + "reason": "synthetic fixture", + }, + }, + } + ) + payload["relation_evidence"] = [ + row + for row in payload["relation_evidence"] + if row["name"] != "schema_migrations" + ] + manifest = ModelMigrationOwnershipManifest.model_validate(payload) + + matrix = build_application_database_acl_matrix( + topology=ModelDeploymentTopology.from_yaml(_FIXTURES / "topology.yaml"), + sources=( + *_complete_sources(), + _source("service_ownership", "service_ownership"), + ), + relation_inventories={"inventory": _inventory()}, + service_manifests={"service_ownership": manifest}, + principal_inventories={"principal_inventory": _principal_inventory()}, + acl_policies={"acl_policy": _acl_policy()}, + authorization_scope=EnumApplicationDatabaseAclAuthorizationScope.SYNTHETIC_PROOF, + ) + + assert matrix.status == "BLOCKED" + assert any( + "db_io table application.omninode_internal.schema_migrations lacks exact" + in item + for item in matrix.blockers + ) + assert not any( + "projection_delegation_summary" in item + and "requires exact database_objects" in item + for item in matrix.blockers + ) + + +def test_service_function_relation_requires_signature_capable_object_evidence() -> None: + fixture = ( + Path(__file__).parents[2] + / "fixtures" + / "application_relation_ownership" + / "service-owner.yaml" + ) + payload = yaml.safe_load(fixture.read_text(encoding="utf-8")) + payload.update( + { + "completion_status": "verified", + "materialized_physical_databases": ["omnidash_analytics"], + "retained_live_census": { + "observed_base_tables": 1, + "observed_views_and_materialized_views": 2, + "parity_status": "verified", + }, + "runtime_evidence": { + "full_day_datname_usename_activity": { + "status": "verified", + "reason": "synthetic fixture", + }, + "live_catalog_parity": { + "status": "verified", + "reason": "synthetic fixture", + }, + }, + } + ) + payload["relation_evidence"][1]["kind"] = "function" + manifest = ModelMigrationOwnershipManifest.model_validate(payload) + + matrix = build_application_database_acl_matrix( + topology=ModelDeploymentTopology.from_yaml(_FIXTURES / "topology.yaml"), + sources=( + *_complete_sources(), + _source("service_ownership", "service_ownership"), + ), + relation_inventories={"inventory": _inventory()}, + service_manifests={"service_ownership": manifest}, + principal_inventories={"principal_inventory": _principal_inventory()}, + acl_policies={"acl_policy": _acl_policy()}, + authorization_scope=EnumApplicationDatabaseAclAuthorizationScope.SYNTHETIC_PROOF, + ) + + assert matrix.status == "BLOCKED" + assert any( + "function relation_evidence 'projection_delegation_summary' requires exact " + "database_objects evidence" in blocker + for blocker in matrix.blockers + ) + + +def test_service_inventory_requires_explicit_ready_retained_census_status() -> None: + fixture = ( + Path(__file__).parents[2] + / "fixtures" + / "application_relation_ownership" + / "service-owner.yaml" + ) + payload = yaml.safe_load(fixture.read_text(encoding="utf-8")) + payload.update( + { + "completion_status": "verified", + "retained_live_census": { + "observed_base_tables": 1, + "observed_views_and_materialized_views": 2, + "observed_sequences": 0, + "observed_functions": 0, + "observed_procedures": 0, + "observed_types": 0, + "observed_extensions": 0, + "parity_status": None, + }, + "runtime_evidence": { + "full_day_datname_usename_activity": { + "status": "verified", + "reason": "synthetic fixture", + }, + "live_catalog_parity": { + "status": "verified", + "reason": "synthetic fixture", + }, + }, + } + ) + manifest = ModelMigrationOwnershipManifest.model_validate(payload) + matrix = build_application_database_acl_matrix( + topology=ModelDeploymentTopology.from_yaml(_FIXTURES / "topology.yaml"), + sources=( + *_complete_sources(), + _source("service_ownership", "service_ownership"), + ), + relation_inventories={"inventory": _inventory()}, + service_manifests={"service_ownership": manifest}, + principal_inventories={"principal_inventory": _principal_inventory()}, + acl_policies={"acl_policy": _acl_policy()}, + authorization_scope=( + EnumApplicationDatabaseAclAuthorizationScope.SYNTHETIC_PROOF + ), + ) + + assert matrix.status == "BLOCKED" + assert any( + "service_ownership: retained_live_census=None" in blocker + for blocker in matrix.blockers + )