infrasynth-backend-kit/infrasynth/configs/signals.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

23 lines
888 B
Python

"""Public signals of ``infrasynth.configs``.
Both signals are a documented extension point: a consuming app connects them in
``apps.py:ready()`` to react to configuration changes (for example, to refresh a
third-party client). They are emitted from :class:`ConfigService` itself, so
correctness never depends on a receiver being connected, and every signal carries
``tenant_id`` explicitly (``TENANCY.md`` §7).
Secret values are **always masked**: ``old_value``/``new_value`` are ``None``
when the definition is secret, so no plaintext or ciphertext ever appears in a
signal payload.
"""
from django.dispatch import Signal
__all__ = ["config_changed", "config_reset"]
# kwargs: tenant_id (str|None), key, scope ("tenant"|"global"),
# old_value, new_value, actor_id
config_changed = Signal()
# kwargs: tenant_id, key, scope, previous_value, actor_id
config_reset = Signal()