tenantshield 0.7.0b0__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 (227) hide show
  1. tenantshield-0.7.0b0/.editorconfig +15 -0
  2. tenantshield-0.7.0b0/.gitattributes +37 -0
  3. tenantshield-0.7.0b0/.github/ISSUE_TEMPLATE/bug_report.yml +75 -0
  4. tenantshield-0.7.0b0/.github/ISSUE_TEMPLATE/config.yml +9 -0
  5. tenantshield-0.7.0b0/.github/ISSUE_TEMPLATE/feature_request.yml +41 -0
  6. tenantshield-0.7.0b0/.github/ISSUE_TEMPLATE/security_disclosure.md +22 -0
  7. tenantshield-0.7.0b0/.github/PULL_REQUEST_TEMPLATE.md +30 -0
  8. tenantshield-0.7.0b0/.github/dependabot.yml +22 -0
  9. tenantshield-0.7.0b0/.github/workflows/bench.yml +27 -0
  10. tenantshield-0.7.0b0/.github/workflows/ci.yml +79 -0
  11. tenantshield-0.7.0b0/.github/workflows/docs.yml +31 -0
  12. tenantshield-0.7.0b0/.github/workflows/pages-deploy.yml +48 -0
  13. tenantshield-0.7.0b0/.github/workflows/publish-pypi.yml +60 -0
  14. tenantshield-0.7.0b0/.github/workflows/publish-testpypi.yml +53 -0
  15. tenantshield-0.7.0b0/.github/workflows/security.yml +53 -0
  16. tenantshield-0.7.0b0/.gitignore +60 -0
  17. tenantshield-0.7.0b0/.pre-commit-config.yaml +50 -0
  18. tenantshield-0.7.0b0/.python-version +1 -0
  19. tenantshield-0.7.0b0/CHANGELOG.md +2186 -0
  20. tenantshield-0.7.0b0/CODE_OF_CONDUCT.md +83 -0
  21. tenantshield-0.7.0b0/CONTRIBUTING.md +74 -0
  22. tenantshield-0.7.0b0/LICENSE +201 -0
  23. tenantshield-0.7.0b0/PKG-INFO +356 -0
  24. tenantshield-0.7.0b0/README.md +294 -0
  25. tenantshield-0.7.0b0/SECURITY.md +33 -0
  26. tenantshield-0.7.0b0/docs/adapters/index.md +73 -0
  27. tenantshield-0.7.0b0/docs/adr/0001-commit-signing-deferral.md +80 -0
  28. tenantshield-0.7.0b0/docs/adr/0002-django-6-deferral.md +123 -0
  29. tenantshield-0.7.0b0/docs/adr/0003-django-4-2-empirical-support.md +136 -0
  30. tenantshield-0.7.0b0/docs/adr/0004-drf-stubs-empirical-support.md +162 -0
  31. tenantshield-0.7.0b0/docs/adr/0005-tight-upper-bounds-strategy.md +165 -0
  32. tenantshield-0.7.0b0/docs/adr/0006-sqlalchemy-2-0-only.md +160 -0
  33. tenantshield-0.7.0b0/docs/adr/0007-event-based-enforcement.md +216 -0
  34. tenantshield-0.7.0b0/docs/adr/0008-middleware-lifecycle-design.md +201 -0
  35. tenantshield-0.7.0b0/docs/adr/0009-async-session-adapter-architecture.md +240 -0
  36. tenantshield-0.7.0b0/docs/adr/0010-cross-adapter-strategy-unification.md +292 -0
  37. tenantshield-0.7.0b0/docs/adr/0011-observability-architecture.md +257 -0
  38. tenantshield-0.7.0b0/docs/adr/0012-audit-dual-pattern.md +257 -0
  39. tenantshield-0.7.0b0/docs/adr/0013-three-mode-read-write-semantics.md +289 -0
  40. tenantshield-0.7.0b0/docs/adr/0014-phase-6-retrospective.md +314 -0
  41. tenantshield-0.7.0b0/docs/api/index.md +24 -0
  42. tenantshield-0.7.0b0/docs/concepts/adopter-governance.md +99 -0
  43. tenantshield-0.7.0b0/docs/concepts/cross-adapter-parity.md +173 -0
  44. tenantshield-0.7.0b0/docs/concepts/index.md +57 -0
  45. tenantshield-0.7.0b0/docs/concepts/security-posture.md +207 -0
  46. tenantshield-0.7.0b0/docs/evidence/smoke_2b_middleware_output.md +266 -0
  47. tenantshield-0.7.0b0/docs/evidence/smoke_2c_premises.md +117 -0
  48. tenantshield-0.7.0b0/docs/getting-started.md +239 -0
  49. tenantshield-0.7.0b0/docs/index.md +25 -0
  50. tenantshield-0.7.0b0/docs/observability/async-middleware-migration.md +80 -0
  51. tenantshield-0.7.0b0/docs/observability/dual-pattern.md +79 -0
  52. tenantshield-0.7.0b0/docs/observability/integration/opentelemetry.md +69 -0
  53. tenantshield-0.7.0b0/docs/observability/integration/prometheus.md +81 -0
  54. tenantshield-0.7.0b0/docs/observability/production-checklist.md +59 -0
  55. tenantshield-0.7.0b0/docs/observability/quick-start.md +84 -0
  56. tenantshield-0.7.0b0/examples/01_django/README.md +227 -0
  57. tenantshield-0.7.0b0/examples/01_django/example_app/__init__.py +0 -0
  58. tenantshield-0.7.0b0/examples/01_django/example_app/apps.py +12 -0
  59. tenantshield-0.7.0b0/examples/01_django/example_app/migrations/__init__.py +0 -0
  60. tenantshield-0.7.0b0/examples/01_django/example_app/models.py +50 -0
  61. tenantshield-0.7.0b0/examples/01_django/example_app/serializers.py +47 -0
  62. tenantshield-0.7.0b0/examples/01_django/example_app/urls.py +23 -0
  63. tenantshield-0.7.0b0/examples/01_django/example_app/viewsets.py +41 -0
  64. tenantshield-0.7.0b0/examples/01_django/example_project/__init__.py +1 -0
  65. tenantshield-0.7.0b0/examples/01_django/example_project/asgi.py +11 -0
  66. tenantshield-0.7.0b0/examples/01_django/example_project/settings.py +70 -0
  67. tenantshield-0.7.0b0/examples/01_django/example_project/urls.py +9 -0
  68. tenantshield-0.7.0b0/examples/01_django/example_project/wsgi.py +11 -0
  69. tenantshield-0.7.0b0/examples/01_django/manage.py +26 -0
  70. tenantshield-0.7.0b0/examples/01_django/pyproject.toml +20 -0
  71. tenantshield-0.7.0b0/examples/02_sqlalchemy/README.md +52 -0
  72. tenantshield-0.7.0b0/examples/02_sqlalchemy/cli/README.md +63 -0
  73. tenantshield-0.7.0b0/examples/02_sqlalchemy/cli/cli.py +160 -0
  74. tenantshield-0.7.0b0/examples/02_sqlalchemy/cli/conftest.py +15 -0
  75. tenantshield-0.7.0b0/examples/02_sqlalchemy/cli/models.py +35 -0
  76. tenantshield-0.7.0b0/examples/02_sqlalchemy/cli/pyproject.toml +27 -0
  77. tenantshield-0.7.0b0/examples/02_sqlalchemy/cli/seed.py +58 -0
  78. tenantshield-0.7.0b0/examples/02_sqlalchemy/cli/tests/__init__.py +0 -0
  79. tenantshield-0.7.0b0/examples/02_sqlalchemy/cli/tests/test_cli.py +65 -0
  80. tenantshield-0.7.0b0/examples/02_sqlalchemy/fastapi/README.md +106 -0
  81. tenantshield-0.7.0b0/examples/02_sqlalchemy/fastapi/app.py +205 -0
  82. tenantshield-0.7.0b0/examples/02_sqlalchemy/fastapi/conftest.py +16 -0
  83. tenantshield-0.7.0b0/examples/02_sqlalchemy/fastapi/models.py +33 -0
  84. tenantshield-0.7.0b0/examples/02_sqlalchemy/fastapi/pyproject.toml +33 -0
  85. tenantshield-0.7.0b0/examples/02_sqlalchemy/fastapi/tests/__init__.py +0 -0
  86. tenantshield-0.7.0b0/examples/02_sqlalchemy/fastapi/tests/test_app.py +88 -0
  87. tenantshield-0.7.0b0/examples/02_sqlalchemy/flask/README.md +57 -0
  88. tenantshield-0.7.0b0/examples/02_sqlalchemy/flask/app.py +139 -0
  89. tenantshield-0.7.0b0/examples/02_sqlalchemy/flask/conftest.py +15 -0
  90. tenantshield-0.7.0b0/examples/02_sqlalchemy/flask/models.py +35 -0
  91. tenantshield-0.7.0b0/examples/02_sqlalchemy/flask/pyproject.toml +28 -0
  92. tenantshield-0.7.0b0/examples/02_sqlalchemy/flask/tests/__init__.py +0 -0
  93. tenantshield-0.7.0b0/examples/02_sqlalchemy/flask/tests/test_app.py +72 -0
  94. tenantshield-0.7.0b0/mkdocs.yml +69 -0
  95. tenantshield-0.7.0b0/pyproject.toml +193 -0
  96. tenantshield-0.7.0b0/src/tenantshield/__init__.py +119 -0
  97. tenantshield-0.7.0b0/src/tenantshield/_types.py +23 -0
  98. tenantshield-0.7.0b0/src/tenantshield/_version.py +3 -0
  99. tenantshield-0.7.0b0/src/tenantshield/adapters/__init__.py +11 -0
  100. tenantshield-0.7.0b0/src/tenantshield/adapters/django/__init__.py +33 -0
  101. tenantshield-0.7.0b0/src/tenantshield/adapters/django/admin.py +58 -0
  102. tenantshield-0.7.0b0/src/tenantshield/adapters/django/apps.py +31 -0
  103. tenantshield-0.7.0b0/src/tenantshield/adapters/django/checks.py +180 -0
  104. tenantshield-0.7.0b0/src/tenantshield/adapters/django/decorators.py +176 -0
  105. tenantshield-0.7.0b0/src/tenantshield/adapters/django/exceptions.py +47 -0
  106. tenantshield-0.7.0b0/src/tenantshield/adapters/django/managers.py +429 -0
  107. tenantshield-0.7.0b0/src/tenantshield/adapters/django/middleware/__init__.py +155 -0
  108. tenantshield-0.7.0b0/src/tenantshield/adapters/django/middleware/strategies/__init__.py +113 -0
  109. tenantshield-0.7.0b0/src/tenantshield/adapters/django/middleware/strategies/_request_adapter.py +51 -0
  110. tenantshield-0.7.0b0/src/tenantshield/adapters/django/middleware/strategies/base.py +53 -0
  111. tenantshield-0.7.0b0/src/tenantshield/adapters/django/middleware/strategies/callable_.py +84 -0
  112. tenantshield-0.7.0b0/src/tenantshield/adapters/django/middleware/strategies/header.py +80 -0
  113. tenantshield-0.7.0b0/src/tenantshield/adapters/django/middleware/strategies/jwt.py +104 -0
  114. tenantshield-0.7.0b0/src/tenantshield/adapters/django/middleware/strategies/subdomain.py +66 -0
  115. tenantshield-0.7.0b0/src/tenantshield/adapters/django/migrations.py +94 -0
  116. tenantshield-0.7.0b0/src/tenantshield/adapters/django/scope.py +56 -0
  117. tenantshield-0.7.0b0/src/tenantshield/adapters/django/signals.py +185 -0
  118. tenantshield-0.7.0b0/src/tenantshield/adapters/drf/__init__.py +25 -0
  119. tenantshield-0.7.0b0/src/tenantshield/adapters/drf/exceptions.py +41 -0
  120. tenantshield-0.7.0b0/src/tenantshield/adapters/drf/mixins.py +101 -0
  121. tenantshield-0.7.0b0/src/tenantshield/adapters/drf/permissions.py +72 -0
  122. tenantshield-0.7.0b0/src/tenantshield/adapters/drf/serializers.py +196 -0
  123. tenantshield-0.7.0b0/src/tenantshield/adapters/sqlalchemy/__init__.py +132 -0
  124. tenantshield-0.7.0b0/src/tenantshield/adapters/sqlalchemy/_request_adapter.py +89 -0
  125. tenantshield-0.7.0b0/src/tenantshield/adapters/sqlalchemy/async_lifecycle.py +269 -0
  126. tenantshield-0.7.0b0/src/tenantshield/adapters/sqlalchemy/decorator.py +153 -0
  127. tenantshield-0.7.0b0/src/tenantshield/adapters/sqlalchemy/events.py +448 -0
  128. tenantshield-0.7.0b0/src/tenantshield/adapters/sqlalchemy/exceptions.py +21 -0
  129. tenantshield-0.7.0b0/src/tenantshield/adapters/sqlalchemy/lifecycle.py +235 -0
  130. tenantshield-0.7.0b0/src/tenantshield/adapters/sqlalchemy/middleware.py +592 -0
  131. tenantshield-0.7.0b0/src/tenantshield/adapters/sqlalchemy/migrations.py +87 -0
  132. tenantshield-0.7.0b0/src/tenantshield/adapters/sqlalchemy/scopes.py +72 -0
  133. tenantshield-0.7.0b0/src/tenantshield/audit.py +229 -0
  134. tenantshield-0.7.0b0/src/tenantshield/context.py +157 -0
  135. tenantshield-0.7.0b0/src/tenantshield/exceptions.py +237 -0
  136. tenantshield-0.7.0b0/src/tenantshield/observability/__init__.py +45 -0
  137. tenantshield-0.7.0b0/src/tenantshield/observability/_emit.py +37 -0
  138. tenantshield-0.7.0b0/src/tenantshield/observability/config.py +39 -0
  139. tenantshield-0.7.0b0/src/tenantshield/observability/events.py +39 -0
  140. tenantshield-0.7.0b0/src/tenantshield/policies.py +243 -0
  141. tenantshield-0.7.0b0/src/tenantshield/py.typed +0 -0
  142. tenantshield-0.7.0b0/src/tenantshield/registry.py +193 -0
  143. tenantshield-0.7.0b0/src/tenantshield/strategies/__init__.py +66 -0
  144. tenantshield-0.7.0b0/src/tenantshield/strategies/_resolver.py +125 -0
  145. tenantshield-0.7.0b0/src/tenantshield/strategies/base.py +120 -0
  146. tenantshield-0.7.0b0/src/tenantshield/strategies/callable_.py +58 -0
  147. tenantshield-0.7.0b0/src/tenantshield/strategies/header.py +41 -0
  148. tenantshield-0.7.0b0/src/tenantshield/strategies/host.py +52 -0
  149. tenantshield-0.7.0b0/src/tenantshield/strategies/jwt.py +110 -0
  150. tenantshield-0.7.0b0/tests/__init__.py +0 -0
  151. tenantshield-0.7.0b0/tests/conftest.py +61 -0
  152. tenantshield-0.7.0b0/tests/integration/__init__.py +0 -0
  153. tenantshield-0.7.0b0/tests/integration/django/__init__.py +0 -0
  154. tenantshield-0.7.0b0/tests/integration/django/conftest.py +52 -0
  155. tenantshield-0.7.0b0/tests/integration/django/settings.py +38 -0
  156. tenantshield-0.7.0b0/tests/integration/django/test_admin.py +51 -0
  157. tenantshield-0.7.0b0/tests/integration/django/test_checks.py +55 -0
  158. tenantshield-0.7.0b0/tests/integration/django/test_cross_tenant_audit.py +280 -0
  159. tenantshield-0.7.0b0/tests/integration/django/test_decorator.py +58 -0
  160. tenantshield-0.7.0b0/tests/integration/django/test_drf.py +418 -0
  161. tenantshield-0.7.0b0/tests/integration/django/test_dx_sugar.py +81 -0
  162. tenantshield-0.7.0b0/tests/integration/django/test_fk_auto_propagation.py +140 -0
  163. tenantshield-0.7.0b0/tests/integration/django/test_manager.py +65 -0
  164. tenantshield-0.7.0b0/tests/integration/django/test_middleware.py +241 -0
  165. tenantshield-0.7.0b0/tests/integration/django/test_middleware_checks.py +153 -0
  166. tenantshield-0.7.0b0/tests/integration/django/test_migrations_metadata.py +52 -0
  167. tenantshield-0.7.0b0/tests/integration/django/test_queryset.py +81 -0
  168. tenantshield-0.7.0b0/tests/integration/django/test_request_adapter.py +55 -0
  169. tenantshield-0.7.0b0/tests/integration/django/test_signals.py +73 -0
  170. tenantshield-0.7.0b0/tests/integration/django/test_signals_bench.py +73 -0
  171. tenantshield-0.7.0b0/tests/integration/django/test_strategies.py +296 -0
  172. tenantshield-0.7.0b0/tests/integration/django/test_unsafe_unscoped.py +228 -0
  173. tenantshield-0.7.0b0/tests/integration/django/testapp/__init__.py +0 -0
  174. tenantshield-0.7.0b0/tests/integration/django/testapp/apps.py +9 -0
  175. tenantshield-0.7.0b0/tests/integration/django/testapp/models.py +89 -0
  176. tenantshield-0.7.0b0/tests/integration/django/testapp/serializers.py +25 -0
  177. tenantshield-0.7.0b0/tests/integration/django/testapp/urls.py +31 -0
  178. tenantshield-0.7.0b0/tests/integration/django/testapp/views.py +64 -0
  179. tenantshield-0.7.0b0/tests/integration/django/testapp/viewsets.py +27 -0
  180. tenantshield-0.7.0b0/tests/integration/examples/__init__.py +0 -0
  181. tenantshield-0.7.0b0/tests/integration/examples/test_01_django.py +84 -0
  182. tenantshield-0.7.0b0/tests/integration/test_cross_adapter_strategies.py +190 -0
  183. tenantshield-0.7.0b0/tests/integration/test_sqlalchemy_middleware_async_fastapi.py +114 -0
  184. tenantshield-0.7.0b0/tests/unit/__init__.py +0 -0
  185. tenantshield-0.7.0b0/tests/unit/test_audit_bench.py +78 -0
  186. tenantshield-0.7.0b0/tests/unit/test_audit_bus.py +219 -0
  187. tenantshield-0.7.0b0/tests/unit/test_audit_concurrency.py +115 -0
  188. tenantshield-0.7.0b0/tests/unit/test_audit_sinks.py +100 -0
  189. tenantshield-0.7.0b0/tests/unit/test_audit_types.py +75 -0
  190. tenantshield-0.7.0b0/tests/unit/test_context_async.py +107 -0
  191. tenantshield-0.7.0b0/tests/unit/test_context_audit_integration.py +101 -0
  192. tenantshield-0.7.0b0/tests/unit/test_context_bench.py +65 -0
  193. tenantshield-0.7.0b0/tests/unit/test_context_properties.py +95 -0
  194. tenantshield-0.7.0b0/tests/unit/test_context_sync.py +93 -0
  195. tenantshield-0.7.0b0/tests/unit/test_exceptions.py +218 -0
  196. tenantshield-0.7.0b0/tests/unit/test_observability_audit_dual_dispatch.py +230 -0
  197. tenantshield-0.7.0b0/tests/unit/test_observability_enforcement_events.py +240 -0
  198. tenantshield-0.7.0b0/tests/unit/test_observability_middleware_events.py +250 -0
  199. tenantshield-0.7.0b0/tests/unit/test_observability_module.py +104 -0
  200. tenantshield-0.7.0b0/tests/unit/test_observability_scope_events.py +167 -0
  201. tenantshield-0.7.0b0/tests/unit/test_policies.py +262 -0
  202. tenantshield-0.7.0b0/tests/unit/test_policies_properties.py +135 -0
  203. tenantshield-0.7.0b0/tests/unit/test_registry_class.py +146 -0
  204. tenantshield-0.7.0b0/tests/unit/test_registry_concurrency.py +39 -0
  205. tenantshield-0.7.0b0/tests/unit/test_registry_default.py +115 -0
  206. tenantshield-0.7.0b0/tests/unit/test_registry_properties.py +49 -0
  207. tenantshield-0.7.0b0/tests/unit/test_smoke.py +126 -0
  208. tenantshield-0.7.0b0/tests/unit/test_sqlalchemy_async_lifecycle.py +231 -0
  209. tenantshield-0.7.0b0/tests/unit/test_sqlalchemy_async_mapper_events.py +213 -0
  210. tenantshield-0.7.0b0/tests/unit/test_sqlalchemy_async_orm_execute.py +221 -0
  211. tenantshield-0.7.0b0/tests/unit/test_sqlalchemy_async_sync_coexistence.py +207 -0
  212. tenantshield-0.7.0b0/tests/unit/test_sqlalchemy_bulk_operations.py +190 -0
  213. tenantshield-0.7.0b0/tests/unit/test_sqlalchemy_decorator.py +97 -0
  214. tenantshield-0.7.0b0/tests/unit/test_sqlalchemy_events.py +350 -0
  215. tenantshield-0.7.0b0/tests/unit/test_sqlalchemy_flush_commit_timing.py +179 -0
  216. tenantshield-0.7.0b0/tests/unit/test_sqlalchemy_lifecycle.py +263 -0
  217. tenantshield-0.7.0b0/tests/unit/test_sqlalchemy_middleware_asgi.py +426 -0
  218. tenantshield-0.7.0b0/tests/unit/test_sqlalchemy_middleware_async_asgi.py +283 -0
  219. tenantshield-0.7.0b0/tests/unit/test_sqlalchemy_middleware_wsgi.py +250 -0
  220. tenantshield-0.7.0b0/tests/unit/test_sqlalchemy_migrations_metadata.py +63 -0
  221. tenantshield-0.7.0b0/tests/unit/test_sqlalchemy_nested_transactions.py +276 -0
  222. tenantshield-0.7.0b0/tests/unit/test_sqlalchemy_raw_sql.py +181 -0
  223. tenantshield-0.7.0b0/tests/unit/test_sqlalchemy_request_adapter.py +105 -0
  224. tenantshield-0.7.0b0/tests/unit/test_sqlalchemy_tenant_scope_for_model.py +54 -0
  225. tenantshield-0.7.0b0/tests/unit/test_strategies.py +278 -0
  226. tenantshield-0.7.0b0/tests/unit/test_types.py +22 -0
  227. tenantshield-0.7.0b0/uv.lock +1944 -0
