domainkit 0.6.1__tar.gz → 0.6.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {domainkit-0.6.1 → domainkit-0.6.2}/PKG-INFO +1 -1
- {domainkit-0.6.1 → domainkit-0.6.2}/pyproject.toml +1 -1
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/auth/__init__.py +2 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/auth/access.py +82 -22
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/auth/apps.py +6 -2
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/auth/middleware.py +18 -11
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/auth/repositories.py +10 -5
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/idempotency/middleware.py +4 -4
- {domainkit-0.6.1 → domainkit-0.6.2}/LICENSE +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/README.md +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/__init__.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/apps/__init__.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/apps/config.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/apps/registry.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/architecture.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/broker/__init__.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/broker/base.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/broker/handler.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/broker/memory.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/broker/rabbitmq.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/cache/__init__.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/cache/base.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/cache/core.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/cache/decorators.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/cache/handler.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/cache/memory.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/cache/metrics.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/cache/redis.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/conf/__init__.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/conf/env.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/conf/global_settings.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/conf/lazy.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/context.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/__init__.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/audit/__init__.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/audit/apps.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/audit/management/__init__.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/audit/management/commands/__init__.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/audit/management/commands/auditforget.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/audit/management/commands/auditlog.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/audit/management/commands/auditseal.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/audit/management/commands/auditverify.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/audit/personal.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/audit/protection.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/audit/recorder.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/audit/seals.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/audit/settings.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/audit/tables.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/audit/tasks.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/auth/admin.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/auth/api.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/auth/authentication.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/auth/backends.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/auth/common-passwords.NOTICE +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/auth/common-passwords.txt.gz +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/auth/events.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/auth/exceptions.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/auth/hashers.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/auth/management/__init__.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/auth/management/commands/__init__.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/auth/management/commands/changepassword.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/auth/management/commands/cleartokens.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/auth/management/commands/createsuperuser.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/auth/management/commands/createtoken.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/auth/models.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/auth/permissions.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/auth/settings.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/auth/tables.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/auth/tasks.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/auth/tokens.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/auth/uow.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/auth/users.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/auth/validators.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/contenttypes/__init__.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/contenttypes/apps.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/contenttypes/models.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/contenttypes/registry.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/contenttypes/sync.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/contenttypes/tables.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/evidence/__init__.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/evidence/apps.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/evidence/management/__init__.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/evidence/management/commands/__init__.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/evidence/management/commands/evidence.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/evidence/model.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/evidence/settings.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/evidence/store.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/evidence/tasks.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/idempotency/__init__.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/idempotency/apps.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/idempotency/operations.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/idempotency/settings.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/idempotency/tables.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/idempotency/tasks.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/messaging/__init__.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/messaging/admin.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/messaging/apps.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/messaging/dispatch.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/messaging/management/__init__.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/messaging/management/commands/__init__.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/messaging/management/commands/messages.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/messaging/management/commands/runworker.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/messaging/metrics.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/messaging/outbox.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/messaging/registry.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/messaging/settings.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/messaging/tables.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/messaging/worker.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/db/__init__.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/db/connections.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/db/drivers.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/db/errors.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/db/migration_env/__init__.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/db/migration_env/env.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/db/migration_env/script.py.mako +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/db/migrations.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/db/orm.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/db/partitioning.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/db/repository.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/db/routing.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/db/snapshots.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/db/types.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/db/uow.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/ddd/__init__.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/ddd/_dataclass.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/ddd/events.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/ddd/exceptions.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/ddd/messages.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/ddd/model.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/ddd/pagination.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/ddd/personal.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/ddd/repository.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/ddd/uow.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/deprecation.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/exceptions.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/http/__init__.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/http/application.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/http/errors.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/http/health.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/http/metrics.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/http/middleware.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/http/pagination.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/http/ratelimit.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/ledger/__init__.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/ledger/base.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/ledger/handler.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/ledger/immudb.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/ledger/memory.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/lifecycle.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/log.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/__init__.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/base.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/commands/__init__.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/commands/broker.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/commands/cache.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/commands/check.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/commands/init.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/commands/makemigrations.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/commands/migrate.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/commands/partitions.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/commands/runserver.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/commands/shell.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/commands/showmigrations.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/commands/startdomain.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/domain/package/__init__.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/domain/package/api/__init__.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/domain/package/api/dependencies.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/domain/package/api/routes.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/domain/package/api/schemas.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/domain/package/application/__init__.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/domain/package/application/commands.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/domain/package/application/handlers.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/domain/package/application/services.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/domain/package/application/unit_of_work.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/domain/package/apps.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/domain/package/domain/__init__.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/domain/package/domain/events.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/domain/package/domain/exceptions.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/domain/package/domain/model.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/domain/package/domain/repositories.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/domain/package/infrastructure/__init__.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/domain/package/infrastructure/orm.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/domain/package/infrastructure/repositories.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/domain/package/infrastructure/unit_of_work.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/domain/package/management/__init__.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/domain/package/management/commands/__init__.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/domain/package/management/commands/{{ aggregates }}.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/domain/package/settings.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/domain/tests/__init__.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/domain/tests/fakes.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/domain/tests/test_api.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/domain/tests/test_model.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/domain/tests/test_services.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/domain/tests/test_settings.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/project/dot-env-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/project/dot-gitignore-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/project/manage.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/project/pyproject.toml-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/project/src/config/__init__.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/project/src/config/asgi.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/project/src/config/settings/__init__.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/project/src/config/settings/base.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/project/src/config/settings/local.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/project/src/config/settings/production.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/project/src/config/settings/test.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/project/src/config/urls.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/project/src/domains/__init__.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/project/tests/__init__.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/management/templates/project/tests/test_health.py-tpl +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/py.typed +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/reporting.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/testing.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/tracing.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/utils/__init__.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/utils/closing.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/utils/formatting.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/utils/module_loading.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/utils/rates.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/utils/readiness.py +0 -0
- {domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/utils/text.py +0 -0
|
@@ -46,6 +46,7 @@ from .access import (
|
|
|
46
46
|
Require,
|
|
47
47
|
check_object_permissions,
|
|
48
48
|
current_user,
|
|
49
|
+
mark_public,
|
|
49
50
|
open_routes,
|
|
50
51
|
)
|
|
51
52
|
from .authentication import (
|
|
@@ -165,6 +166,7 @@ __all__ = [
|
|
|
165
166
|
"has_perm",
|
|
166
167
|
"has_perms",
|
|
167
168
|
"make_password",
|
|
169
|
+
"mark_public",
|
|
168
170
|
"open_routes",
|
|
169
171
|
"password_help_texts",
|
|
170
172
|
"validate_password",
|
|
@@ -25,7 +25,7 @@ A refused anonymous caller gets 401, so it knows to log in; a refused user
|
|
|
25
25
|
gets 403. ``AuthenticationMiddleware`` must be installed.
|
|
26
26
|
"""
|
|
27
27
|
|
|
28
|
-
from collections.abc import Sequence
|
|
28
|
+
from collections.abc import Iterator, Sequence
|
|
29
29
|
from typing import Annotated, Any, ClassVar, Final, cast
|
|
30
30
|
|
|
31
31
|
from fastapi import Depends, FastAPI, Request, status
|
|
@@ -33,6 +33,7 @@ from fastapi.dependencies.models import Dependant
|
|
|
33
33
|
from fastapi.routing import APIRoute, APIWebSocketRoute, iter_route_contexts
|
|
34
34
|
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
|
|
35
35
|
from starlette.requests import HTTPConnection
|
|
36
|
+
from starlette.routing import BaseRoute, Host, Mount, Route, WebSocketRoute
|
|
36
37
|
|
|
37
38
|
from domainkit.ddd import PermissionDenied
|
|
38
39
|
from domainkit.exceptions import ImproperlyConfigured
|
|
@@ -43,8 +44,10 @@ from .backends import has_perms
|
|
|
43
44
|
from .models import AbstractBaseUser, AnyUser
|
|
44
45
|
|
|
45
46
|
SAFE_METHODS: Final = frozenset({"GET", "HEAD", "OPTIONS"})
|
|
46
|
-
FRAMEWORK_ROUTES: Final = "domainkit.http."
|
|
47
|
-
"""Modules whose routes (probes, metrics)
|
|
47
|
+
FRAMEWORK_ROUTES: Final = ("domainkit.http.", "fastapi.")
|
|
48
|
+
"""Modules whose routes guard themselves (probes, metrics, ``API_DOCS``)."""
|
|
49
|
+
PUBLIC_MARK: Final = "domainkit_public"
|
|
50
|
+
"""The attribute ``mark_public`` sets."""
|
|
48
51
|
MODEL_ACTIONS: Final = {
|
|
49
52
|
"GET": "view",
|
|
50
53
|
"HEAD": "view",
|
|
@@ -384,46 +387,103 @@ USER_GUARDS: Final[tuple[object, ...]] = (current_user, authenticated_user)
|
|
|
384
387
|
"""Dependencies that read the user, besides ``Require``."""
|
|
385
388
|
|
|
386
389
|
|
|
390
|
+
def mark_public[T](served: T) -> T:
|
|
391
|
+
"""Mark a mounted application or a Starlette endpoint public on purpose.
|
|
392
|
+
|
|
393
|
+
They take no dependencies, so ``Public`` cannot sit on them, and
|
|
394
|
+
``open_routes`` lists them otherwise::
|
|
395
|
+
|
|
396
|
+
app.mount("/static", mark_public(StaticFiles(directory="static")))
|
|
397
|
+
"""
|
|
398
|
+
setattr(served, PUBLIC_MARK, True)
|
|
399
|
+
return served
|
|
400
|
+
|
|
401
|
+
|
|
387
402
|
def open_routes(app: FastAPI) -> list[str]:
|
|
388
403
|
"""``METHOD /path`` of every route that declares no access rule.
|
|
389
404
|
|
|
390
405
|
A route declares one with ``Require``, ``CurrentUser``,
|
|
391
406
|
``AuthenticatedUser``, or ``Public``, on itself or its router. The
|
|
392
|
-
framework's own routes (``/health``, ``/ready``, ``/metrics
|
|
393
|
-
themselves.
|
|
407
|
+
framework's own routes (``/health``, ``/ready``, ``/metrics``, and the
|
|
408
|
+
``API_DOCS``) guard themselves. Mounted FastAPI and Starlette
|
|
409
|
+
applications are walked route by route. What takes no dependencies (a
|
|
410
|
+
mounted ``StaticFiles``, Starlette's own ``Route``) is listed unless
|
|
411
|
+
marked with ``mark_public``.
|
|
394
412
|
"""
|
|
413
|
+
return [name for name, _ in unguarded_routes(app)]
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
def unguarded_routes(app: FastAPI) -> list[tuple[str, bool]]:
|
|
417
|
+
"""``open_routes``, each with whether it could take a rule (a dependency)."""
|
|
395
418
|
guards = (public, *USER_GUARDS)
|
|
396
|
-
return [
|
|
419
|
+
return [
|
|
420
|
+
(name, dependant is not None)
|
|
421
|
+
for name, dependant in _routes(app.routes)
|
|
422
|
+
if dependant is None or not _uses(dependant, guards)
|
|
423
|
+
]
|
|
397
424
|
|
|
398
425
|
|
|
399
426
|
def routes_need_users(app: FastAPI) -> bool:
|
|
400
427
|
"""Whether some route of ``app`` reads the user or checks rules."""
|
|
401
|
-
return any(
|
|
428
|
+
return any(
|
|
429
|
+
dependant is not None and _uses(dependant, USER_GUARDS)
|
|
430
|
+
for _, dependant in _routes(app.routes)
|
|
431
|
+
)
|
|
402
432
|
|
|
403
433
|
|
|
404
|
-
def _routes(
|
|
434
|
+
def _routes(
|
|
435
|
+
routes: Sequence[BaseRoute], prefix: str = ""
|
|
436
|
+
) -> Iterator[tuple[str, Dependant | None]]:
|
|
405
437
|
"""``METHOD /path`` and dependencies of each route, but the framework's own.
|
|
406
438
|
|
|
407
439
|
Routers are walked as OpenAPI walks them, so the prefixes and
|
|
408
|
-
dependencies of the routers a route is included through count
|
|
440
|
+
dependencies of the routers a route is included through count, and so
|
|
441
|
+
are the applications mounted with routes of their own. What takes no
|
|
442
|
+
dependencies (an application without routes, Starlette's own routes)
|
|
443
|
+
has None, unless it was marked public.
|
|
409
444
|
"""
|
|
410
|
-
|
|
411
|
-
for context in iter_route_contexts(app.routes):
|
|
445
|
+
for context in iter_route_contexts(routes):
|
|
412
446
|
route = context.original_route
|
|
447
|
+
# Routes of included routers keep their full path (and a WebSocket
|
|
448
|
+
# its dependencies) here; FastAPI's own context has them for others.
|
|
449
|
+
effective = getattr(context, "starlette_route", None)
|
|
450
|
+
if isinstance(effective, type(route)):
|
|
451
|
+
route = effective
|
|
452
|
+
found: tuple[str, Dependant | None]
|
|
413
453
|
if isinstance(route, APIWebSocketRoute):
|
|
414
|
-
|
|
415
|
-
effective = getattr(context, "starlette_route", None)
|
|
416
|
-
if isinstance(effective, APIWebSocketRoute):
|
|
417
|
-
route = effective
|
|
418
|
-
name, dependant = f"WEBSOCKET {route.path}", route.dependant
|
|
454
|
+
found = (f"WEBSOCKET {prefix}{route.path}", route.dependant)
|
|
419
455
|
elif isinstance(route, APIRoute):
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
456
|
+
methods = " ".join(sorted(route.methods or ()))
|
|
457
|
+
found = (f"{methods} {prefix}{context.path}", context.dependant)
|
|
458
|
+
elif _marked_public(route):
|
|
423
459
|
continue
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
460
|
+
elif isinstance(route, Mount | Host) and route.routes:
|
|
461
|
+
inner = prefix + route.path if isinstance(route, Mount) else prefix
|
|
462
|
+
yield from _routes(route.routes, inner)
|
|
463
|
+
continue
|
|
464
|
+
else:
|
|
465
|
+
path = getattr(route, "path", "")
|
|
466
|
+
found = (f"{_kind(route)} {prefix}{path}".rstrip(), None)
|
|
467
|
+
endpoint = getattr(route, "endpoint", None)
|
|
468
|
+
if not getattr(endpoint, "__module__", "").startswith(FRAMEWORK_ROUTES):
|
|
469
|
+
yield found
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
def _marked_public(route: BaseRoute) -> bool:
|
|
473
|
+
"""Whether what ``route`` serves was marked with ``mark_public``."""
|
|
474
|
+
served = (getattr(route, name, None) for name in ("endpoint", "app", "_base_app"))
|
|
475
|
+
return any(getattr(target, PUBLIC_MARK, False) is True for target in served)
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
def _kind(route: BaseRoute) -> str:
|
|
479
|
+
"""How ``open_routes`` names a route that takes no dependencies."""
|
|
480
|
+
if isinstance(route, Route):
|
|
481
|
+
return " ".join(sorted(route.methods)) if route.methods else "ANY"
|
|
482
|
+
if isinstance(route, WebSocketRoute):
|
|
483
|
+
return "WEBSOCKET"
|
|
484
|
+
if isinstance(route, Host):
|
|
485
|
+
return f"HOST {route.host}"
|
|
486
|
+
return "MOUNT" if isinstance(route, Mount) else type(route).__name__
|
|
427
487
|
|
|
428
488
|
|
|
429
489
|
def _uses(dependant: Dependant, guards: tuple[object, ...]) -> bool:
|
|
@@ -16,7 +16,7 @@ from domainkit.db.routing import router
|
|
|
16
16
|
from domainkit.exceptions import ImproperlyConfigured
|
|
17
17
|
from domainkit.utils.module_loading import import_string
|
|
18
18
|
|
|
19
|
-
from .access import
|
|
19
|
+
from .access import routes_need_users, unguarded_routes
|
|
20
20
|
from .authentication import get_authenticators
|
|
21
21
|
from .backends import get_backends
|
|
22
22
|
from .hashers import insecure_hashers
|
|
@@ -97,7 +97,11 @@ class AuthConfig(DomainConfig):
|
|
|
97
97
|
problems.extend(
|
|
98
98
|
f"{route} declares no access rule: add Depends(Require(...)), or "
|
|
99
99
|
"dependencies=[Public] if anyone may call it."
|
|
100
|
-
|
|
100
|
+
if takes_rules
|
|
101
|
+
else f"{route} takes no access rule: serve it from a FastAPI route "
|
|
102
|
+
"with Require(...), or wrap it in mark_public(...) if anyone may "
|
|
103
|
+
"call it."
|
|
104
|
+
for route, takes_rules in unguarded_routes(app)
|
|
101
105
|
)
|
|
102
106
|
return problems
|
|
103
107
|
|
|
@@ -22,7 +22,9 @@ callers may do (``domainkit.contrib.auth.access``).
|
|
|
22
22
|
Refused credentials never reach ``RateLimitMiddleware``, so they are
|
|
23
23
|
counted here, per client address, against ``RATE_LIMIT``. Past it, the
|
|
24
24
|
address gets 429, and its requests with an ``Authorization`` header are
|
|
25
|
-
refused before any lookup until ``Retry-After`` has passed.
|
|
25
|
+
refused before any lookup until ``Retry-After`` has passed. Credentials in
|
|
26
|
+
other headers, which only a project's own class reads, are refused too,
|
|
27
|
+
once read, even when they hold: a guess that works gets the same 429.
|
|
26
28
|
"""
|
|
27
29
|
|
|
28
30
|
import logging
|
|
@@ -83,18 +85,20 @@ class AuthenticationMiddleware:
|
|
|
83
85
|
await self.app(scope, receive, send)
|
|
84
86
|
return
|
|
85
87
|
connection = HTTPConnection(scope)
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
and (held := self._held(address_key(scope))) is not None
|
|
90
|
-
):
|
|
91
|
-
await refuse(scope, receive, send, self.rate[0], held)
|
|
88
|
+
held = self._held(address_key(scope))
|
|
89
|
+
if held is not None and "authorization" in connection.headers:
|
|
90
|
+
await refuse(scope, receive, send, *held)
|
|
92
91
|
return
|
|
93
92
|
try:
|
|
94
93
|
credentials = await self._authenticate(connection)
|
|
95
94
|
except _Refused as refused:
|
|
96
95
|
await self._refuse(scope, receive, send, refused)
|
|
97
96
|
return
|
|
97
|
+
if held is not None and credentials is not None:
|
|
98
|
+
# Credentials in another header, read by a project's own class,
|
|
99
|
+
# are refused once read: a guess that works must not stand out.
|
|
100
|
+
await refuse(scope, receive, send, *held)
|
|
101
|
+
return
|
|
98
102
|
scope["user"] = AnonymousUser() if credentials is None else credentials.user
|
|
99
103
|
scope["auth"] = credentials
|
|
100
104
|
context = current_request()
|
|
@@ -151,16 +155,19 @@ class AuthenticationMiddleware:
|
|
|
151
155
|
if len(self.held) > MAX_HELD:
|
|
152
156
|
self.held.popitem(last=False)
|
|
153
157
|
|
|
154
|
-
def _held(self, address: str) -> Decision | None:
|
|
155
|
-
"""The refusal ``address`` is still held to, if any."""
|
|
158
|
+
def _held(self, address: str) -> tuple[int, Decision] | None:
|
|
159
|
+
"""The limit and the refusal ``address`` is still held to, if any."""
|
|
156
160
|
until = self.held.get(address)
|
|
157
|
-
if until is None:
|
|
161
|
+
if until is None or self.rate is None:
|
|
158
162
|
return None
|
|
159
163
|
left = until - monotonic()
|
|
160
164
|
if left <= 0:
|
|
161
165
|
del self.held[address]
|
|
162
166
|
return None
|
|
163
|
-
|
|
167
|
+
refusal = Decision(
|
|
168
|
+
allowed=False, remaining=0, reset_after=left, retry_after=left
|
|
169
|
+
)
|
|
170
|
+
return self.rate[0], refusal
|
|
164
171
|
|
|
165
172
|
|
|
166
173
|
class _Refused(Exception):
|
|
@@ -129,15 +129,20 @@ class UserRepository(SqlAlchemyRepository[AbstractBaseUser, UserId]):
|
|
|
129
129
|
)
|
|
130
130
|
|
|
131
131
|
async def active_superusers(self) -> int:
|
|
132
|
-
"""How many active superusers there are.
|
|
132
|
+
"""How many active superusers there are, locked until the commit.
|
|
133
|
+
|
|
134
|
+
Two transactions that each demote one of the last two superusers
|
|
135
|
+
would both count two; with the rows locked, the second count waits
|
|
136
|
+
for the first transaction and sees what it left.
|
|
137
|
+
"""
|
|
133
138
|
table = get_user_table()
|
|
134
139
|
found = await self.session.execute(
|
|
135
|
-
select(
|
|
136
|
-
.select_from(table)
|
|
140
|
+
select(table.c.id)
|
|
137
141
|
.where(table.c.is_superuser.is_(True), table.c.is_active.is_(True))
|
|
142
|
+
.order_by(table.c.id)
|
|
143
|
+
.with_for_update()
|
|
138
144
|
)
|
|
139
|
-
|
|
140
|
-
return count
|
|
145
|
+
return len(found.all())
|
|
141
146
|
|
|
142
147
|
async def record_login(self, user: AbstractBaseUser) -> None:
|
|
143
148
|
"""Store the login time and record ``UserLoggedIn``.
|
|
@@ -213,7 +213,7 @@ class IdempotencyMiddleware:
|
|
|
213
213
|
)
|
|
214
214
|
else:
|
|
215
215
|
headers = [
|
|
216
|
-
(name.encode(), value.encode())
|
|
216
|
+
(name.encode("latin-1"), value.encode("latin-1"))
|
|
217
217
|
for name, value in (existing["headers"] or {}).items()
|
|
218
218
|
]
|
|
219
219
|
await send(
|
|
@@ -287,10 +287,10 @@ async def _finish(
|
|
|
287
287
|
)
|
|
288
288
|
if released.rowcount:
|
|
289
289
|
return
|
|
290
|
-
headers = {
|
|
291
|
-
name.decode().lower(): value.decode()
|
|
290
|
+
headers = { # ASGI header values are Latin-1 bytes, not always UTF-8.
|
|
291
|
+
name.decode("latin-1").lower(): value.decode("latin-1")
|
|
292
292
|
for name, value in started.get("headers", [])
|
|
293
|
-
if name.decode().lower() in _STORED_HEADERS
|
|
293
|
+
if name.decode("latin-1").lower() in _STORED_HEADERS
|
|
294
294
|
}
|
|
295
295
|
await connection.execute(
|
|
296
296
|
update(idempotency_keys)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/audit/management/commands/__init__.py
RENAMED
|
File without changes
|
{domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/audit/management/commands/auditforget.py
RENAMED
|
File without changes
|
{domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/audit/management/commands/auditlog.py
RENAMED
|
File without changes
|
{domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/audit/management/commands/auditseal.py
RENAMED
|
File without changes
|
{domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/audit/management/commands/auditverify.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/auth/management/commands/__init__.py
RENAMED
|
File without changes
|
{domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/auth/management/commands/changepassword.py
RENAMED
|
File without changes
|
{domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/auth/management/commands/cleartokens.py
RENAMED
|
File without changes
|
|
File without changes
|
{domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/auth/management/commands/createtoken.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/evidence/management/commands/__init__.py
RENAMED
|
File without changes
|
{domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/evidence/management/commands/evidence.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/messaging/management/commands/__init__.py
RENAMED
|
File without changes
|
{domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/messaging/management/commands/messages.py
RENAMED
|
File without changes
|
{domainkit-0.6.1 → domainkit-0.6.2}/src/domainkit/contrib/messaging/management/commands/runworker.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|