- 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)
8.1 KiB
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/deletecodenames ({app}.{verb}_{model}) to a kit-owned permission catalog (security.Permission), andinfrasynth.security.permissions.AutoPermissionderives and enforces the right codename per DRF action with no per-view configuration. Consumers register custom codenames in their own code viaPermissionRegistry, kit model viewsets enforce automatically, andmanage.py sync_permissions+post_migratekeep the catalog in sync.INFRASYNTH_SECURITY["AUTO_PERMISSIONS"]selectsglobal(default) /opt_in/off. NewGET /api/v1/auth/permissions/catalog endpoint for assignment UIs. - Multiple roles per user per tenant.
security.RoleAssignment(tenant-scoped) complements the globalRole.usersM2M;AuthorizationServiceresolves both. Global roles (tenant IS NULL) requireplatform.roles.manageto create/edit; tenant roles remain undersecurity.manage_roles. - Global grants/revokes.
Grant/Revokeare now global-or-tenant: a normal write is tenant-scoped,{"scope": "global"}(requiresplatform.roles.manage) creates a platform-wide override that applies in every tenant. - Built-in custom permissions for the kit (
security.*,audit.*,configs.*,tenancy.*, and theplatform.*cross-tenant set). infrasynth.configs— typed, multi-tenant configuration store. New app (configsfeature 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/(GETvalues/definitions,PUT/DELETEoverride,PUT .../global/<key>/), gated byconfigs.manage/configs.manage_global. Public signalsconfig_changed/config_reset.- Emitted signals that were previously declared but never fired.
features.flag_created/flag_toggled/flag_deletedandoverride_created/override_deletednow fire from the flag viewsets (and flag mutations bust the feature cache);scheduler.task_completed/task_failedfire exactly once on terminalTaskExecutiontransitions (newscheduler/receivers.py);tenancy.tenant_updatedfires from the tenant edit path (TenantService.update_tenant);audit.model_changedfires alongside eachModelChangeLogrow. INFRASYNTH_AUDIT["EXCLUDED_MODEL_FIELDS"]— per-model excluded fields soConfigValueis audited without ever logging its (possibly encrypted) value.- Uniform extensibility across every module. Storage backends can be
registered (
register_storage_backendorSTORAGE_BACKENDS[name]["CLASS"]), pipeline steps viaPipelineStepRegistry/@pipeline_step, the pipeline executor viaPIPELINE_EXECUTOR, the invoice PDF viaINVOICE_PDF_BUILDER, and the 2FA method viaTWO_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.sharedre-exports its primitives eagerly. - Composable per-endpoint gates (
infrasynth.gates): declareinfrasynth_gates = [...](and/or@gated(...)on a viewset action) withTwoFactorGate,AltchaGate,EntitlementGate,FeatureGate,PermissionGate, or a customGate. 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, …).GatePermissionis a default permission class and the kit'sHybridPermissionevaluates declared gates too. 2faJWT claim minted only after successful verification and preserved across workspace selection, soTwoFactorGateworks for multi-workspace users.- Verified inbound webhooks.
InboundReceiveViewnow enforces the shared HMAC signature (or a provider-specificBaseInboundHandler.verify), payload size limits, timestamp tolerance, and idempotent re-delivery viaInboundEvent.external_id; verified events are dispatched to the endpoint's handler throughprocess_inbound_eventand markedis_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/(or2fa/recovery/) succeeds;TwoFactorMiddlewareguards the session-authenticated surface. - Permission enforcement.
HybridPermission(any-ofrequired_permissions, or all-of withrequire_all) is now wired into security and audit viewsets with documented codenames and a tenant-owner bypass;HybridPermissiontakes 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
PaymentTransactionrows; replay protection viaassert_fresh_webhook. - Scheduled billing lifecycle (
sync_subscriptions,advance_entitlement_lifecycle,expire_entitlements,generate_renewal_invoices) and notification retries + log retention, all wired intoCELERY_BEAT_SCHEDULE. - Audit update diffs are captured automatically via a
pre_savesnapshot; 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) withREQUIRE_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.
IsAuthenticatedAndPermittedis now an alias ofHybridPermission(it was a no-op subclass), and therequire_permission(...)class factory was removed: userequired_permissions(any-of) plusrequire_all = Trueon the view for all-of. Custom permissions are declared only throughPermissionRegistry(theINFRASYNTH_SECURITY["CUSTOM_PERMISSIONS"]settings path was dropped). TenantRateThrottleandRateLimitHeadersMiddlewareare active by default, producingX-RateLimit-*headers on API responses.EntitlementServicetreatspast_dueas within grace (entitled) and merges entitlement-level feature overrides overplan.features;require_limitraisesENTITLEMENT_LIMIT_REACHED.FeatureServiceresolves the current tenant automatically and honors rollout and environment targeting.
Fixed
- API-key authentication no longer leaks tenant context.
EventRegistry.emitno longer uses__import__and honorsDELIVERY_BACKEND.- Test media artifacts no longer accumulate in the repository tree.