@@ -0,0 +1,15 @@
1
+ root = true
2
+
3
+ [*]
4
+ indent_style = space
5
+ indent_size = 4
6
+ end_of_line = lf
7
+ charset = utf-8
8
+ trim_trailing_whitespace = true
9
+ insert_final_newline = true
10
+
11
+ [*.{yml,yaml,toml,json}]
12
+ indent_size = 2
13
+
14
+ [*.md]
15
+ trim_trailing_whitespace = false
@@ -0,0 +1,37 @@
1
+ # Normalize line endings: LF in repo, platform-appropriate on checkout
2
+ * text=auto eol=lf
3
+
4
+ # Explicit text files
5
+ *.py text eol=lf
6
+ *.pyi text eol=lf
7
+ *.toml text eol=lf
8
+ *.yaml text eol=lf
9
+ *.yml text eol=lf
10
+ *.json text eol=lf
11
+ *.md text eol=lf
12
+ *.txt text eol=lf
13
+ *.cfg text eol=lf
14
+ *.ini text eol=lf
15
+ *.sh text eol=lf
16
+ *.env text eol=lf
17
+ .gitignore text eol=lf
18
+ .gitattributes text eol=lf
19
+ .editorconfig text eol=lf
20
+ LICENSE text eol=lf
21
+
22
+ # Windows-native scripts keep CRLF
23
+ *.ps1 text eol=crlf
24
+ *.bat text eol=crlf
25
+ *.cmd text eol=crlf
26
+
27
+ # Binary
28
+ *.png binary
29
+ *.jpg binary
30
+ *.jpeg binary
31
+ *.gif binary
32
+ *.ico binary
33
+ *.pdf binary
34
+ *.zip binary
35
+ *.tar.gz binary
36
+ *.whl binary
37
+ *.pyc binary
@@ -0,0 +1,75 @@
1
+ name: Bug report
2
+ description: Report a defect in TenantShield.
3
+ title: "[Bug]: "
4
+ labels: ["bug", "needs-triage"]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: |
9
+ Thanks for taking the time to file a bug report. Before you submit:
10
+
11
+ - Do not include real tenant data, credentials, secrets, or production
12
+ identifiers in this report. Replace anything sensitive with a
13
+ placeholder such as `<TENANT_ID>` or `<API_KEY>`.
14
+ - If you believe this is a security vulnerability, do not file a public
15
+ issue. Follow the procedure in `SECURITY.md` instead.
16
+
17
+ - type: textarea
18
+ id: description
19
+ attributes:
20
+ label: What happened?
21
+ description: A clear, concise description of the bug.
22
+ validations:
23
+ required: true
24
+
25
+ - type: textarea
26
+ id: expected
27
+ attributes:
28
+ label: What did you expect to happen?
29
+ validations:
30
+ required: true
31
+
32
+ - type: textarea
33
+ id: reproduction
34
+ attributes:
35
+ label: Minimal reproduction
36
+ description: Steps or a minimal code snippet that reproduces the issue.
37
+ render: python
38
+ validations:
39
+ required: true
40
+
41
+ - type: input
42
+ id: version
43
+ attributes:
44
+ label: TenantShield version
45
+ placeholder: "0.0.1a0"
46
+ validations:
47
+ required: true
48
+
49
+ - type: dropdown
50
+ id: framework
51
+ attributes:
52
+ label: Framework
53
+ options:
54
+ - Django
55
+ - SQLAlchemy
56
+ - Celery
57
+ - DRF
58
+ - Core / None of the above
59
+ validations:
60
+ required: true
61
+
62
+ - type: input
63
+ id: python_version
64
+ attributes:
65
+ label: Python version
66
+ placeholder: "3.13.0"
67
+ validations:
68
+ required: true
69
+
70
+ - type: textarea
71
+ id: logs
72
+ attributes:
73
+ label: Relevant logs or stack trace
74
+ description: Paste any structured log entries or traceback related to the bug.
75
+ render: text
@@ -0,0 +1,9 @@
1
+ blank_issues_enabled: false
2
+
3
+ contact_links:
4
+ - name: Security Vulnerability Disclosure
5
+ url: https://github.com/Jhoelperaltap/tenantshield/blob/main/SECURITY.md
6
+ about: For security issues, please email security@ejsupportit.com privately. Do NOT use public issues.
7
+ - name: Documentation
8
+ url: https://jhoelperaltap.github.io/tenantshield/
9
+ about: Check the official documentation site for guides, ADRs, and API reference.
@@ -0,0 +1,41 @@
1
+ name: Feature request
2
+ description: Propose a new feature or enhancement.
3
+ title: "[Feature]: "
4
+ labels: ["enhancement", "needs-triage"]
5
+ body:
6
+ - type: textarea
7
+ id: problem
8
+ attributes:
9
+ label: What problem does this solve?
10
+ description: Describe the user-facing problem or limitation this feature addresses.
11
+ validations:
12
+ required: true
13
+
14
+ - type: textarea
15
+ id: proposal
16
+ attributes:
17
+ label: Proposed solution or API sketch
18
+ description: A rough proposal. Code snippets or API shapes welcome.
19
+ validations:
20
+ required: true
21
+
22
+ - type: textarea
23
+ id: alternatives
24
+ attributes:
25
+ label: Alternatives considered
26
+ description: Other approaches you considered and why they were not chosen.
27
+
28
+ - type: dropdown
29
+ id: scope
30
+ attributes:
31
+ label: Scope
32
+ options:
33
+ - Core engine
34
+ - Django adapter
35
+ - SQLAlchemy adapter
36
+ - Celery adapter
37
+ - DRF integration
38
+ - Tooling / CI
39
+ - Documentation
40
+ validations:
41
+ required: true
@@ -0,0 +1,22 @@
1
+ ---
2
+ name: Security Vulnerability
3
+ about: For security issues, please DO NOT use GitHub issues
4
+ title: ""
5
+ labels: []
6
+ ---
7
+
8
+ ## ⚠️ STOP — Security issues require private disclosure
9
+
10
+ **Do NOT report security vulnerabilities via public GitHub issues.**
11
+
12
+ Security vulnerabilities should be reported privately to:
13
+
14
+ **security@ejsupportit.com**
15
+
16
+ Please see [SECURITY.md](../SECURITY.md) for our security disclosure policy, including:
17
+
18
+ - What to include in your report
19
+ - Expected response timeline (initial acknowledgement within 72 hours)
20
+ - Coordinated disclosure process
21
+
22
+ If you continue and submit this template publicly, your issue **will be closed and redacted**.
@@ -0,0 +1,30 @@
1
+ ## Summary
2
+
3
+ <!-- One paragraph describing what this PR does and why. -->
4
+
5
+ ## Type of change
6
+
7
+ - [ ] feat — new feature
8
+ - [ ] fix — bug fix
9
+ - [ ] docs — documentation only
10
+ - [ ] test — adding or correcting tests
11
+ - [ ] refactor — code change that neither fixes a bug nor adds a feature
12
+ - [ ] perf — performance improvement
13
+ - [ ] chore — tooling, config, or maintenance
14
+ - [ ] build — build system or dependencies
15
+ - [ ] ci — continuous integration
16
+
17
+ ## Checklist
18
+
19
+ - [ ] Tests added or updated, and passing locally (`uv run pytest`).
20
+ - [ ] Type checks pass (`uv run mypy src/tenantshield` and `uv run pyright src/tenantshield`).
21
+ - [ ] Lint and format pass (`uv run pre-commit run --all-files`).
22
+ - [ ] Coverage has not decreased.
23
+ - [ ] `CHANGELOG.md` updated under `[Unreleased]`.
24
+ - [ ] Documentation updated if applicable.
25
+ - [ ] No `TODO` without an associated issue number.
26
+ - [ ] PR is under 400 lines of net change, or a justification is provided.
27
+
28
+ ## Related issues
29
+
30
+ <!-- Closes #N, Refs #N, etc. -->
@@ -0,0 +1,22 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "uv"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
7
+ open-pull-requests-limit: 5
8
+ commit-message:
9
+ prefix: "build"
10
+ prefix-development: "build"
11
+ include: "scope"
12
+ labels: ["dependencies", "python"]
13
+
14
+ - package-ecosystem: "github-actions"
15
+ directory: "/"
16
+ schedule:
17
+ interval: "weekly"
18
+ open-pull-requests-limit: 5
19
+ commit-message:
20
+ prefix: "ci"
21
+ include: "scope"
22
+ labels: ["dependencies", "github-actions"]
@@ -0,0 +1,27 @@
1
+ name: bench
2
+
3
+ on:
4
+ pull_request:
5
+ branches: [main]
6
+ push:
7
+ branches: [main]
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ bench:
14
+ name: bench
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - uses: actions/checkout@v6
18
+ - uses: astral-sh/setup-uv@v8.1.0
19
+ with:
20
+ enable-cache: true
21
+ cache-dependency-glob: "uv.lock"
22
+ python-version: "3.13"
23
+ - run: uv sync --all-extras --dev
24
+ - name: Run benchmarks (slow markers, strict mode)
25
+ run: uv run pytest -m slow -v --no-cov
26
+ env:
27
+ TENANTSHIELD_BENCH_STRICT: "1"
@@ -0,0 +1,79 @@
1
+ name: ci
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ concurrency:
10
+ group: ci-${{ github.workflow }}-${{ github.ref }}
11
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
12
+
13
+ permissions:
14
+ contents: read
15
+
16
+ jobs:
17
+ lint:
18
+ name: lint
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - uses: actions/checkout@v6
22
+ - uses: astral-sh/setup-uv@v8.1.0
23
+ with:
24
+ enable-cache: true
25
+ cache-dependency-glob: "uv.lock"
26
+ python-version: "3.13"
27
+ - run: uv sync --all-extras --dev
28
+ - run: uv run ruff check .
29
+ - run: uv run ruff format --check .
30
+
31
+ typecheck:
32
+ name: typecheck
33
+ runs-on: ubuntu-latest
34
+ steps:
35
+ - uses: actions/checkout@v6
36
+ - uses: astral-sh/setup-uv@v8.1.0
37
+ with:
38
+ enable-cache: true
39
+ cache-dependency-glob: "uv.lock"
40
+ python-version: "3.13"
41
+ - run: uv sync --all-extras --dev
42
+ - run: uv run mypy src/tenantshield
43
+ - run: uv run pyright src/tenantshield
44
+
45
+ test:
46
+ name: test (py${{ matrix.python-version }}, django${{ matrix.django-version }})
47
+ runs-on: ubuntu-latest
48
+ strategy:
49
+ fail-fast: false
50
+ matrix:
51
+ python-version: ["3.11", "3.12", "3.13", "3.14"]
52
+ django-version: ["4.2", "5.2", "6.0"]
53
+ exclude:
54
+ # Django 6.0 requires Python >=3.12; py3.11 combination is
55
+ # unsatisfiable.
56
+ - python-version: "3.11"
57
+ django-version: "6.0"
58
+ # Django 4.2 LTS predates Python 3.14; django/template/context.py:39
59
+ # raises AttributeError on Python 3.14's super() / __dict__ semantics.
60
+ # Upstream issue (not TenantShield code; 10/11 matrix cells pass).
61
+ # See ADR-0003: Django 4.2 LTS commitment preserved for py3.11-3.13.
62
+ - python-version: "3.14"
63
+ django-version: "4.2"
64
+ steps:
65
+ - uses: actions/checkout@v6
66
+ - uses: astral-sh/setup-uv@v8.1.0
67
+ with:
68
+ enable-cache: true
69
+ cache-dependency-glob: "uv.lock"
70
+ python-version: ${{ matrix.python-version }}
71
+ - run: uv sync --all-extras --dev
72
+ - run: uv pip install "django==${{ matrix.django-version }}.*"
73
+ - run: uv run pytest
74
+ - uses: actions/upload-artifact@v7
75
+ if: always()
76
+ with:
77
+ name: coverage-py${{ matrix.python-version }}-django${{ matrix.django-version }}
78
+ path: coverage.xml
79
+ retention-days: 7
@@ -0,0 +1,31 @@
1
+ name: docs
2
+
3
+ on:
4
+ pull_request:
5
+ branches: [main]
6
+ paths:
7
+ - 'docs/**'
8
+ - 'mkdocs.yml'
9
+ - 'src/tenantshield/**'
10
+ push:
11
+ branches: [main]
12
+ paths:
13
+ - 'docs/**'
14
+ - 'mkdocs.yml'
15
+ - 'src/tenantshield/**'
16
+
17
+ permissions:
18
+ contents: read
19
+
20
+ jobs:
21
+ build:
22
+ runs-on: ubuntu-latest
23
+ steps:
24
+ - uses: actions/checkout@v6
25
+ - uses: astral-sh/setup-uv@v8.1.0
26
+ with:
27
+ enable-cache: true
28
+ cache-dependency-glob: "uv.lock"
29
+ python-version: "3.13"
30
+ - run: uv sync --all-extras --dev
31
+ - run: uv run mkdocs build --strict
@@ -0,0 +1,48 @@
1
+ name: Deploy MkDocs to GitHub Pages
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ paths:
7
+ - 'docs/**'
8
+ - 'mkdocs.yml'
9
+ - 'README.md'
10
+ - '.github/workflows/pages-deploy.yml'
11
+ workflow_dispatch:
12
+
13
+ permissions:
14
+ contents: read
15
+ pages: write
16
+ id-token: write
17
+
18
+ concurrency:
19
+ group: pages
20
+ cancel-in-progress: false
21
+
22
+ jobs:
23
+ build:
24
+ name: Build MkDocs site
25
+ runs-on: ubuntu-latest
26
+ steps:
27
+ - uses: actions/checkout@v6
28
+ - uses: astral-sh/setup-uv@v8.1.0
29
+ with:
30
+ enable-cache: true
31
+ cache-dependency-glob: "uv.lock"
32
+ python-version: "3.13"
33
+ - run: uv sync --all-extras --dev
34
+ - run: uv run mkdocs build --strict
35
+ - uses: actions/upload-pages-artifact@v3
36
+ with:
37
+ path: site/
38
+
39
+ deploy:
40
+ name: Deploy to GitHub Pages
41
+ needs: build
42
+ runs-on: ubuntu-latest
43
+ environment:
44
+ name: github-pages
45
+ url: ${{ steps.deployment.outputs.page_url }}
46
+ steps:
47
+ - id: deployment
48
+ uses: actions/deploy-pages@v4
@@ -0,0 +1,60 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+
8
+ # Trusted Publishing via OIDC; no PyPI API token in repository secrets.
9
+ # Setup (one-time, browser):
10
+ # 1. Register a pending publisher at
11
+ # https://pypi.org/manage/account/publishing/ with:
12
+ # - PyPI project name: tenantshield
13
+ # - Owner: Jhoelperaltap
14
+ # - Repository name: tenantshield
15
+ # - Workflow filename: publish-pypi.yml
16
+ # - Environment name: pypi
17
+ # 2. In GitHub repo Settings -> Environments, create environment "pypi".
18
+ # (Optional: add required reviewers if you want a manual gate before
19
+ # every public publish; without reviewers it auto-publishes on tag push.)
20
+ permissions:
21
+ contents: read
22
+ id-token: write
23
+
24
+ jobs:
25
+ build:
26
+ name: Build distributions
27
+ runs-on: ubuntu-latest
28
+ steps:
29
+ - uses: actions/checkout@v6
30
+ with:
31
+ fetch-depth: 0
32
+ - uses: astral-sh/setup-uv@v8.1.0
33
+ with:
34
+ enable-cache: true
35
+ cache-dependency-glob: "uv.lock"
36
+ python-version: "3.13"
37
+ - run: uv sync --all-extras --dev
38
+ - run: uv build
39
+ - uses: actions/upload-artifact@v7
40
+ with:
41
+ name: dist-pypi
42
+ path: dist/
43
+ retention-days: 7
44
+
45
+ publish-pypi:
46
+ name: Publish to PyPI
47
+ needs: build
48
+ runs-on: ubuntu-latest
49
+ environment:
50
+ name: pypi
51
+ url: https://pypi.org/project/tenantshield/
52
+ steps:
53
+ - uses: actions/download-artifact@v5
54
+ with:
55
+ name: dist-pypi
56
+ path: dist/
57
+ - name: Publish distributions to PyPI
58
+ uses: pypa/gh-action-pypi-publish@release/v1
59
+ with:
60
+ skip-existing: true
@@ -0,0 +1,53 @@
1
+ name: Publish to TestPyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+
8
+ # Trusted Publishing via OIDC; no PyPI API token in repository secrets.
9
+ # Setup: register a pending publisher at
10
+ # https://test.pypi.org/manage/account/publishing/ with the workflow
11
+ # filename above and repository "Jhoelperaltap/tenantshield".
12
+ permissions:
13
+ contents: read
14
+ id-token: write
15
+
16
+ jobs:
17
+ build:
18
+ name: Build distributions
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - uses: actions/checkout@v6
22
+ with:
23
+ fetch-depth: 0
24
+ - uses: astral-sh/setup-uv@v8.1.0
25
+ with:
26
+ enable-cache: true
27
+ cache-dependency-glob: "uv.lock"
28
+ python-version: "3.13"
29
+ - run: uv sync --all-extras --dev
30
+ - run: uv build
31
+ - uses: actions/upload-artifact@v7
32
+ with:
33
+ name: dist
34
+ path: dist/
35
+ retention-days: 7
36
+
37
+ publish-testpypi:
38
+ name: Publish to TestPyPI
39
+ needs: build
40
+ runs-on: ubuntu-latest
41
+ environment:
42
+ name: testpypi
43
+ url: https://test.pypi.org/project/tenantshield/
44
+ steps:
45
+ - uses: actions/download-artifact@v5
46
+ with:
47
+ name: dist
48
+ path: dist/
49
+ - name: Publish distributions to TestPyPI
50
+ uses: pypa/gh-action-pypi-publish@release/v1
51
+ with:
52
+ repository-url: https://test.pypi.org/legacy/
53
+ skip-existing: true
@@ -0,0 +1,53 @@
1
+ name: security
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+ schedule:
9
+ - cron: "0 6 * * 1"
10
+
11
+ permissions:
12
+ contents: read
13
+
14
+ jobs:
15
+ bandit:
16
+ name: bandit
17
+ runs-on: ubuntu-latest
18
+ steps:
19
+ - uses: actions/checkout@v6
20
+ - uses: astral-sh/setup-uv@v8.1.0
21
+ with:
22
+ enable-cache: true
23
+ cache-dependency-glob: "uv.lock"
24
+ python-version: "3.13"
25
+ - run: uv sync --all-extras --dev
26
+ - run: uv run bandit -c pyproject.toml -r src/
27
+
28
+ pip-audit:
29
+ name: pip-audit
30
+ runs-on: ubuntu-latest
31
+ steps:
32
+ - uses: actions/checkout@v6
33
+ - uses: astral-sh/setup-uv@v8.1.0
34
+ with:
35
+ enable-cache: true
36
+ cache-dependency-glob: "uv.lock"
37
+ python-version: "3.13"
38
+ - run: uv sync --all-extras --dev
39
+ - run: uv run pip-audit
40
+
41
+ codeql:
42
+ name: codeql
43
+ runs-on: ubuntu-latest
44
+ permissions:
45
+ actions: read
46
+ contents: read
47
+ security-events: write
48
+ steps:
49
+ - uses: actions/checkout@v6
50
+ - uses: github/codeql-action/init@v4
51
+ with:
52
+ languages: python
53
+ - uses: github/codeql-action/analyze@v4
@@ -0,0 +1,60 @@
1
+ # Byte-compiled / cached
2
+ __pycache__/
3
+ *.pyc
4
+ *.pyo
5
+
6
+ # Distribution / packaging
7
+ *.egg-info/
8
+ build/
9
+ dist/
10
+
11
+ # Virtual environments
12
+ .venv/
13
+ venv/
14
+ .env
15
+ .envrc
16
+
17
+ # Tooling caches
18
+ .pytest_cache/
19
+ .mypy_cache/
20
+ .ruff_cache/
21
+ .tox/
22
+ .nox/
23
+ .hypothesis/
24
+
25
+ # Coverage
26
+ htmlcov/
27
+ .coverage
28
+ coverage.xml
29
+ *.cover
30
+
31
+ # IDE / OS
32
+ .idea/
33
+ .vscode/
34
+ .DS_Store
35
+ Thumbs.db
36
+
37
+ # Documentation build output
38
+ site/
39
+
40
+ # Agent / local-only artifacts (not part of the project)
41
+ CLAUDE.md
42
+ PHASE_*_KICKOFF.md
43
+ PHASE_*_CLOSURE.md
44
+ TENANTSHIELD_ROADMAP.md
45
+ _scratch_*
46
+ .claude/
47
+ .aider*
48
+ .cursor*
49
+ .continue/
50
+ *.local.md
51
+
52
+ # Django runtime artifacts (for examples/)
53
+ *.sqlite3
54
+ *.sqlite3-journal
55
+ examples/*/staticfiles/
56
+ examples/*/media/
57
+ examples/*/local_settings.py
58
+
59
+ # Examples lockfiles (each example resolves locally; Phase 2 precedent)
60
+ examples/**/uv.lock