generated from erangel1/generic-template
53 lines
1.8 KiB
Python
53 lines
1.8 KiB
Python
"""
|
|
Core app configuration.
|
|
|
|
Connects a post_migrate signal to enable PostgreSQL Row-Level Security
|
|
on the core_node table. The policy is permissive for now (allow all);
|
|
Phase 2+ can tighten it for multi-user support.
|
|
"""
|
|
|
|
import logging
|
|
|
|
from django.apps import AppConfig
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class CoreConfig(AppConfig):
|
|
name = "apps.core"
|
|
verbose_name = "Infrastructure Core"
|
|
default_auto_field = "django.db.models.BigAutoField"
|
|
|
|
def ready(self) -> None:
|
|
from django.db.models.signals import post_migrate
|
|
|
|
post_migrate.connect(_enable_node_rls, sender=self)
|
|
|
|
|
|
def _enable_node_rls(sender: AppConfig, **kwargs: object) -> None:
|
|
"""Enable PostgreSQL RLS on the node table after migrations complete."""
|
|
from django.db import connection
|
|
from django.db.utils import OperationalError, ProgrammingError
|
|
|
|
try:
|
|
with connection.cursor() as cursor:
|
|
# Bail out early if core_node doesn't exist yet (fires before core migrations)
|
|
cursor.execute(
|
|
"SELECT EXISTS ("
|
|
" SELECT 1 FROM information_schema.tables WHERE table_name = 'core_node'"
|
|
");"
|
|
)
|
|
row = cursor.fetchone()
|
|
if row is None or not row[0]:
|
|
return
|
|
cursor.execute("ALTER TABLE core_node ENABLE ROW LEVEL SECURITY;")
|
|
cursor.execute(
|
|
"DO $$ BEGIN "
|
|
" IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE tablename = 'core_node' AND policyname = 'allow_all_for_now') THEN "
|
|
" CREATE POLICY allow_all_for_now ON core_node USING (true) WITH CHECK (true); "
|
|
" END IF; "
|
|
"END $$;"
|
|
)
|
|
except (OperationalError, ProgrammingError):
|
|
logger.debug("core_node table not yet available for RLS setup; will apply on next migrate.")
|