hexcore 11.3.0__tar.gz → 11.4.0__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.
Files changed (397) hide show
  1. {hexcore-11.3.0/hexcore.egg-info → hexcore-11.4.0}/PKG-INFO +1 -1
  2. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/application/services.py +14 -0
  3. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/domain/exceptions.py +23 -0
  4. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/domain/ports.py +20 -0
  5. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/infrastructure/api/dependencies.py +5 -1
  6. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/infrastructure/api/middlewares.py +75 -7
  7. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/infrastructure/orms/beanie/repositories.py +12 -0
  8. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/infrastructure/orms/sqlalchemy/repositories.py +13 -0
  9. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/testing/fakes.py +9 -0
  10. {hexcore-11.3.0 → hexcore-11.4.0/hexcore.egg-info}/PKG-INFO +1 -1
  11. {hexcore-11.3.0 → hexcore-11.4.0}/pyproject.toml +1 -1
  12. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_http.py +190 -0
  13. {hexcore-11.3.0 → hexcore-11.4.0}/LICENSE +0 -0
  14. {hexcore-11.3.0 → hexcore-11.4.0}/MANIFEST.in +0 -0
  15. {hexcore-11.3.0 → hexcore-11.4.0}/README.md +0 -0
  16. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/__init__.py +0 -0
  17. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/__main__.py +0 -0
  18. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/_deprecation.py +0 -0
  19. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/application/__init__.py +0 -0
  20. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/application/cqrs/__init__.py +0 -0
  21. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/application/cqrs/adapters.py +0 -0
  22. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/application/cqrs/config.py +0 -0
  23. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/application/cqrs/factory.py +0 -0
  24. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/application/cqrs/in_memory_buses.py +0 -0
  25. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/application/cqrs/pipeline.py +0 -0
  26. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/application/cqrs/registry.py +0 -0
  27. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/application/cqrs/scheduler.py +0 -0
  28. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/application/dtos/__init__.py +0 -0
  29. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/application/dtos/base.py +0 -0
  30. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/application/dtos/cursor.py +0 -0
  31. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/application/dtos/errors.py +0 -0
  32. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/application/dtos/query.py +0 -0
  33. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/application/eventsourcing/__init__.py +0 -0
  34. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/application/eventsourcing/config.py +0 -0
  35. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/application/eventsourcing/factory.py +0 -0
  36. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/application/eventsourcing/projector.py +0 -0
  37. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/application/eventsourcing/relay.py +0 -0
  38. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/application/eventsourcing/repository.py +0 -0
  39. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/application/use_cases/__init__.py +0 -0
  40. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/application/use_cases/base.py +0 -0
  41. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/application/use_cases/query.py +0 -0
  42. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/capabilities.py +0 -0
  43. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/config.py +0 -0
  44. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/cqrs.py +0 -0
  45. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/cqrs.pyi +0 -0
  46. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/__init__.py +0 -0
  47. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/__init__.pyi +0 -0
  48. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/application/__init__.py +0 -0
  49. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/application/authorization.py +0 -0
  50. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/application/authz_middleware.py +0 -0
  51. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/application/commands.py +0 -0
  52. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/application/config.py +0 -0
  53. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/application/container.py +0 -0
  54. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/application/hooks.py +0 -0
  55. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/application/plugins.py +0 -0
  56. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/domain/__init__.py +0 -0
  57. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/domain/authorization.py +0 -0
  58. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/domain/context.py +0 -0
  59. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/domain/entities.py +0 -0
  60. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/domain/events.py +0 -0
  61. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/domain/permissions.py +0 -0
  62. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/domain/plugins.py +0 -0
  63. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/domain/value_objects.py +0 -0
  64. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/infrastructure/__init__.py +0 -0
  65. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/infrastructure/api/__init__.py +0 -0
  66. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/infrastructure/api/authorization.py +0 -0
  67. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/infrastructure/api/routers.py +0 -0
  68. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/infrastructure/cli.py +0 -0
  69. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/infrastructure/clock.py +0 -0
  70. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/infrastructure/envelope.py +0 -0
  71. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/infrastructure/hashing.py +0 -0
  72. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/infrastructure/keys.py +0 -0
  73. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/infrastructure/lifespan.py +0 -0
  74. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/infrastructure/orms/__init__.py +0 -0
  75. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/infrastructure/orms/beanie/__init__.py +0 -0
  76. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/infrastructure/orms/beanie/documents.py +0 -0
  77. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/infrastructure/orms/beanie/schema.py +0 -0
  78. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/infrastructure/orms/selection.py +0 -0
  79. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/infrastructure/orms/sqlalchemy/__init__.py +0 -0
  80. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/infrastructure/orms/sqlalchemy/models.py +0 -0
  81. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/infrastructure/orms/sqlalchemy/models_mixins.py +0 -0
  82. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/infrastructure/orms/sqlalchemy/registry.py +0 -0
  83. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/infrastructure/orms/sqlalchemy/schema.py +0 -0
  84. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/infrastructure/revocation.py +0 -0
  85. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/infrastructure/secretbox.py +0 -0
  86. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/infrastructure/tokens.py +0 -0
  87. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/infrastructure/transports.py +0 -0
  88. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/__init__.py +0 -0
  89. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/drbac/__init__.py +0 -0
  90. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/drbac/cache.py +0 -0
  91. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/drbac/conditions.py +0 -0
  92. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/drbac/domain.py +0 -0
  93. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/drbac/orms/__init__.py +0 -0
  94. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/drbac/orms/beanie/__init__.py +0 -0
  95. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/drbac/orms/beanie/repository.py +0 -0
  96. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/drbac/orms/sqlalchemy/__init__.py +0 -0
  97. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/drbac/orms/sqlalchemy/models.py +0 -0
  98. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/drbac/orms/sqlalchemy/models_mixins.py +0 -0
  99. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/drbac/orms/sqlalchemy/repository.py +0 -0
  100. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/drbac/pdp.py +0 -0
  101. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/drbac/pip.py +0 -0
  102. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/drbac/predicates.py +0 -0
  103. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/drbac/provider.py +0 -0
  104. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/drbac/router.py +0 -0
  105. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/drbac/service.py +0 -0
  106. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/impersonate/__init__.py +0 -0
  107. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/impersonate/commands.py +0 -0
  108. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/impersonate/domain.py +0 -0
  109. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/impersonate/router.py +0 -0
  110. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/impersonate/service.py +0 -0
  111. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/magic_link/__init__.py +0 -0
  112. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/magic_link/commands.py +0 -0
  113. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/magic_link/router.py +0 -0
  114. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/oauth/__init__.py +0 -0
  115. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/oauth/domain.py +0 -0
  116. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/oauth/http.py +0 -0
  117. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/oauth/orms/__init__.py +0 -0
  118. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/oauth/orms/beanie/__init__.py +0 -0
  119. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/oauth/orms/beanie/repository.py +0 -0
  120. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/oauth/orms/sqlalchemy/__init__.py +0 -0
  121. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/oauth/orms/sqlalchemy/models.py +0 -0
  122. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/oauth/orms/sqlalchemy/models_mixins.py +0 -0
  123. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/oauth/orms/sqlalchemy/repository.py +0 -0
  124. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/oauth/providers.py +0 -0
  125. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/oauth/router.py +0 -0
  126. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/oauth/service.py +0 -0
  127. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/organization/__init__.py +0 -0
  128. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/organization/domain.py +0 -0
  129. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/organization/orms/__init__.py +0 -0
  130. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/organization/orms/beanie/__init__.py +0 -0
  131. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/organization/orms/beanie/repository.py +0 -0
  132. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/organization/orms/sqlalchemy/__init__.py +0 -0
  133. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/organization/orms/sqlalchemy/models.py +0 -0
  134. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/organization/orms/sqlalchemy/models_mixins.py +0 -0
  135. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/organization/orms/sqlalchemy/repository.py +0 -0
  136. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/organization/router.py +0 -0
  137. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/organization/service.py +0 -0
  138. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/passkey/__init__.py +0 -0
  139. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/passkey/domain.py +0 -0
  140. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/passkey/orms/__init__.py +0 -0
  141. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/passkey/orms/beanie/__init__.py +0 -0
  142. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/passkey/orms/beanie/repository.py +0 -0
  143. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/passkey/orms/sqlalchemy/__init__.py +0 -0
  144. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/passkey/orms/sqlalchemy/models.py +0 -0
  145. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/passkey/orms/sqlalchemy/models_mixins.py +0 -0
  146. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/passkey/orms/sqlalchemy/repository.py +0 -0
  147. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/passkey/router.py +0 -0
  148. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/passkey/service.py +0 -0
  149. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/passkey/webauthn_adapter.py +0 -0
  150. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/rbac/__init__.py +0 -0
  151. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/rbac/cache.py +0 -0
  152. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/rbac/cli.py +0 -0
  153. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/rbac/domain.py +0 -0
  154. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/rbac/matcher.py +0 -0
  155. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/rbac/orms/__init__.py +0 -0
  156. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/rbac/orms/beanie/__init__.py +0 -0
  157. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/rbac/orms/beanie/repository.py +0 -0
  158. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/rbac/orms/sqlalchemy/__init__.py +0 -0
  159. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/rbac/orms/sqlalchemy/models.py +0 -0
  160. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/rbac/orms/sqlalchemy/models_mixins.py +0 -0
  161. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/rbac/orms/sqlalchemy/repository.py +0 -0
  162. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/rbac/provider.py +0 -0
  163. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/rbac/resolver.py +0 -0
  164. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/rbac/router.py +0 -0
  165. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/rbac/service.py +0 -0
  166. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/storage.py +0 -0
  167. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/two_factor/__init__.py +0 -0
  168. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/two_factor/commands.py +0 -0
  169. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/two_factor/crypto.py +0 -0
  170. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/two_factor/domain.py +0 -0
  171. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/two_factor/orms/__init__.py +0 -0
  172. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/two_factor/orms/beanie/__init__.py +0 -0
  173. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/two_factor/orms/beanie/repository.py +0 -0
  174. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/two_factor/orms/sqlalchemy/__init__.py +0 -0
  175. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/two_factor/orms/sqlalchemy/models.py +0 -0
  176. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/two_factor/orms/sqlalchemy/models_mixins.py +0 -0
  177. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/two_factor/orms/sqlalchemy/repository.py +0 -0
  178. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/two_factor/router.py +0 -0
  179. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/two_factor/service.py +0 -0
  180. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/plugins/two_factor/totp.py +0 -0
  181. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/testing/__init__.py +0 -0
  182. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/testing/fixtures.py +0 -0
  183. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/darwin/testing/helpers.py +0 -0
  184. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/domain/__init__.py +0 -0
  185. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/domain/base.py +0 -0
  186. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/domain/cqrs/__init__.py +0 -0
  187. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/domain/cqrs/buses.py +0 -0
  188. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/domain/cqrs/commands.py +0 -0
  189. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/domain/cqrs/context.py +0 -0
  190. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/domain/cqrs/cron.py +0 -0
  191. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/domain/cqrs/decorators.py +0 -0
  192. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/domain/cqrs/dispatch.py +0 -0
  193. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/domain/cqrs/envelope.py +0 -0
  194. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/domain/cqrs/exceptions.py +0 -0
  195. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/domain/cqrs/handlers.py +0 -0
  196. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/domain/cqrs/middleware.py +0 -0
  197. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/domain/cqrs/queries.py +0 -0
  198. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/domain/cqrs/resolution.py +0 -0
  199. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/domain/cqrs/serializer.py +0 -0
  200. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/domain/cqrs/task_queues.py +0 -0
  201. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/domain/events.py +0 -0
  202. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/domain/eventsourcing/__init__.py +0 -0
  203. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/domain/eventsourcing/aggregate.py +0 -0
  204. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/domain/eventsourcing/exceptions.py +0 -0
  205. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/domain/eventsourcing/projections.py +0 -0
  206. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/domain/eventsourcing/snapshots.py +0 -0
  207. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/domain/eventsourcing/store.py +0 -0
  208. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/domain/eventsourcing/stored.py +0 -0
  209. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/domain/exceptions.py +0 -0
  210. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/domain/repositories.py +0 -0
  211. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/domain/services.py +0 -0
  212. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/domain/uow.py +0 -0
  213. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/eventsourcing.py +0 -0
  214. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/eventsourcing.pyi +0 -0
  215. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/fastapi.py +0 -0
  216. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/fastapi.pyi +0 -0
  217. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/__init__.py +0 -0
  218. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/api/__init__.py +0 -0
  219. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/api/app.py +0 -0
  220. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/api/cqrs.py +0 -0
  221. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/api/eventsourcing.py +0 -0
  222. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/api/exception_handlers.py +0 -0
  223. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/api/health.py +0 -0
  224. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/api/lifespan.py +0 -0
  225. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/api/middlewares.py +0 -0
  226. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/api/rate_limit.py +0 -0
  227. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/api/routing.py +0 -0
  228. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/api/streaming.py +0 -0
  229. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/api/utils.py +0 -0
  230. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/cache/__init__.py +0 -0
  231. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/cache/cache_backends/__init__.py +0 -0
  232. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/cache/cache_backends/memory.py +0 -0
  233. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/cache/cache_backends/redis.py +0 -0
  234. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/cli.py +0 -0
  235. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/cqrs/__init__.py +0 -0
  236. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/cqrs/cron_sql.py +0 -0
  237. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/cqrs/middlewares.py +0 -0
  238. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/cqrs/postgres_bus.py +0 -0
  239. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/cqrs/postgres_lock.py +0 -0
  240. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/cqrs/procrastinate.py +0 -0
  241. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/cqrs/pydantic_serializer.py +0 -0
  242. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/cqrs/rabbitmq.py +0 -0
  243. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/cqrs/redis_bus.py +0 -0
  244. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/cqrs/redis_lock.py +0 -0
  245. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/eventsourcing/__init__.py +0 -0
  246. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/eventsourcing/beanie_documents.py +0 -0
  247. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/eventsourcing/beanie_store.py +0 -0
  248. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/eventsourcing/memory.py +0 -0
  249. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/eventsourcing/redis_store.py +0 -0
  250. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/eventsourcing/sqlalchemy_models.py +0 -0
  251. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/eventsourcing/sqlalchemy_models_mixins.py +0 -0
  252. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/eventsourcing/sqlalchemy_store.py +0 -0
  253. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/repositories/__init__.py +0 -0
  254. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/repositories/_beanie_impl.py +0 -0
  255. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/repositories/_sqlalchemy_impl.py +0 -0
  256. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/repositories/base.py +0 -0
  257. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/repositories/decorators.py +0 -0
  258. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/repositories/implementations.py +0 -0
  259. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/repositories/orms/__init__.py +0 -0
  260. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/repositories/orms/beanie/__init__.py +0 -0
  261. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/repositories/orms/beanie/utils.py +0 -0
  262. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/repositories/orms/sqlalchemy/__init__.py +0 -0
  263. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/repositories/orms/sqlalchemy/id_types.py +0 -0
  264. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/repositories/orms/sqlalchemy/session.py +0 -0
  265. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/repositories/orms/sqlalchemy/utils.py +0 -0
  266. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/repositories/utils.py +0 -0
  267. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/task_queues/__init__.py +0 -0
  268. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/task_queues/celery_adapter.py +0 -0
  269. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/task_queues/procrastinate_adapter.py +0 -0
  270. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/uow/__init__.py +0 -0
  271. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/uow/decorators.py +0 -0
  272. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/uow/helpers.py +0 -0
  273. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/uow/scopes.py +0 -0
  274. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/workers/__init__.py +0 -0
  275. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/workers/consumer.py +0 -0
  276. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/workers/rabbitmq_worker.py +0 -0
  277. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/infrastructure/workers/runner.py +0 -0
  278. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/py.typed +0 -0
  279. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/sql.py +0 -0
  280. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/sql.pyi +0 -0
  281. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/testing/__init__.py +0 -0
  282. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/testing/fakes.py +0 -0
  283. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/testing/fixtures.py +0 -0
  284. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/testing/helpers.py +0 -0
  285. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/testing/repositories.py +0 -0
  286. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore/types.py +0 -0
  287. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore.egg-info/SOURCES.txt +0 -0
  288. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore.egg-info/dependency_links.txt +0 -0
  289. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore.egg-info/entry_points.txt +0 -0
  290. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore.egg-info/requires.txt +0 -0
  291. {hexcore-11.3.0 → hexcore-11.4.0}/hexcore.egg-info/top_level.txt +0 -0
  292. {hexcore-11.3.0 → hexcore-11.4.0}/setup.cfg +0 -0
  293. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_alembic_metadata_completeness.py +0 -0
  294. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_anclas_del_repo.py +0 -0
  295. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_api_app_and_lifespan.py +0 -0
  296. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_api_cors_dinamico.py +0 -0
  297. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_api_cqrs_providers.py +0 -0
  298. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_api_exception_handlers.py +0 -0
  299. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_api_health.py +0 -0
  300. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_api_middlewares_and_routing.py +0 -0
  301. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_api_rate_limit.py +0 -0
  302. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_api_streaming.py +0 -0
  303. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_basic.py +0 -0
  304. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_beanie_query_utils.py +0 -0
  305. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_celery_event_loop.py +0 -0
  306. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_config_cors_security.py +0 -0
  307. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_config_loading.py +0 -0
  308. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_consumer_optional_event_bus.py +0 -0
  309. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_cqrs.py +0 -0
  310. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_cqrs_envelope.py +0 -0
  311. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_cqrs_factory.py +0 -0
  312. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_cqrs_middlewares.py +0 -0
  313. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_cron_sql.py +0 -0
  314. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_10_4_hardening.py +0 -0
  315. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_authorization_engine.py +0 -0
  316. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_authorization_http.py +0 -0
  317. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_backend_neutrality.py +0 -0
  318. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_beanie.py +0 -0
  319. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_cli.py +0 -0
  320. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_container.py +0 -0
  321. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_context.py +0 -0
  322. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_custom_plugin.py +0 -0
  323. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_drbac_conditions.py +0 -0
  324. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_drbac_pdp.py +0 -0
  325. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_drbac_router.py +0 -0
  326. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_drbac_service.py +0 -0
  327. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_envelope.py +0 -0
  328. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_facade_and_events.py +0 -0
  329. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_flows.py +0 -0
  330. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_hashing.py +0 -0
  331. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_impersonate.py +0 -0
  332. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_magic_link.py +0 -0
  333. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_models.py +0 -0
  334. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_oauth.py +0 -0
  335. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_openapi.py +0 -0
  336. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_organization.py +0 -0
  337. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_passkey.py +0 -0
  338. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_permissions.py +0 -0
  339. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_plugin_decoupling.py +0 -0
  340. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_plugins.py +0 -0
  341. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_principals.py +0 -0
  342. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_production_defaults.py +0 -0
  343. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_rbac.py +0 -0
  344. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_rbac_service.py +0 -0
  345. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_repositories.py +0 -0
  346. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_revocation.py +0 -0
  347. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_schema_registration.py +0 -0
  348. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_storage_selection.py +0 -0
  349. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_tokens.py +0 -0
  350. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_two_factor.py +0 -0
  351. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_username.py +0 -0
  352. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_darwin_value_objects.py +0 -0
  353. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_deprecations.py +0 -0
  354. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_documentation_examples.py +0 -0
  355. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_domain_base_contract.py +0 -0
  356. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_domain_service_query.py +0 -0
  357. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_dotted_resolution.py +0 -0
  358. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_event_dispatch_mro.py +0 -0
  359. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_eventsourcing_aggregate.py +0 -0
  360. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_eventsourcing_beanie.py +0 -0
  361. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_eventsourcing_config.py +0 -0
  362. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_eventsourcing_ports.py +0 -0
  363. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_eventsourcing_projections.py +0 -0
  364. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_eventsourcing_redis.py +0 -0
  365. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_eventsourcing_relay.py +0 -0
  366. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_eventsourcing_repository.py +0 -0
  367. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_eventsourcing_snapshot_checkpoint.py +0 -0
  368. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_eventsourcing_sql_schema.py +0 -0
  369. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_eventsourcing_store_contract.py +0 -0
  370. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_eventsourcing_uow_integration.py +0 -0
  371. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_facades.py +0 -0
  372. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_handler_registry.py +0 -0
  373. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_infrastructure_query_path.py +0 -0
  374. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_lock_error_policy.py +0 -0
  375. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_optional_dependencies.py +0 -0
  376. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_packaging.py +0 -0
  377. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_postgres_bus.py +0 -0
  378. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_postgres_lock.py +0 -0
  379. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_query_cursor_and_endpoint.py +0 -0
  380. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_query_field_validation.py +0 -0
  381. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_rabbitmq_bus.py +0 -0
  382. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_redis_bus.py +0 -0
  383. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_redis_lock.py +0 -0
  384. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_repositories_utils.py +0 -0
  385. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_scheduler.py +0 -0
  386. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_scheduler_catchup.py +0 -0
  387. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_smart_routing.py +0 -0
  388. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_sql_naming_convention.py +0 -0
  389. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_sql_session_layer.py +0 -0
  390. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_task_queues_adapters.py +0 -0
  391. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_testing_kit.py +0 -0
  392. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_testing_utilities.py +0 -0
  393. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_typing_gate.py +0 -0
  394. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_uow_session_regression.py +0 -0
  395. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_use_cases_query.py +0 -0
  396. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_worker_bus_integration.py +0 -0
  397. {hexcore-11.3.0 → hexcore-11.4.0}/tests/test_worker_runner.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hexcore
