- infrasynth.configs: typed multi-tenant config store (registry, service, secrets, cache) + public config_changed/config_reset signals and API - emit the declared-but-dead signals (features flags/overrides, scheduler task_completed/task_failed, tenancy tenant_updated, audit model_changed) and per-model audit field exclusions - security: permission catalog (security_permission), Django-style model-derived AutoPermission, PermissionRegistry, RoleAssignment, global-or-tenant Grant/Revoke, catalog API - consolidate the permission surface: PermissionRegistry only (drop the settings dict), IsAuthenticatedAndPermitted aliases HybridPermission, require_permission replaced by required_permissions + require_all - packaging: add [build-system]; add Forgejo publish workflow (.forgejo)
77 lines
3.9 KiB
Python
77 lines
3.9 KiB
Python
import logging
|
|
|
|
from django.apps import AppConfig
|
|
from django.db.models.signals import post_migrate
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# Explicit (non model-derived) codenames the kit enforces or documents.
|
|
_KIT_PERMISSIONS: list[tuple[str, str, str, str]] = [
|
|
# (codename, name, group, description)
|
|
("security.manage_api_keys", "Manage API keys", "Security", "Create/rotate/delete tenant API keys."),
|
|
("security.manage_roles", "Manage roles", "Security", "Create and assign tenant roles."),
|
|
("security.manage_grants", "Manage grants", "Security", "Grant/revoke permissions directly."),
|
|
("security.view_permissions", "View permissions", "Security", "Read the permission catalog."),
|
|
("platform.roles.manage", "Manage platform roles", "Platform", "Create and assign global roles."),
|
|
("platform.tenants.view", "View any tenant", "Platform", "Read tenants across the platform."),
|
|
("platform.tenants.manage", "Manage tenants", "Platform", "Edit tenant metadata across the platform."),
|
|
("platform.tenants.suspend", "Suspend tenants", "Platform", "Suspend a tenant."),
|
|
("platform.tenants.reinstate", "Reinstate tenants", "Platform", "Reinstate a suspended tenant."),
|
|
("platform.tenants.delete", "Delete tenants", "Platform", "Archive/delete a tenant."),
|
|
("platform.tenants.impersonate", "Impersonate tenants", "Platform", "Open a support session into a tenant."),
|
|
("platform.users.view_any", "View any user", "Platform", "Read users/members across tenants."),
|
|
("platform.users.manage_email", "Change any user email", "Platform", "Update a user's email across tenants."),
|
|
("platform.users.deactivate", "Deactivate any user", "Platform", "Disable accounts across tenants."),
|
|
("platform.users.manage_roles", "Assign roles anywhere", "Platform", "Assign roles in any tenant."),
|
|
("platform.audit.view_all", "View all audit", "Platform", "Read audit records across tenants."),
|
|
("audit.view_model_changes", "View model changes", "Audit", "Read the model change log."),
|
|
("audit.view_api_logs", "View API logs", "Audit", "Read API interaction logs."),
|
|
("audit.view_security_events", "View security events", "Audit", "Read security events."),
|
|
("tenancy.manage_tenant", "Manage tenant", "Tenancy", "Edit the current tenant."),
|
|
("tenancy.manage_members", "Manage members", "Tenancy", "Invite/remove tenant members."),
|
|
("configs.manage", "Manage configuration", "Configs", "Write tenant configuration values."),
|
|
("configs.manage_global", "Manage global configuration", "Configs", "Write platform configuration defaults."),
|
|
]
|
|
|
|
|
|
def register_builtin_permissions() -> None:
|
|
from .registry import PermissionRegistry
|
|
|
|
for codename, name, group, description in _KIT_PERMISSIONS:
|
|
PermissionRegistry.register(codename, name=name, group=group, description=description)
|
|
|
|
|
|
def _sync_permissions_on_migrate(sender, **kwargs) -> None:
|
|
from .catalog import sync_permissions
|
|
|
|
try:
|
|
summary = sync_permissions()
|
|
except Exception: # noqa: BLE001 - migrate must never fail because of the catalog
|
|
logger.exception("Permission catalog sync failed during post_migrate")
|
|
return
|
|
logger.info("Permission catalog synced: %s", summary)
|
|
|
|
|
|
class SecurityConfig(AppConfig):
|
|
default_auto_field = "django.db.models.BigAutoField"
|
|
name = "infrasynth.security"
|
|
label = "infrasynth_security"
|
|
|
|
def ready(self):
|
|
from infrasynth.features.registry import FeatureRegistry
|
|
|
|
register_builtin_permissions()
|
|
|
|
FeatureRegistry.register(
|
|
"security",
|
|
name="Security & Access",
|
|
description="Authentication, authorization, 2FA, API keys, ALTCHA",
|
|
default=True,
|
|
category="system",
|
|
)
|
|
|
|
post_migrate.connect(
|
|
_sync_permissions_on_migrate,
|
|
sender=self,
|
|
dispatch_uid="infrasynth_security.sync_permissions",
|
|
)
|