infrasynth-backend-kit/infrasynth/security/__init__.py
jcv-dev a2930426b4 feat: tenant configs, live signals, and automatic permission management
- 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)
2026-09-29 17:06:54 -05:00

77 lines
2.6 KiB
Python

"""Public surface of ``infrasynth.security``.
The exports are resolved lazily (PEP 562) so importing this package never
triggers Django model imports before the app registry is ready. Import from
here::
from infrasynth.security import AuthorizationService, HybridPermission, CookieJWTAuthentication
"""
from __future__ import annotations
from importlib import import_module
from typing import Any
__all__ = [
"ALTCHAService",
"APIKeyAuthentication",
"AuthorizationService",
"AutoPermission",
"CookieJWTAuthentication",
"EmailOrUsernameBackend",
"HybridPermission",
"InfraSynthModelViewSet",
"InfraSynthReadOnlyModelViewSet",
"IsAuthenticatedAndPermitted",
"LoginAttemptGuard",
"PasswordPolicyValidator",
"Permission",
"PermissionRegistry",
"RecoveryCodeService",
"RoleAssignment",
"SystemUser",
"TOTPService",
"get_recovery_code_service",
"get_two_factor_service",
"is_tenant_owner",
]
# public name -> module (relative to the ``infrasynth`` package) that defines it
_EXPORTS: dict[str, str] = {
"ALTCHAService": "security.altcha.services",
"APIKeyAuthentication": "security.auth.api_keys",
"AuthorizationService": "security.services",
"AutoPermission": "security.permissions",
"CookieJWTAuthentication": "security.auth.cookies",
"EmailOrUsernameBackend": "security.auth.backends",
"HybridPermission": "security.permissions",
"InfraSynthModelViewSet": "security.viewsets",
"InfraSynthReadOnlyModelViewSet": "security.viewsets",
"IsAuthenticatedAndPermitted": "security.permissions",
"LoginAttemptGuard": "security.throttling",
"PasswordPolicyValidator": "security.password_validation",
"Permission": "security.models",
"PermissionRegistry": "security.registry",
"RecoveryCodeService": "security.two_factor.services",
"RoleAssignment": "security.models",
"SystemUser": "security.auth.api_keys",
"TOTPService": "security.two_factor.services",
"get_recovery_code_service": "security.two_factor.services",
"get_two_factor_service": "security.two_factor.services",
"is_tenant_owner": "security.permissions",
}
def __getattr__(name: str) -> Any:
module_path = _EXPORTS.get(name)
if module_path is not None:
return getattr(import_module(f"infrasynth.{module_path}"), name)
# Let ``infrasynth.<app>.<submodule>`` resolve as usual.
try:
return import_module(f"{__name__}.{name}")
except ModuleNotFoundError as exc:
raise AttributeError(f"module {__name__!r} has no attribute {name!r}") from exc
def __dir__() -> list[str]:
return sorted(set(__all__) | set(globals()))