3
- Version: 11.3.0
3
+ Version: 11.4.0
4
4
  Summary: Reusable core for Python projects with hexagonal architecture, DDD, CQRS and background tasks. Ships the abstractions and the infrastructure: SQL session layer, FastAPI factories, worker runner, dynamic cron and identity.
5
5
  Author-email: "David Latosefki (Indroic)" <indroic@outlook.com>
6
6
  License-Expression: MIT
@@ -381,6 +381,20 @@ class SessionService:
381
381
  impersonation=impersonacion,
382
382
  )
383
383
 
384
+ async def previous_session_ids(self, session_id: UUID, *, limit: int = 100) -> list[UUID]:
385
+ """
386
+ Los `sid` de las sesiones **anteriores** de la familia de `session_id` (sin incluirla).
387
+
388
+ Existe para que `CsrfMiddleware` reconozca un token anti-CSRF que fue válido para la
389
+ sesión que el refresh acaba de reemplazar. Lee la base, pero sólo en el camino de
390
+ rechazo y con tope: el camino feliz de un request no lo llama.
391
+ """
392
+ sesion = await self._sessions.get(session_id)
393
+ if sesion is None:
394
+ return []
395
+ ids = await self._sessions.list_family_session_ids(sesion.family_id, limit=limit)
396
+ return [sid for sid in ids if sid != session_id]
397
+
384
398
  # ── Rotar ─────────────────────────────────────────────────────────────────
