# Changelog All notable changes to `infrasynth-base` are documented here. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 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//`), 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//rotate/`) and **user permission/role endpoints** (`/api/v1/auth/users//permissions/`, `/users//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.