infrasynth-backend-kit/CHANGELOG.md
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

8.1 KiB

Changelog

All notable changes to infrasynth-base are documented here.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning. Versions are derived from Conventional Commits by python-semantic-release; do not hand-pick a version (see ../AGENTS.backend-packages.md §8).

[Unreleased]

Added

  • Automatic permission management. Every concrete model contributes Django-style view/add/change/delete codenames ({app}.{verb}_{model}) to a kit-owned permission catalog (security.Permission), and infrasynth.security.permissions.AutoPermission derives and enforces the right codename per DRF action with no per-view configuration. Consumers register custom codenames in their own code via PermissionRegistry, kit model viewsets enforce automatically, and manage.py sync_permissions + post_migrate keep the catalog in sync. INFRASYNTH_SECURITY["AUTO_PERMISSIONS"] selects global (default) / opt_in / off. New GET /api/v1/auth/permissions/ catalog endpoint for assignment UIs.
  • Multiple roles per user per tenant. security.RoleAssignment (tenant-scoped) complements the global Role.users M2M; AuthorizationService resolves both. Global roles (tenant IS NULL) require platform.roles.manage to create/edit; tenant roles remain under security.manage_roles.
  • Global grants/revokes. Grant/Revoke are now global-or-tenant: a normal write is tenant-scoped, {"scope": "global"} (requires platform.roles.manage) creates a platform-wide override that applies in every tenant.
  • Built-in custom permissions for the kit (security.*, audit.*, configs.*, tenancy.*, and the platform.* cross-tenant set).
  • infrasynth.configs — typed, multi-tenant configuration store. New app (configs feature flag) with a code/settings registry (ConfigRegistry/INFRASYNTH_CONFIGS["DEFINITIONS"]), typed coercion (string/int/float/bool/decimal/json/choice/duration), precedence tenant override → global default → registry default, per-tenant caching, and Fernet-encrypted secrets that are masked in the API/signals/audit. API under /api/v1/configs/ (GET values/definitions, PUT/DELETE override, PUT .../global/<key>/), gated by configs.manage/configs.manage_global. Public signals config_changed/config_reset.
  • Emitted signals that were previously declared but never fired. features.flag_created/flag_toggled/flag_deleted and override_created/override_deleted now fire from the flag viewsets (and flag mutations bust the feature cache); scheduler.task_completed/task_failed fire exactly once on terminal TaskExecution transitions (new scheduler/receivers.py); tenancy.tenant_updated fires from the tenant edit path (TenantService.update_tenant); audit.model_changed fires alongside each ModelChangeLog row.
  • INFRASYNTH_AUDIT["EXCLUDED_MODEL_FIELDS"] — per-model excluded fields so ConfigValue is audited without ever logging its (possibly encrypted) value.
  • Uniform extensibility across every module. Storage backends can be registered (register_storage_backend or STORAGE_BACKENDS[name]["CLASS"]), pipeline steps via PipelineStepRegistry/@pipeline_step, the pipeline executor via PIPELINE_EXECUTOR, the invoice PDF via INVOICE_PDF_BUILDER, and the 2FA method via TWO_FACTOR_SERVICE/TWO_FACTOR_RECOVERY_SERVICE — all through settings/registries, with no kit edits. The other modules already resolved extensions through dotted paths (gateways, channels, tasks, inbound handlers, scanner) and are now documented as such.
  • Lazy public API per app package. from infrasynth.security import AuthorizationService, from infrasynth.billing import EntitlementService, etc. resolve via PEP 562 without importing models before the app registry is ready; infrasynth.shared re-exports its primitives eagerly.
  • Composable per-endpoint gates (infrasynth.gates): declare infrasynth_gates = [...] (and/or @gated(...) on a viewset action) with TwoFactorGate, AltchaGate, EntitlementGate, FeatureGate, PermissionGate, or a custom Gate. Access is evaluated per endpoint, the default is "gate nothing", and denials raise the correct namespaced error (AUTH_2FA_REQUIRED, ENTITLEMENT_PLAN_UPGRADE_REQUIRED, VALIDATION_ALTCHA_REQUIRED, …). GatePermission is a default permission class and the kit's HybridPermission evaluates declared gates too.
  • 2fa JWT claim minted only after successful verification and preserved across workspace selection, so TwoFactorGate works for multi-workspace users.
  • Verified inbound webhooks. InboundReceiveView now enforces the shared HMAC signature (or a provider-specific BaseInboundHandler.verify), payload size limits, timestamp tolerance, and idempotent re-delivery via InboundEvent.external_id; verified events are dispatched to the endpoint's handler through process_inbound_event and marked is_verified/is_processed.
  • Working 2FA login flow. Login now challenges users with a configured second factor (pre-auth session + cookie) and only mints JWT cookies after 2fa/verify/ (or 2fa/recovery/) succeeds; TwoFactorMiddleware guards the session-authenticated surface.
  • Permission enforcement. HybridPermission (any-of required_permissions, or all-of with require_all) is now wired into security and audit viewsets with documented codenames and a tenant-owner bypass; HybridPermission takes tenant ownership into account.
  • API-key rotation (/api/v1/auth/api-keys/<id>/rotate/) and user permission/role endpoints (/api/v1/auth/users/<id>/permissions/, /users/<id>/roles/).
  • Billing webhook processing. Verified events are applied idempotently to subscriptions, entitlements, invoices, and PaymentTransaction rows; replay protection via assert_fresh_webhook.
  • Scheduled billing lifecycle (sync_subscriptions, advance_entitlement_lifecycle, expire_entitlements, generate_renewal_invoices) and notification retries + log retention, all wired into CELERY_BEAT_SCHEDULE.
  • Audit update diffs are captured automatically via a pre_save snapshot; audit retention purge task added.
  • Feature rollout (rollout_percentage, environments, ROLLOUT_HASH_ALGORITHM) and settings-driven flag registration.
  • Login brute-force guard (per-credential rate limit + IP blacklist), configurable password policy (PasswordPolicyValidator), and a correctly enforced ALTCHA proof-of-work.
  • File hardening: global upload-size limit, processing-pipeline toggle, and a pluggable virus scanner (noop/clamav/custom) with REQUIRE_VIRUS_SCAN.
  • Workflow guards: MAX_INSTANCES_PER_WORKFLOW, ROUTE_MAX_DEPTH, ALLOW_SELF_ASSIGNMENT, AUTO_CLONE_ASSIGNEES_ON_REENTRY.
  • MercadoPago webhook signature verification.
  • README.md, CHANGELOG.md, and a CI format/coverage gate.

Changed

  • Permission surface consolidated. IsAuthenticatedAndPermitted is now an alias of HybridPermission (it was a no-op subclass), and the require_permission(...) class factory was removed: use required_permissions (any-of) plus require_all = True on the view for all-of. Custom permissions are declared only through PermissionRegistry (the INFRASYNTH_SECURITY["CUSTOM_PERMISSIONS"] settings path was dropped).
  • TenantRateThrottle and RateLimitHeadersMiddleware are active by default, producing X-RateLimit-* headers on API responses.
  • EntitlementService treats past_due as within grace (entitled) and merges entitlement-level feature overrides over plan.features; require_limit raises ENTITLEMENT_LIMIT_REACHED.
  • FeatureService resolves the current tenant automatically and honors rollout and environment targeting.

Fixed

  • API-key authentication no longer leaks tenant context.
  • EventRegistry.emit no longer uses __import__ and honors DELIVERY_BACKEND.
  • Test media artifacts no longer accumulate in the repository tree.