385
399
  async def refresh(
386
400
  self, refresh_token: str, *, transport: Transport
@@ -36,6 +36,8 @@ __all__ = [
36
36
  "EmailNotVerifiedError",
37
37
  "ImpersonationNotPermittedError",
38
38
  "CsrfValidationError",
39
+ "CSRF_CODE_INVALID",
40
+ "CSRF_CODE_PREVIOUS_SESSION",
39
41
  # ── Estado (409 / 423) ──
40
42
  "EmailAlreadyRegisteredError",
41
43
  "UsernameAlreadyTakenError",
@@ -164,14 +166,35 @@ class ImpersonationNotPermittedError(AuthorizationError):
164
166
  """
165
167
 
166
168
 
169
+ #: `code` de un rechazo de CSRF cuyo token no verifica contra la sesión en curso ni contra
170
+ #: ninguna anterior de su familia: lo mandó alguien que no lo recibió del servidor.
171
+ CSRF_CODE_INVALID = "CsrfTokenInvalid"
172
+
173
+ #: `code` de un rechazo de CSRF cuyo token **sí** fue válido, pero de una sesión anterior de la
174
+ #: misma familia de rotación: el cliente firmó antes de que un refresh rotara el `sid`. Es el
175
+ #: caso que se arregla pidiendo el token vigente (`GET /auth/csrf`) y reintentando.
176
+ CSRF_CODE_PREVIOUS_SESSION = "CsrfTokenFromPreviousSession"
177
+
178
+
167
179
  class CsrfValidationError(AuthorizationError):
168
180
  """
169
181
  Falló el chequeo anti-CSRF del transporte por cookie.
170
182
 
171
183
  Sólo aplica al camino de cookie: un cliente Bearer manda el token a propósito en cada
172
184
  petición, así que no hay nada que falsificar desde otro origen.
185
+
186
+ `code` distingue, **cuando el rechazo es por el token**, entre `CSRF_CODE_INVALID` y
187
+ `CSRF_CODE_PREVIOUS_SESSION`; viaja en el cuerpo del 403 junto a `error`
188
+ (`CsrfValidationError`, que sigue siendo el discriminante). Es `None` cuando el rechazo
189
+ no es por el token (un origen en el que no se confía), porque ahí no hay nada que
190
+ recuperar. No revela nada útil a un atacante: sólo se llega a `CSRF_CODE_PREVIOUS_SESSION`
191
+ mandando un token que el servidor ya emitió para esa misma familia de sesiones.
173
192
  """
174
193
 
194
+ def __init__(self, *args: object, code: str | None = None) -> None:
195
+ super().__init__(*args)
196
+ self.code = code
197
+
175
198
 
176
199
  # ── Estado del recurso ────────────────────────────────────────────────────────
177
200
  class EmailAlreadyRegisteredError(IdentityError):
@@ -187,6 +187,26 @@ class AbstractSessionRepository(abc.ABC):
187
187
  async def revoke(self, session_id: UUID, *, at: datetime, reason: str) -> None:
188
188
  raise NotImplementedError
189
189
 
190
+ async def list_family_session_ids(
191
+ self, family_id: UUID, *, limit: int = 100
192
+ ) -> "list[UUID]":
193
+ """
194
+ Los `id` de las sesiones de una familia de rotación, las **más recientes primero**, con
195
+ tope de `limit`.
196
+
197
+ Sólo lo usa `CsrfMiddleware` para clasificar un rechazo de CSRF: reconocer que el token
198
+ que llegó era de una sesión anterior de la familia (el cliente firmó antes de que un
199
+ refresh rotara el `sid`). Incluye revocadas y consumidas: justamente las anteriores lo
200
+ están.
201
+
202
+ **No es abstracto a propósito**: es un puerto agregado después, y volverlo abstracto
203
+ rompería a todo repositorio propio ya escrito. La implementación por defecto devuelve
204
+ `[]`, y entonces el rechazo se clasifica siempre como token inválido: el comportamiento
205
+ (403) no cambia, sólo se pierde el `code` más específico.
206
+ """
207
+ del family_id, limit
208
+ return []
209
+
190
210
  @abc.abstractmethod
191
211
  async def revoke_family(self, family_id: UUID, *, at: datetime, reason: str) -> int:
192
212
  """
@@ -194,13 +194,17 @@ def identity_exception_payload(exc: Exception) -> t.Mapping[str, t.Any]:
194
194
  Darwin) devuelve sólo lo del núcleo en vez de lanzar — mismo trato que `_mapa_de_plugins()`
195
195
  en `app.py`.
196
196
  """
197
- from hexcore.darwin.domain.exceptions import AccessDeniedError
197
+ from hexcore.darwin.domain.exceptions import AccessDeniedError, CsrfValidationError
198
198
 
199
199
  base: dict[str, t.Any] = {}
200
200
  if isinstance(exc, AccessDeniedError):
201
201
  # Sólo `required`: `Decision.reason` es interno y nunca llega al cliente. Ver el
202
202
  # docstring de `AccessDeniedError`.
203
203
  base["required"] = exc.required
204
+ elif isinstance(exc, CsrfValidationError) and exc.code is not None:
205
+ # El mismo `code` que `CsrfMiddleware` pone en su 403, para que un rechazo de CSRF
206
+ # lanzado desde un handler tenga la misma forma que el del middleware.
207
+ base["code"] = exc.code
204
208
 
205
209
  from hexcore.darwin.application.container import get_identity_container
206
210
 
@@ -25,7 +25,12 @@ from starlette.requests import Request
25
25
  from starlette.responses import JSONResponse, Response
26
26
 
27
27
  from hexcore.darwin.domain.context import AUTH_CONTEXT
28
- from hexcore.darwin.domain.exceptions import CsrfValidationError, IdentityError
28
+ from hexcore.darwin.domain.exceptions import (
29
+ CSRF_CODE_INVALID,
30
+ CSRF_CODE_PREVIOUS_SESSION,
31
+ CsrfValidationError,
32
+ IdentityError,
33
+ )
29
34
 
30
35
  if t.TYPE_CHECKING:
31
36
  from hexcore.darwin.application.config import IdentityConfig
@@ -224,13 +229,74 @@ class CsrfMiddleware(BaseHTTPMiddleware):
224
229
  logger.info(
225
230
  "CSRF rechazado en %s %s: %s", request.method, request.url.path, exc
226
231
  )
227
- return JSONResponse(
228
- status_code=403,
229
- content={"detail": str(exc), "error": type(exc).__name__},
230
- )
232
+ if exc.code == CSRF_CODE_INVALID and await self._es_de_sesion_anterior(
233
+ request, contenedor
234
+ ):
235
+ exc = CsrfValidationError(
236
+ "El token anti-CSRF del header es de una sesión anterior: el refresh "
237
+ "rotó la sesión después de que el cliente lo obtuvo. Pedí el vigente con "
238
+ "`GET /auth/csrf` y repetí la petición.",
239
+ code=CSRF_CODE_PREVIOUS_SESSION,
240
+ )
241
+ content: dict[str, t.Any] = {"detail": str(exc), "error": type(exc).__name__}
242
+ if exc.code is not None:
243
+ content["code"] = exc.code
244
+ return JSONResponse(status_code=403, content=content)
231
245
 
232
246
  return await call_next(request)
233
247
 
248
+ async def _es_de_sesion_anterior(
249
+ self, request: Request, contenedor: t.Any
250
+ ) -> bool:
251
+ """
252
+ Si el token del header fue el de una sesión **anterior de la misma familia** que la de
253
+ la cookie de acceso.
254
+
255
+ Sólo corre al rechazar, así que el camino feliz de un request no paga la lectura de la
256
+ base. Tiene que ser **mejor esfuerzo**: cualquier fallo (credencial que no autentica,
257
+ base caída, un backend sin `list_family_session_ids`) devuelve `False` y el rechazo
258
+ sale como token inválido, que es lo que habría salido sin esta clasificación. Nunca
259
+ convierte un 403 en un 500.
260
+ """
261
+ from hexcore.darwin.infrastructure.hashing import compare_hashes, derive_csrf_token
262
+
263
+ enviado = request.headers.get(CSRF_HEADER)
264
+ clave = contenedor.config.secret_key
265
+ if not enviado or clave is None:
266
+ return False
267
+
268
+ try:
269
+ auth = auth_from_request(request)
270
+ if auth is None:
271
+ from hexcore.darwin.infrastructure.transports import TransportResolver
272
+
273
+ transporte = TransportResolver(cookies=contenedor.config.cookies).resolve(
274
+ request
275
+ )
276
+ token = transporte.extract_access(request)
277
+ if token is None:
278
+ return False
279
+ auth = await contenedor.session_service().authenticate(
280
+ token, transport=transporte.name
281
+ )
282
+
283
+ sid = getattr(auth.actor, "session_id", None)
284
+ if sid is None or auth.transport != "cookie":
285
+ return False
286
+
287
+ secreto = clave.get_secret_value()
288
+ previas = await contenedor.session_service().previous_session_ids(sid)
289
+ # Se recorren **todas** sin cortar en la primera que coincide: el tiempo no tiene
290
+ # que depender de cuál era (aunque `compare_hashes` ya es en tiempo constante).
291
+ coincide = False
292
+ for previa in previas:
293
+ if compare_hashes(enviado, derive_csrf_token(str(previa), secreto)):
294
+ coincide = True
295
+ return coincide
296
+ except Exception:
297
+ logger.debug("No se pudo clasificar el rechazo de CSRF.", exc_info=True)
298
+ return False
299
+
234
300
  def _exento(self, request: Request) -> bool:
235
301
  if request.method.upper() in SAFE_METHODS:
236
302
  return True
@@ -262,14 +328,16 @@ class CsrfMiddleware(BaseHTTPMiddleware):
262
328
  if not enviado or not esperado:
263
329
  raise CsrfValidationError(
264
330
  f"Falta el chequeo anti-CSRF: la petición tiene que mandar el header "
265
- f"'{CSRF_HEADER}' con el mismo valor que la cookie de CSRF."
331
+ f"'{CSRF_HEADER}' con el mismo valor que la cookie de CSRF.",
332
+ code=CSRF_CODE_INVALID,
266
333
  )
267
334
 
268
335
  from hexcore.darwin.infrastructure.hashing import compare_hashes
269
336
 
270
337
  if not compare_hashes(enviado, esperado):
271
338
  raise CsrfValidationError(
272
- "El valor anti-CSRF del header no coincide con el de la cookie."
339
+ "El valor anti-CSRF del header no coincide con el de la cookie.",
340
+ code=CSRF_CODE_INVALID,
273
341
  )
274
342
 
275
343
  @staticmethod
@@ -245,6 +245,18 @@ class BeanieSessionRepository(_BaseBeanieRepository, AbstractSessionRepository):
245
245
  {"$set": {"revoked_at": at, "updated_at": datetime.now(UTC)}}
246
246
  )
247
247
 
248
+ async def list_family_session_ids(
249
+ self, family_id: UUID, *, limit: int = 100
250
+ ) -> list[UUID]:
251
+ """Los `id` de la familia, las más recientes primero. Ver el puerto."""
252
+ docs = (
253
+ await self._doc.find(self._doc.family_id == family_id)
254
+ .sort("-created_at")
255
+ .limit(limit)
256
+ .to_list()
257
+ )
258
+ return [doc.entity_id for doc in docs]
259
+
248
260
  async def revoke_family(
249
261
  self, family_id: UUID, *, at: datetime, reason: str
250
262
  ) -> int:
@@ -221,6 +221,19 @@ class SqlAlchemySessionRepository(_BaseIdentityRepository, AbstractSessionReposi
221
221
  )
222
222
  await session.commit()
223
223
 
224
+ async def list_family_session_ids(
225
+ self, family_id: UUID, *, limit: int = 100
226
+ ) -> list[UUID]:
227
+ """Los `id` de la familia, las más recientes primero. Ver el puerto."""
228
+ async with self._session_scope() as session:
229
+ resultado = await session.execute(
230
+ select(self._model.id)
231
+ .where(self._model.family_id == family_id)
232
+ .order_by(self._model.created_at.desc())
233
+ .limit(limit)
234
+ )
235
+ return list(resultado.scalars().all())
236
+
224
237
  async def revoke_family(
225
238
  self, family_id: UUID, *, at: datetime, reason: str
226
239
  ) -> int:
@@ -259,6 +259,15 @@ class FakeSessionRepository(AbstractSessionRepository):
259
259
  )
260
260
  self.reasons[session_id] = reason
261
261
 
262
+ async def list_family_session_ids(
263
+ self, family_id: UUID, *, limit: int = 100
264
+ ) -> list[UUID]:
265
+ """Los `id` de la familia, las más recientes primero. Ver el puerto."""
266
+ with self._lock:
267
+ familia = [s for s in self._por_id.values() if s.family_id == family_id]
268
+ familia.sort(key=lambda s: s.created_at, reverse=True)
269
+ return [s.id for s in familia[:limit]]
270
+
262
271
  async def revoke_family(
263
272
  self, family_id: UUID, *, at: datetime, reason: str
264
273
  ) -> int:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hexcore
3
- Version: 11.3.0
3
+ Version: 11.4.0
4
4
  Summary: Reusable core for Python projects with hexagonal architecture, DDD, CQRS and background tasks. Ships the abstractions and the infrastructure: SQL session layer, FastAPI factories, worker runner, dynamic cron and identity.
5
5
  Author-email: "David Latosefki (Indroic)" <indroic@outlook.com>
6
6
  License-Expression: MIT
@@ -10,7 +10,7 @@ build-backend = "setuptools.build_meta"
10
10
 
11
11
  [project]
12
12
  name = "hexcore"
13
- version = "11.3.0"
13
+ version = "11.4.0"
14
14
  authors = [
15
15
  { name="David Latosefki (Indroic)", email="indroic@outlook.com" },
16
16
  ]
@@ -1006,3 +1006,193 @@ def test_una_app_sin_el_feature_no_resuelve_credenciales(contenedor):
1006
1006
  r = TestClient(app).get("/x")
1007
1007
 
1008
1008
  assert r.json()["hay_contexto"] is False
1009
+
1010
+
1011
+ # ── 2c. CSRF y rotación de sesión (HC-01) ─────────────────────────────────────
1012
+ #
1013
+ # El refresh rota la sesión: crea una con `sid` nuevo, y el token anti-CSRF es `HMAC(sid)`. Una
1014
+ # petición firmada **antes** del refresh llega con el token de la sesión anterior y se rechaza
1015
+ # con 403. Es un caso distinto de un token inventado, y el cliente lo resuelve pidiendo el token
1016
+ # vigente: por eso el 403 lleva un `code` que los distingue.
1017
+ CODIGO_SESION_ANTERIOR = "CsrfTokenFromPreviousSession"
1018
+ CODIGO_INVALIDO = "CsrfTokenInvalid"
1019
+
1020
+
1021
+ def _escribir(client: TestClient, token: str | None):
1022
+ """Una escritura por cookie con el token dado en el header (o sin header si es `None`)."""
1023
+ headers = {"Origin": ORIGEN}
1024
+ if token is not None:
1025
+ headers[CSRF_HEADER] = token
1026
+ return client.post("/auth/sign-out", headers=headers)
1027
+
1028
+
1029
+ def test_el_refresh_entrega_siempre_el_token_csrf_de_la_sesion_nueva(client, contenedor):
1030
+ _alta(client)
1031
+ anterior = _sign_in_cookie(client).headers[CSRF_HEADER]
1032
+
1033
+ r = client.post("/auth/refresh", headers=_csrf_headers(client))
1034
+
1035
+ assert r.status_code == 200, r.text
1036
+ sid_nuevo = r.json()["session_id"]
1037
+ assert r.headers[CSRF_HEADER] == derive_csrf_token(sid_nuevo, CLAVE)
1038
+ assert r.headers[CSRF_HEADER] != anterior
1039
+
1040
+
1041
+ def test_un_token_de_una_sesion_anterior_de_la_familia_tiene_su_propio_code(client, contenedor):
1042
+ _alta(client)
1043
+ anterior = _sign_in_cookie(client).headers[CSRF_HEADER]
1044
+ r = client.post("/auth/refresh", headers=_csrf_headers(client))
1045
+ assert r.status_code == 200, r.text
1046
+
1047
+ r = _escribir(client, anterior)
1048
+
1049
+ assert r.status_code == 403
1050
+ cuerpo = r.json()
1051
+ assert cuerpo["error"] == "CsrfValidationError"
1052
+ assert cuerpo["code"] == CODIGO_SESION_ANTERIOR
1053
+ assert "sesión anterior" in cuerpo["detail"]
1054
+
1055
+
1056
+ def test_tambien_se_reconoce_un_token_de_dos_rotaciones_atras(client, contenedor):
1057
+ _alta(client)
1058
+ primero = _sign_in_cookie(client).headers[CSRF_HEADER]
1059
+ assert client.post("/auth/refresh", headers=_csrf_headers(client)).status_code == 200
1060
+ assert client.post("/auth/refresh", headers=_csrf_headers(client)).status_code == 200
1061
+
1062
+ r = _escribir(client, primero)
1063
+
1064
+ assert r.status_code == 403
1065
+ assert r.json()["code"] == CODIGO_SESION_ANTERIOR
1066
+
1067
+
1068
+ def test_un_token_inventado_tiene_el_code_generico(client, contenedor):
1069
+ _alta(client)
1070
+ _sign_in_cookie(client)
1071
+
1072
+ r = _escribir(client, "x" * 43)
1073
+
1074
+ assert r.status_code == 403
1075
+ cuerpo = r.json()
1076
+ assert cuerpo["error"] == "CsrfValidationError"
1077
+ assert cuerpo["code"] == CODIGO_INVALIDO
1078
+ assert "sesión anterior" not in cuerpo["detail"]
1079
+
1080
+
1081
+ def test_un_token_inventado_tras_un_refresh_sigue_siendo_generico(client, contenedor):
1082
+ """Que la sesión haya rotado no vuelve «de una sesión anterior» a cualquier valor."""
1083
+ _alta(client)
1084
+ _sign_in_cookie(client)
1085
+ assert client.post("/auth/refresh", headers=_csrf_headers(client)).status_code == 200
1086
+
1087
+ r = _escribir(client, derive_csrf_token("00000000-0000-0000-0000-000000000000", CLAVE))
1088
+
1089
+ assert r.status_code == 403
1090
+ assert r.json()["code"] == CODIGO_INVALIDO
1091
+
1092
+
1093
+ def test_el_token_de_otra_cuenta_es_generico_no_de_sesion_anterior(client, contenedor):
1094
+ """Un token **válido** pero de otra familia no se reconoce como «de una sesión anterior»."""
1095
+ ajeno = TestClient(client.app, raise_server_exceptions=False)
1096
+ r = ajeno.post("/auth/sign-up", json={"email": "bea@test.com", "password": PASS})
1097
+ assert r.status_code == 201, r.text
1098
+ r = ajeno.post(
1099
+ "/auth/verify-email",
1100
+ json={"email": "bea@test.com", "code": r.json()["verification_code"]},
1101
+ )
1102
+ assert r.status_code == 200, r.text
1103
+ token_ajeno = ajeno.post(
1104
+ "/auth/sign-in",
1105
+ json={"email": "bea@test.com", "password": PASS},
1106
+ headers={"Origin": ORIGEN},
1107
+ ).headers[CSRF_HEADER]
1108
+
1109
+ # El alta y el sign-in tienen un límite de 5 por IP que comparten las dos cuentas del test.
1110
+ from hexcore.config import LazyConfig
1111
+ from hexcore.infrastructure.cache.cache_backends.memory import MemoryCache
1112
+
1113
+ LazyConfig.get_config().cache_backend = MemoryCache()
1114
+
1115
+ _alta(client)
1116
+ entrada = _sign_in_cookie(client)
1117
+ assert entrada.status_code == 200, entrada.text
1118
+ r = _escribir(client, token_ajeno)
1119
+
1120
+ assert r.status_code == 403
1121
+ assert r.json()["code"] == CODIGO_INVALIDO
1122
+
1123
+
1124
+ def test_sin_el_header_el_rechazo_tiene_el_code_generico(client, contenedor):
1125
+ _alta(client)
1126
+ _sign_in_cookie(client)
1127
+
1128
+ r = _escribir(client, None)
1129
+
1130
+ assert r.status_code == 403
1131
+ assert r.json()["code"] == CODIGO_INVALIDO
1132
+
1133
+
1134
+ def test_un_origen_ajeno_se_rechaza_sin_code(client, contenedor):
1135
+ """No es un problema del token: no hay nada que recuperar pidiendo otro."""
1136
+ _alta(client)
1137
+ _sign_in_cookie(client)
1138
+
1139
+ r = client.post(
1140
+ "/auth/sign-out",
1141
+ headers={"Origin": "https://evil.test", CSRF_HEADER: client.cookies.get("csrf") or ""},
1142
+ )
1143
+
1144
+ assert r.status_code == 403
1145
+ assert "code" not in r.json()
1146
+
1147
+
1148
+ def test_un_repositorio_sin_listado_de_familia_cae_al_code_generico(client, contenedor):
1149
+ """Un backend propio que no implementa el puerto nuevo no pierde el 403, sólo el `code`."""
1150
+ _alta(client)
1151
+ anterior = _sign_in_cookie(client).headers[CSRF_HEADER]
1152
+ assert client.post("/auth/refresh", headers=_csrf_headers(client)).status_code == 200
1153
+
1154
+ from hexcore.darwin.domain.ports import AbstractSessionRepository
1155
+
1156
+ repo = contenedor.sessions_repository()
1157
+ original = type(repo).list_family_session_ids
1158
+ type(repo).list_family_session_ids = AbstractSessionRepository.list_family_session_ids
1159
+ try:
1160
+ r = _escribir(client, anterior)
1161
+ finally:
1162
+ type(repo).list_family_session_ids = original
1163
+
1164
+ assert r.status_code == 403
1165
+ assert r.json()["code"] == CODIGO_INVALIDO
1166
+
1167
+
1168
+ def test_si_la_clasificacion_falla_el_rechazo_sigue_siendo_un_403(client, contenedor):
1169
+ """La lectura de la base es accesoria: si revienta nunca se convierte en un 500."""
1170
+ _alta(client)
1171
+ anterior = _sign_in_cookie(client).headers[CSRF_HEADER]
1172
+ assert client.post("/auth/refresh", headers=_csrf_headers(client)).status_code == 200
1173
+
1174
+ repo = contenedor.sessions_repository()
1175
+ original = type(repo).list_family_session_ids
1176
+
1177
+ async def _explota(self, family_id, *, limit=100):
1178
+ raise RuntimeError("la base no responde")
1179
+
1180
+ type(repo).list_family_session_ids = _explota
1181
+ try:
1182
+ r = _escribir(client, anterior)
1183
+ finally:
1184
+ type(repo).list_family_session_ids = original
1185
+
1186
+ assert r.status_code == 403
1187
+ assert r.json()["code"] == CODIGO_INVALIDO
1188
+
1189
+
1190
+ def test_el_token_vigente_sigue_pasando_tras_la_rotacion(client, contenedor):
1191
+ """La clasificación sólo corre al rechazar: el camino feliz no cambia."""
1192
+ _alta(client)
1193
+ _sign_in_cookie(client)
1194
+ assert client.post("/auth/refresh", headers=_csrf_headers(client)).status_code == 200
1195
+
1196
+ r = _escribir(client, client.cookies.get("csrf"))
1197
+
1198
+ assert r.status_code == 200, r.text
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes