adminA 0.15.2__tar.gz → 0.15.4__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 (313) hide show
  1. {admina-0.15.2/admina.egg-info → admina-0.15.4}/PKG-INFO +28 -4
  2. {admina-0.15.2 → admina-0.15.4}/README.md +24 -1
  3. {admina-0.15.2 → admina-0.15.4}/admina/__init__.py +1 -1
  4. {admina-0.15.2 → admina-0.15.4}/admina/cli/main.py +2 -1
  5. {admina-0.15.2 → admina-0.15.4}/admina/core/config.py +1 -1
  6. {admina-0.15.2 → admina-0.15.4}/admina/proxy/main.py +13 -0
  7. {admina-0.15.2 → admina-0.15.4/admina.egg-info}/PKG-INFO +28 -4
  8. {admina-0.15.2 → admina-0.15.4}/admina.egg-info/SOURCES.txt +1 -0
  9. {admina-0.15.2 → admina-0.15.4}/admina.egg-info/requires.txt +2 -2
  10. {admina-0.15.2 → admina-0.15.4}/pyproject.toml +11 -6
  11. {admina-0.15.2 → admina-0.15.4}/tests/test_enabled_surfaces.py +4 -2
  12. admina-0.15.4/tests/test_fastapi_telemetry.py +68 -0
  13. {admina-0.15.2 → admina-0.15.4}/tests/test_gateway_scan_coverage.py +30 -11
  14. {admina-0.15.2 → admina-0.15.4}/tests/test_lazy_imports.py +5 -2
  15. {admina-0.15.2 → admina-0.15.4}/LICENSE +0 -0
  16. {admina-0.15.2 → admina-0.15.4}/NOTICE +0 -0
  17. {admina-0.15.2 → admina-0.15.4}/admina/cli/__init__.py +0 -0
  18. {admina-0.15.2 → admina-0.15.4}/admina/cli/commands/__init__.py +0 -0
  19. {admina-0.15.2 → admina-0.15.4}/admina/cli/forensic.py +0 -0
  20. {admina-0.15.2 → admina-0.15.4}/admina/cli/redteam.py +0 -0
  21. {admina-0.15.2 → admina-0.15.4}/admina/cli/templates/admina.yaml.j2 +0 -0
  22. {admina-0.15.2 → admina-0.15.4}/admina/cli/templates/docker-compose.yml.j2 +0 -0
  23. {admina-0.15.2 → admina-0.15.4}/admina/cli/templates/env.j2 +0 -0
  24. {admina-0.15.2 → admina-0.15.4}/admina/cli/templates/main.py.j2 +0 -0
  25. {admina-0.15.2 → admina-0.15.4}/admina/cli/templates/plugin.py.j2 +0 -0
  26. {admina-0.15.2 → admina-0.15.4}/admina/cli/templates/plugin_pyproject.toml.j2 +0 -0
  27. {admina-0.15.2 → admina-0.15.4}/admina/cli/templates/plugin_readme.md.j2 +0 -0
  28. {admina-0.15.2 → admina-0.15.4}/admina/cli/templates/plugin_test.py.j2 +0 -0
  29. {admina-0.15.2 → admina-0.15.4}/admina/core/__init__.py +0 -0
  30. {admina-0.15.2 → admina-0.15.4}/admina/core/config_schema.py +0 -0
  31. {admina-0.15.2 → admina-0.15.4}/admina/core/event_bus.py +0 -0
  32. {admina-0.15.2 → admina-0.15.4}/admina/core/exception_log.py +0 -0
  33. {admina-0.15.2 → admina-0.15.4}/admina/core/install_hint.py +0 -0
  34. {admina-0.15.2 → admina-0.15.4}/admina/core/jcs.py +0 -0
  35. {admina-0.15.2 → admina-0.15.4}/admina/core/offline.py +0 -0
  36. {admina-0.15.2 → admina-0.15.4}/admina/core/secretfile.py +0 -0
  37. {admina-0.15.2 → admina-0.15.4}/admina/core/secrets.py +0 -0
  38. {admina-0.15.2 → admina-0.15.4}/admina/core/trace_context.py +0 -0
  39. {admina-0.15.2 → admina-0.15.4}/admina/core/types.py +0 -0
  40. {admina-0.15.2 → admina-0.15.4}/admina/dashboard/__init__.py +0 -0
  41. {admina-0.15.2 → admina-0.15.4}/admina/dashboard/static/heimdall.png +0 -0
  42. {admina-0.15.2 → admina-0.15.4}/admina/dashboard/static/index.html +0 -0
  43. {admina-0.15.2 → admina-0.15.4}/admina/dashboard/static/vendor/alpinejs.min.js +0 -0
  44. {admina-0.15.2 → admina-0.15.4}/admina/domains/__init__.py +0 -0
  45. {admina-0.15.2 → admina-0.15.4}/admina/domains/agent_security/__init__.py +0 -0
  46. {admina-0.15.2 → admina-0.15.4}/admina/domains/agent_security/coordination.py +0 -0
  47. {admina-0.15.2 → admina-0.15.4}/admina/domains/agent_security/egress.py +0 -0
  48. {admina-0.15.2 → admina-0.15.4}/admina/domains/agent_security/fingerprint.py +0 -0
  49. {admina-0.15.2 → admina-0.15.4}/admina/domains/agent_security/firewall.py +0 -0
  50. {admina-0.15.2 → admina-0.15.4}/admina/domains/agent_security/loop_breaker.py +0 -0
  51. {admina-0.15.2 → admina-0.15.4}/admina/domains/agent_security/pattern_packs.py +0 -0
  52. {admina-0.15.2 → admina-0.15.4}/admina/domains/agent_security/pattern_timing.py +0 -0
  53. {admina-0.15.2 → admina-0.15.4}/admina/domains/agent_security/ruleset.py +0 -0
  54. {admina-0.15.2 → admina-0.15.4}/admina/domains/agent_security/sandbox.py +0 -0
  55. {admina-0.15.2 → admina-0.15.4}/admina/domains/agent_security/scan_policy.py +0 -0
  56. {admina-0.15.2 → admina-0.15.4}/admina/domains/ai_infra/__init__.py +0 -0
  57. {admina-0.15.2 → admina-0.15.4}/admina/domains/ai_infra/llm_engine.py +0 -0
  58. {admina-0.15.2 → admina-0.15.4}/admina/domains/ai_infra/rag.py +0 -0
  59. {admina-0.15.2 → admina-0.15.4}/admina/domains/ai_infra/webui.py +0 -0
  60. {admina-0.15.2 → admina-0.15.4}/admina/domains/compliance/__init__.py +0 -0
  61. {admina-0.15.2 → admina-0.15.4}/admina/domains/compliance/ai_act_terms.py +0 -0
  62. {admina-0.15.2 → admina-0.15.4}/admina/domains/compliance/cross_regulation.py +0 -0
  63. {admina-0.15.2 → admina-0.15.4}/admina/domains/compliance/eu_ai_act.py +0 -0
  64. {admina-0.15.2 → admina-0.15.4}/admina/domains/compliance/forensic.py +0 -0
  65. {admina-0.15.2 → admina-0.15.4}/admina/domains/compliance/forensic_files.py +0 -0
  66. {admina-0.15.2 → admina-0.15.4}/admina/domains/compliance/forensic_integrity.py +0 -0
  67. {admina-0.15.2 → admina-0.15.4}/admina/domains/compliance/gdpr.py +0 -0
  68. {admina-0.15.2 → admina-0.15.4}/admina/domains/compliance/nis2.py +0 -0
  69. {admina-0.15.2 → admina-0.15.4}/admina/domains/compliance/oisg.py +0 -0
  70. {admina-0.15.2 → admina-0.15.4}/admina/domains/compliance/oisg_evidence.py +0 -0
  71. {admina-0.15.2 → admina-0.15.4}/admina/domains/compliance/otel.py +0 -0
  72. {admina-0.15.2 → admina-0.15.4}/admina/domains/compliance/schemas/oisg-evidence.schema.json +0 -0
  73. {admina-0.15.2 → admina-0.15.4}/admina/domains/data_sovereignty/__init__.py +0 -0
  74. {admina-0.15.2 → admina-0.15.4}/admina/domains/data_sovereignty/classification.py +0 -0
  75. {admina-0.15.2 → admina-0.15.4}/admina/domains/data_sovereignty/email_matching.py +0 -0
  76. {admina-0.15.2 → admina-0.15.4}/admina/domains/data_sovereignty/iban.py +0 -0
  77. {admina-0.15.2 → admina-0.15.4}/admina/domains/data_sovereignty/masking.py +0 -0
  78. {admina-0.15.2 → admina-0.15.4}/admina/domains/data_sovereignty/names.py +0 -0
  79. {admina-0.15.2 → admina-0.15.4}/admina/domains/data_sovereignty/pii.py +0 -0
  80. {admina-0.15.2 → admina-0.15.4}/admina/domains/data_sovereignty/residency.py +0 -0
  81. {admina-0.15.2 → admina-0.15.4}/admina/domains/governance.py +0 -0
  82. {admina-0.15.2 → admina-0.15.4}/admina/engines/__init__.py +0 -0
  83. {admina-0.15.2 → admina-0.15.4}/admina/engines/pii_plugins.py +0 -0
  84. {admina-0.15.2 → admina-0.15.4}/admina/engines/presidio.py +0 -0
  85. {admina-0.15.2 → admina-0.15.4}/admina/integrations/__init__.py +0 -0
  86. {admina-0.15.2 → admina-0.15.4}/admina/integrations/_engines.py +0 -0
  87. {admina-0.15.2 → admina-0.15.4}/admina/integrations/cheshirecat/__init__.py +0 -0
  88. {admina-0.15.2 → admina-0.15.4}/admina/integrations/cheshirecat/admina-plugin/admina_governance.py +0 -0
  89. {admina-0.15.2 → admina-0.15.4}/admina/integrations/crewai/__init__.py +0 -0
  90. {admina-0.15.2 → admina-0.15.4}/admina/integrations/crewai/callbacks.py +0 -0
  91. {admina-0.15.2 → admina-0.15.4}/admina/integrations/langchain/__init__.py +0 -0
  92. {admina-0.15.2 → admina-0.15.4}/admina/integrations/langchain/callbacks.py +0 -0
  93. {admina-0.15.2 → admina-0.15.4}/admina/integrations/n8n/__init__.py +0 -0
  94. {admina-0.15.2 → admina-0.15.4}/admina/integrations/openclaw/__init__.py +0 -0
  95. {admina-0.15.2 → admina-0.15.4}/admina/plugins/__init__.py +0 -0
  96. {admina-0.15.2 → admina-0.15.4}/admina/plugins/base.py +0 -0
  97. {admina-0.15.2 → admina-0.15.4}/admina/plugins/builtin/__init__.py +0 -0
  98. {admina-0.15.2 → admina-0.15.4}/admina/plugins/builtin/adapters/__init__.py +0 -0
  99. {admina-0.15.2 → admina-0.15.4}/admina/plugins/builtin/adapters/_streaming.py +0 -0
  100. {admina-0.15.2 → admina-0.15.4}/admina/plugins/builtin/adapters/anthropic.py +0 -0
  101. {admina-0.15.2 → admina-0.15.4}/admina/plugins/builtin/adapters/bedrock.py +0 -0
  102. {admina-0.15.2 → admina-0.15.4}/admina/plugins/builtin/adapters/gemini.py +0 -0
  103. {admina-0.15.2 → admina-0.15.4}/admina/plugins/builtin/adapters/mistral.py +0 -0
  104. {admina-0.15.2 → admina-0.15.4}/admina/plugins/builtin/adapters/ollama.py +0 -0
  105. {admina-0.15.2 → admina-0.15.4}/admina/plugins/builtin/adapters/openai.py +0 -0
  106. {admina-0.15.2 → admina-0.15.4}/admina/plugins/builtin/adapters/vllm.py +0 -0
  107. {admina-0.15.2 → admina-0.15.4}/admina/plugins/builtin/alerts/__init__.py +0 -0
  108. {admina-0.15.2 → admina-0.15.4}/admina/plugins/builtin/alerts/log.py +0 -0
  109. {admina-0.15.2 → admina-0.15.4}/admina/plugins/builtin/alerts/webhook.py +0 -0
  110. {admina-0.15.2 → admina-0.15.4}/admina/plugins/builtin/auth/__init__.py +0 -0
  111. {admina-0.15.2 → admina-0.15.4}/admina/plugins/builtin/auth/apikey.py +0 -0
  112. {admina-0.15.2 → admina-0.15.4}/admina/plugins/builtin/compliance/__init__.py +0 -0
  113. {admina-0.15.2 → admina-0.15.4}/admina/plugins/builtin/compliance/eu_ai_act.py +0 -0
  114. {admina-0.15.2 → admina-0.15.4}/admina/plugins/builtin/connectors/__init__.py +0 -0
  115. {admina-0.15.2 → admina-0.15.4}/admina/plugins/builtin/connectors/chromadb.py +0 -0
  116. {admina-0.15.2 → admina-0.15.4}/admina/plugins/builtin/connectors/filesystem.py +0 -0
  117. {admina-0.15.2 → admina-0.15.4}/admina/plugins/builtin/forensic/__init__.py +0 -0
  118. {admina-0.15.2 → admina-0.15.4}/admina/plugins/builtin/forensic/filesystem.py +0 -0
  119. {admina-0.15.2 → admina-0.15.4}/admina/plugins/builtin/guards/__init__.py +0 -0
  120. {admina-0.15.2 → admina-0.15.4}/admina/plugins/builtin/guards/guardrailsai_guard.py +0 -0
  121. {admina-0.15.2 → admina-0.15.4}/admina/plugins/builtin/pii/__init__.py +0 -0
  122. {admina-0.15.2 → admina-0.15.4}/admina/plugins/builtin/pii/spacy_regex.py +0 -0
  123. {admina-0.15.2 → admina-0.15.4}/admina/plugins/builtin/sandboxes/__init__.py +0 -0
  124. {admina-0.15.2 → admina-0.15.4}/admina/plugins/builtin/sandboxes/docker.py +0 -0
  125. {admina-0.15.2 → admina-0.15.4}/admina/plugins/builtin/transports/__init__.py +0 -0
  126. {admina-0.15.2 → admina-0.15.4}/admina/plugins/builtin/transports/http_rest.py +0 -0
  127. {admina-0.15.2 → admina-0.15.4}/admina/plugins/builtin/transports/mcp.py +0 -0
  128. {admina-0.15.2 → admina-0.15.4}/admina/plugins/registry.py +0 -0
  129. {admina-0.15.2 → admina-0.15.4}/admina/proxy/__init__.py +0 -0
  130. {admina-0.15.2 → admina-0.15.4}/admina/proxy/api/__init__.py +0 -0
  131. {admina-0.15.2 → admina-0.15.4}/admina/proxy/api/dashboard.py +0 -0
  132. {admina-0.15.2 → admina-0.15.4}/admina/proxy/api/gateway.py +0 -0
  133. {admina-0.15.2 → admina-0.15.4}/admina/proxy/api/integration.py +0 -0
  134. {admina-0.15.2 → admina-0.15.4}/admina/proxy/body_limit.py +0 -0
  135. {admina-0.15.2 → admina-0.15.4}/admina/proxy/config.py +0 -0
  136. {admina-0.15.2 → admina-0.15.4}/admina/proxy/dashboard_session.py +0 -0
  137. {admina-0.15.2 → admina-0.15.4}/admina/proxy/decisions.py +0 -0
  138. {admina-0.15.2 → admina-0.15.4}/admina/proxy/engine_bridge.py +0 -0
  139. {admina-0.15.2 → admina-0.15.4}/admina/proxy/engine_report.py +0 -0
  140. {admina-0.15.2 → admina-0.15.4}/admina/proxy/env_check.py +0 -0
  141. {admina-0.15.2 → admina-0.15.4}/admina/proxy/forensic_backend.py +0 -0
  142. {admina-0.15.2 → admina-0.15.4}/admina/proxy/forensic_probe.py +0 -0
  143. {admina-0.15.2 → admina-0.15.4}/admina/proxy/gateway_body.py +0 -0
  144. {admina-0.15.2 → admina-0.15.4}/admina/proxy/gateway_correlation.py +0 -0
  145. {admina-0.15.2 → admina-0.15.4}/admina/proxy/gateway_outcome.py +0 -0
  146. {admina-0.15.2 → admina-0.15.4}/admina/proxy/gateway_response_scan.py +0 -0
  147. {admina-0.15.2 → admina-0.15.4}/admina/proxy/gateway_scan.py +0 -0
  148. {admina-0.15.2 → admina-0.15.4}/admina/proxy/gateway_transport.py +0 -0
  149. {admina-0.15.2 → admina-0.15.4}/admina/proxy/gateway_upstreams.py +0 -0
  150. {admina-0.15.2 → admina-0.15.4}/admina/proxy/governance.py +0 -0
  151. {admina-0.15.2 → admina-0.15.4}/admina/proxy/log_format.py +0 -0
  152. {admina-0.15.2 → admina-0.15.4}/admina/proxy/loop_lag.py +0 -0
  153. {admina-0.15.2 → admina-0.15.4}/admina/proxy/multi_upstream.py +0 -0
  154. {admina-0.15.2 → admina-0.15.4}/admina/proxy/pipeline_executor.py +0 -0
  155. {admina-0.15.2 → admina-0.15.4}/admina/proxy/request_metrics.py +0 -0
  156. {admina-0.15.2 → admina-0.15.4}/admina/proxy/sandbox_bridge.py +0 -0
  157. {admina-0.15.2 → admina-0.15.4}/admina/proxy/state.py +0 -0
  158. {admina-0.15.2 → admina-0.15.4}/admina/proxy/surfaces.py +0 -0
  159. {admina-0.15.2 → admina-0.15.4}/admina/py.typed +0 -0
  160. {admina-0.15.2 → admina-0.15.4}/admina/redteam/__init__.py +0 -0
  161. {admina-0.15.2 → admina-0.15.4}/admina/redteam/baselines/baseline.json +0 -0
  162. {admina-0.15.2 → admina-0.15.4}/admina/redteam/corpora/SHA256SUMS +0 -0
  163. {admina-0.15.2 → admina-0.15.4}/admina/redteam/corpora/coordination.jsonl +0 -0
  164. {admina-0.15.2 → admina-0.15.4}/admina/redteam/corpora/injection.jsonl +0 -0
  165. {admina-0.15.2 → admina-0.15.4}/admina/redteam/corpora/loop.jsonl +0 -0
  166. {admina-0.15.2 → admina-0.15.4}/admina/redteam/corpora/pii.jsonl +0 -0
  167. {admina-0.15.2 → admina-0.15.4}/admina/redteam/corpora.py +0 -0
  168. {admina-0.15.2 → admina-0.15.4}/admina/redteam/detectors.py +0 -0
  169. {admina-0.15.2 → admina-0.15.4}/admina/redteam/gate.py +0 -0
  170. {admina-0.15.2 → admina-0.15.4}/admina/redteam/metrics.py +0 -0
  171. {admina-0.15.2 → admina-0.15.4}/admina/redteam/report.py +0 -0
  172. {admina-0.15.2 → admina-0.15.4}/admina/redteam/runner.py +0 -0
  173. {admina-0.15.2 → admina-0.15.4}/admina/sdk/__init__.py +0 -0
  174. {admina-0.15.2 → admina-0.15.4}/admina/sdk/_compat.py +0 -0
  175. {admina-0.15.2 → admina-0.15.4}/admina/sdk/compliance_kit.py +0 -0
  176. {admina-0.15.2 → admina-0.15.4}/admina/sdk/errors.py +0 -0
  177. {admina-0.15.2 → admina-0.15.4}/admina/sdk/governed_agent.py +0 -0
  178. {admina-0.15.2 → admina-0.15.4}/admina/sdk/governed_data.py +0 -0
  179. {admina-0.15.2 → admina-0.15.4}/admina/sdk/governed_model.py +0 -0
  180. {admina-0.15.2 → admina-0.15.4}/admina/sdk/retry.py +0 -0
  181. {admina-0.15.2 → admina-0.15.4}/admina/sdk/sandbox.py +0 -0
  182. {admina-0.15.2 → admina-0.15.4}/admina/sdk/streaming.py +0 -0
  183. {admina-0.15.2 → admina-0.15.4}/admina.egg-info/dependency_links.txt +0 -0
  184. {admina-0.15.2 → admina-0.15.4}/admina.egg-info/entry_points.txt +0 -0
  185. {admina-0.15.2 → admina-0.15.4}/admina.egg-info/top_level.txt +0 -0
  186. {admina-0.15.2 → admina-0.15.4}/setup.cfg +0 -0
  187. {admina-0.15.2 → admina-0.15.4}/tests/test_admina_config_path.py +0 -0
  188. {admina-0.15.2 → admina-0.15.4}/tests/test_admina_framework_sdist.py +0 -0
  189. {admina-0.15.2 → admina-0.15.4}/tests/test_ai_act_terms.py +0 -0
  190. {admina-0.15.2 → admina-0.15.4}/tests/test_audit_api_source.py +0 -0
  191. {admina-0.15.2 → admina-0.15.4}/tests/test_auth_middleware_errors.py +0 -0
  192. {admina-0.15.2 → admina-0.15.4}/tests/test_banner_engine_info.py +0 -0
  193. {admina-0.15.2 → admina-0.15.4}/tests/test_benchmark_14us.py +0 -0
  194. {admina-0.15.2 → admina-0.15.4}/tests/test_bus_event_metadata.py +0 -0
  195. {admina-0.15.2 → admina-0.15.4}/tests/test_canary_no_content.py +0 -0
  196. {admina-0.15.2 → admina-0.15.4}/tests/test_check_versions.py +0 -0
  197. {admina-0.15.2 → admina-0.15.4}/tests/test_cli_forensic_export.py +0 -0
  198. {admina-0.15.2 → admina-0.15.4}/tests/test_cli_redteam.py +0 -0
  199. {admina-0.15.2 → admina-0.15.4}/tests/test_compliance_gap_analysis_api.py +0 -0
  200. {admina-0.15.2 → admina-0.15.4}/tests/test_config_schema_validation.py +0 -0
  201. {admina-0.15.2 → admina-0.15.4}/tests/test_coordination.py +0 -0
  202. {admina-0.15.2 → admina-0.15.4}/tests/test_coordination_cli.py +0 -0
  203. {admina-0.15.2 → admina-0.15.4}/tests/test_coordination_corpus.py +0 -0
  204. {admina-0.15.2 → admina-0.15.4}/tests/test_coordination_wiring.py +0 -0
  205. {admina-0.15.2 → admina-0.15.4}/tests/test_core_config.py +0 -0
  206. {admina-0.15.2 → admina-0.15.4}/tests/test_dashboard_container.py +0 -0
  207. {admina-0.15.2 → admina-0.15.4}/tests/test_data_classifier_restricted.py +0 -0
  208. {admina-0.15.2 → admina-0.15.4}/tests/test_domains.py +0 -0
  209. {admina-0.15.2 → admina-0.15.4}/tests/test_domains_governance.py +0 -0
  210. {admina-0.15.2 → admina-0.15.4}/tests/test_egress_analyze.py +0 -0
  211. {admina-0.15.2 → admina-0.15.4}/tests/test_egress_cli.py +0 -0
  212. {admina-0.15.2 → admina-0.15.4}/tests/test_egress_pipeline.py +0 -0
  213. {admina-0.15.2 → admina-0.15.4}/tests/test_egress_policy.py +0 -0
  214. {admina-0.15.2 → admina-0.15.4}/tests/test_egress_surfaces.py +0 -0
  215. {admina-0.15.2 → admina-0.15.4}/tests/test_engine_effective.py +0 -0
  216. {admina-0.15.2 → admina-0.15.4}/tests/test_engine_startup_errors.py +0 -0
  217. {admina-0.15.2 → admina-0.15.4}/tests/test_engines.py +0 -0
  218. {admina-0.15.2 → admina-0.15.4}/tests/test_entrypoint_script.py +0 -0
  219. {admina-0.15.2 → admina-0.15.4}/tests/test_error_disclosure.py +0 -0
  220. {admina-0.15.2 → admina-0.15.4}/tests/test_event_loop_lag_metric.py +0 -0
  221. {admina-0.15.2 → admina-0.15.4}/tests/test_fingerprint.py +0 -0
  222. {admina-0.15.2 → admina-0.15.4}/tests/test_firewall_heuristic_config.py +0 -0
  223. {admina-0.15.2 → admina-0.15.4}/tests/test_firewall_it_baseline.py +0 -0
  224. {admina-0.15.2 → admina-0.15.4}/tests/test_firewall_it_benign.py +0 -0
  225. {admina-0.15.2 → admina-0.15.4}/tests/test_firewall_parity.py +0 -0
  226. {admina-0.15.2 → admina-0.15.4}/tests/test_firewall_pattern_ids.py +0 -0
  227. {admina-0.15.2 → admina-0.15.4}/tests/test_firewall_pattern_packs.py +0 -0
  228. {admina-0.15.2 → admina-0.15.4}/tests/test_firewall_pattern_timing.py +0 -0
  229. {admina-0.15.2 → admina-0.15.4}/tests/test_forensic_atomic_write.py +0 -0
  230. {admina-0.15.2 → admina-0.15.4}/tests/test_forensic_blackbox.py +0 -0
  231. {admina-0.15.2 → admina-0.15.4}/tests/test_forensic_config_coherence.py +0 -0
  232. {admina-0.15.2 → admina-0.15.4}/tests/test_forensic_fail_mode.py +0 -0
  233. {admina-0.15.2 → admina-0.15.4}/tests/test_forensic_gateway_records.py +0 -0
  234. {admina-0.15.2 → admina-0.15.4}/tests/test_forensic_incremental_verify.py +0 -0
  235. {admina-0.15.2 → admina-0.15.4}/tests/test_forensic_integrity.py +0 -0
  236. {admina-0.15.2 → admina-0.15.4}/tests/test_forensic_rebuilt_and_duplicates.py +0 -0
  237. {admina-0.15.2 → admina-0.15.4}/tests/test_forensic_record_signature.py +0 -0
  238. {admina-0.15.2 → admina-0.15.4}/tests/test_forensic_restart.py +0 -0
  239. {admina-0.15.2 → admina-0.15.4}/tests/test_forensic_s3_reads.py +0 -0
  240. {admina-0.15.2 → admina-0.15.4}/tests/test_forensic_volume.py +0 -0
  241. {admina-0.15.2 → admina-0.15.4}/tests/test_gateway_block_status.py +0 -0
  242. {admina-0.15.2 → admina-0.15.4}/tests/test_gateway_config.py +0 -0
  243. {admina-0.15.2 → admina-0.15.4}/tests/test_gateway_correlation.py +0 -0
  244. {admina-0.15.2 → admina-0.15.4}/tests/test_gateway_endpoints.py +0 -0
  245. {admina-0.15.2 → admina-0.15.4}/tests/test_gateway_errors.py +0 -0
  246. {admina-0.15.2 → admina-0.15.4}/tests/test_gateway_forward_body.py +0 -0
  247. {admina-0.15.2 → admina-0.15.4}/tests/test_gateway_governed_stream.py +0 -0
  248. {admina-0.15.2 → admina-0.15.4}/tests/test_gateway_guard_fail_mode.py +0 -0
  249. {admina-0.15.2 → admina-0.15.4}/tests/test_gateway_helpers.py +0 -0
  250. {admina-0.15.2 → admina-0.15.4}/tests/test_gateway_latency_bench.py +0 -0
  251. {admina-0.15.2 → admina-0.15.4}/tests/test_gateway_mount.py +0 -0
  252. {admina-0.15.2 → admina-0.15.4}/tests/test_gateway_outcome_headers.py +0 -0
  253. {admina-0.15.2 → admina-0.15.4}/tests/test_gateway_passthrough.py +0 -0
  254. {admina-0.15.2 → admina-0.15.4}/tests/test_gateway_pii_contract.py +0 -0
  255. {admina-0.15.2 → admina-0.15.4}/tests/test_gateway_ruleset_endpoint.py +0 -0
  256. {admina-0.15.2 → admina-0.15.4}/tests/test_gateway_upstream_auth.py +0 -0
  257. {admina-0.15.2 → admina-0.15.4}/tests/test_gateway_upstream_routes.py +0 -0
  258. {admina-0.15.2 → admina-0.15.4}/tests/test_governance_pipeline.py +0 -0
  259. {admina-0.15.2 → admina-0.15.4}/tests/test_guard_fail_mode.py +0 -0
  260. {admina-0.15.2 → admina-0.15.4}/tests/test_health_fields.py +0 -0
  261. {admina-0.15.2 → admina-0.15.4}/tests/test_health_forensic_probe.py +0 -0
  262. {admina-0.15.2 → admina-0.15.4}/tests/test_iban_it.py +0 -0
  263. {admina-0.15.2 → admina-0.15.4}/tests/test_install_hint.py +0 -0
  264. {admina-0.15.2 → admina-0.15.4}/tests/test_jcs.py +0 -0
  265. {admina-0.15.2 → admina-0.15.4}/tests/test_log_format.py +0 -0
  266. {admina-0.15.2 → admina-0.15.4}/tests/test_mcp_block_reason.py +0 -0
  267. {admina-0.15.2 → admina-0.15.4}/tests/test_mcp_transport.py +0 -0
  268. {admina-0.15.2 → admina-0.15.4}/tests/test_metrics_docs_auth.py +0 -0
  269. {admina-0.15.2 → admina-0.15.4}/tests/test_metrics_gateway.py +0 -0
  270. {admina-0.15.2 → admina-0.15.4}/tests/test_model_allowlist_post.py +0 -0
  271. {admina-0.15.2 → admina-0.15.4}/tests/test_multi_upstream_tool_routing.py +0 -0
  272. {admina-0.15.2 → admina-0.15.4}/tests/test_offline_guarantee.py +0 -0
  273. {admina-0.15.2 → admina-0.15.4}/tests/test_oisg_evidence.py +0 -0
  274. {admina-0.15.2 → admina-0.15.4}/tests/test_otel_enabled_flag.py +0 -0
  275. {admina-0.15.2 → admina-0.15.4}/tests/test_pattern_probe.py +0 -0
  276. {admina-0.15.2 → admina-0.15.4}/tests/test_person_names.py +0 -0
  277. {admina-0.15.2 → admina-0.15.4}/tests/test_pii_email_matching.py +0 -0
  278. {admina-0.15.2 → admina-0.15.4}/tests/test_pii_mask_style.py +0 -0
  279. {admina-0.15.2 → admina-0.15.4}/tests/test_pii_plugin_engines.py +0 -0
  280. {admina-0.15.2 → admina-0.15.4}/tests/test_pipeline_executor.py +0 -0
  281. {admina-0.15.2 → admina-0.15.4}/tests/test_presidio_engine.py +0 -0
  282. {admina-0.15.2 → admina-0.15.4}/tests/test_proxy_dashboard_session.py +0 -0
  283. {admina-0.15.2 → admina-0.15.4}/tests/test_proxy_forensic_would_action.py +0 -0
  284. {admina-0.15.2 → admina-0.15.4}/tests/test_proxy_governance_mode_config.py +0 -0
  285. {admina-0.15.2 → admina-0.15.4}/tests/test_proxy_guard_fail_mode.py +0 -0
  286. {admina-0.15.2 → admina-0.15.4}/tests/test_proxy_mcp_response_pii.py +0 -0
  287. {admina-0.15.2 → admina-0.15.4}/tests/test_proxy_metrics_endpoint.py +0 -0
  288. {admina-0.15.2 → admina-0.15.4}/tests/test_proxy_minimal_extra.py +0 -0
  289. {admina-0.15.2 → admina-0.15.4}/tests/test_proxy_plugins.py +0 -0
  290. {admina-0.15.2 → admina-0.15.4}/tests/test_proxy_security.py +0 -0
  291. {admina-0.15.2 → admina-0.15.4}/tests/test_query_api_key_deprecation.py +0 -0
  292. {admina-0.15.2 → admina-0.15.4}/tests/test_record_decision.py +0 -0
  293. {admina-0.15.2 → admina-0.15.4}/tests/test_redaction_values_only.py +0 -0
  294. {admina-0.15.2 → admina-0.15.4}/tests/test_redteam_efficacy.py +0 -0
  295. {admina-0.15.2 → admina-0.15.4}/tests/test_redteam_external_corpora.py +0 -0
  296. {admina-0.15.2 → admina-0.15.4}/tests/test_redteam_lib.py +0 -0
  297. {admina-0.15.2 → admina-0.15.4}/tests/test_release_workflows.py +0 -0
  298. {admina-0.15.2 → admina-0.15.4}/tests/test_request_sha256.py +0 -0
  299. {admina-0.15.2 → admina-0.15.4}/tests/test_request_size_cap.py +0 -0
  300. {admina-0.15.2 → admina-0.15.4}/tests/test_response_scan_option.py +0 -0
  301. {admina-0.15.2 → admina-0.15.4}/tests/test_ruleset_parity.py +0 -0
  302. {admina-0.15.2 → admina-0.15.4}/tests/test_ruleset_sha256.py +0 -0
  303. {admina-0.15.2 → admina-0.15.4}/tests/test_sandbox_config.py +0 -0
  304. {admina-0.15.2 → admina-0.15.4}/tests/test_sandbox_core.py +0 -0
  305. {admina-0.15.2 → admina-0.15.4}/tests/test_sandbox_docker.py +0 -0
  306. {admina-0.15.2 → admina-0.15.4}/tests/test_sandbox_docker_unit.py +0 -0
  307. {admina-0.15.2 → admina-0.15.4}/tests/test_sandbox_mcp.py +0 -0
  308. {admina-0.15.2 → admina-0.15.4}/tests/test_scan_depth.py +0 -0
  309. {admina-0.15.2 → admina-0.15.4}/tests/test_scan_policy.py +0 -0
  310. {admina-0.15.2 → admina-0.15.4}/tests/test_sdk_sandbox.py +0 -0
  311. {admina-0.15.2 → admina-0.15.4}/tests/test_secret_files.py +0 -0
  312. {admina-0.15.2 → admina-0.15.4}/tests/test_unknown_admina_env.py +0 -0
  313. {admina-0.15.2 → admina-0.15.4}/tests/test_version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: admina
3
- Version: 0.15.2
3
+ Version: 0.15.4
4
4
  Summary: Admina — governed AI development framework
5
5
  Author-email: Stefano Noferi <info@admina.org>
6
6
  Maintainer-email: Stefano Noferi <info@admina.org>
@@ -19,6 +19,7 @@ Classifier: Programming Language :: Python :: 3
19
19
  Classifier: Programming Language :: Python :: 3.11
20
20
  Classifier: Programming Language :: Python :: 3.12
21
21
  Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Programming Language :: Python :: 3.14
22
23
  Classifier: Programming Language :: Rust
23
24
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
25
  Classifier: Topic :: Security
@@ -42,7 +43,7 @@ Requires-Dist: redis<9,>=5.0; extra == "proxy"
42
43
  Requires-Dist: boto3<2,>=1.34; extra == "proxy"
43
44
  Requires-Dist: clickhouse-connect<2,>=0.7; extra == "proxy"
44
45
  Requires-Dist: typer<1,>=0.9; extra == "proxy"
45
- Requires-Dist: numpy<2,>=1.24; extra == "proxy"
46
+ Requires-Dist: numpy<3,>=1.24; extra == "proxy"
46
47
  Requires-Dist: scikit-learn<2,>=1.3; extra == "proxy"
47
48
  Provides-Extra: proxy-minimal
48
49
  Requires-Dist: fastapi<1,>=0.104; extra == "proxy-minimal"
@@ -67,7 +68,7 @@ Requires-Dist: openai<4,>=1.0; extra == "openai"
67
68
  Provides-Extra: ollama
68
69
  Requires-Dist: ollama<1,>=0.3; extra == "ollama"
69
70
  Provides-Extra: anthropic
70
- Requires-Dist: anthropic<2,>=0.39; extra == "anthropic"
71
+ Requires-Dist: anthropic<3,>=0.39; extra == "anthropic"
71
72
  Provides-Extra: mistral
72
73
  Requires-Dist: mistralai<4,>=1.0; extra == "mistral"
73
74
  Provides-Extra: gemini
@@ -1300,7 +1301,7 @@ domains:
1300
1301
  ```
1301
1302
 
1302
1303
  ```bash
1303
- docker pull python:3.12-slim@sha256:a6e34c598f2467ed0e9a8d349809fcd8b5c603269512df273a0bb1784edc11b1
1304
+ docker pull python:3.12-slim@sha256:aa943ce411423c7582288f18707ff66eddcbaeb510502d747a72aeb34f30d159
1304
1305
  ```
1305
1306
 
1306
1307
  On `/mcp`, a `tools/call` of `python_exec` that the pipeline allows is
@@ -1903,6 +1904,29 @@ crew = Crew(agents=[agent], tasks=[task], task_callback=admina_task_callback)
1903
1904
 
1904
1905
  </details>
1905
1906
 
1907
+ <details>
1908
+ <summary><strong>Bifrost</strong> — the OpenAI-compatible gateway in front of the Bifrost LLM gateway</summary>
1909
+
1910
+ <br>
1911
+
1912
+ The gateway forwards governed chat completions to Bifrost, which selects the
1913
+ provider; requests the firewall blocks never reach it. Point the gateway at
1914
+ Bifrost and give it a Bifrost virtual key:
1915
+
1916
+ ```bash
1917
+ ADMINA_GATEWAY_UPSTREAM=http://bifrost:8080/v1
1918
+ ADMINA_GATEWAY_UPSTREAM_API_KEY_FILE=/run/secrets/bifrost_vk
1919
+ ```
1920
+
1921
+ Governed: `/v1/chat/completions` (requests, tool results in the messages,
1922
+ responses). Not governed: the other Bifrost endpoints, tools that Bifrost
1923
+ runs itself (Agent Mode) and response content in Bifrost's own logs. The
1924
+ [Bifrost guide](https://github.com/admina-org/admina/blob/main/docs/guides/bifrost.md)
1925
+ details the scope; [`examples/bifrost/`](https://github.com/admina-org/admina/tree/main/examples/bifrost) runs both with
1926
+ Docker Compose.
1927
+
1928
+ </details>
1929
+
1906
1930
  See [full integration docs](https://github.com/admina-org/admina/blob/main/docs/guides/integrations.md) for details.
1907
1931
 
1908
1932
  ## Performance — Hybrid Python + Rust engine
@@ -1216,7 +1216,7 @@ domains:
1216
1216
  ```
1217
1217
 
1218
1218
  ```bash
1219
- docker pull python:3.12-slim@sha256:a6e34c598f2467ed0e9a8d349809fcd8b5c603269512df273a0bb1784edc11b1
1219
+ docker pull python:3.12-slim@sha256:aa943ce411423c7582288f18707ff66eddcbaeb510502d747a72aeb34f30d159
1220
1220
  ```
1221
1221
 
1222
1222
  On `/mcp`, a `tools/call` of `python_exec` that the pipeline allows is
@@ -1819,6 +1819,29 @@ crew = Crew(agents=[agent], tasks=[task], task_callback=admina_task_callback)
1819
1819
 
1820
1820
  </details>
1821
1821
 
1822
+ <details>
1823
+ <summary><strong>Bifrost</strong> — the OpenAI-compatible gateway in front of the Bifrost LLM gateway</summary>
1824
+
1825
+ <br>
1826
+
1827
+ The gateway forwards governed chat completions to Bifrost, which selects the
1828
+ provider; requests the firewall blocks never reach it. Point the gateway at
1829
+ Bifrost and give it a Bifrost virtual key:
1830
+
1831
+ ```bash
1832
+ ADMINA_GATEWAY_UPSTREAM=http://bifrost:8080/v1
1833
+ ADMINA_GATEWAY_UPSTREAM_API_KEY_FILE=/run/secrets/bifrost_vk
1834
+ ```
1835
+
1836
+ Governed: `/v1/chat/completions` (requests, tool results in the messages,
1837
+ responses). Not governed: the other Bifrost endpoints, tools that Bifrost
1838
+ runs itself (Agent Mode) and response content in Bifrost's own logs. The
1839
+ [Bifrost guide](https://github.com/admina-org/admina/blob/main/docs/guides/bifrost.md)
1840
+ details the scope; [`examples/bifrost/`](https://github.com/admina-org/admina/tree/main/examples/bifrost) runs both with
1841
+ Docker Compose.
1842
+
1843
+ </details>
1844
+
1822
1845
  See [full integration docs](https://github.com/admina-org/admina/blob/main/docs/guides/integrations.md) for details.
1823
1846
 
1824
1847
  ## Performance — Hybrid Python + Rust engine
@@ -23,7 +23,7 @@ from __future__ import annotations
23
23
 
24
24
  from admina.sdk import ComplianceKit, GovernedAgent, GovernedData, GovernedModel
25
25
 
26
- __version__ = "0.15.2"
26
+ __version__ = "0.15.4"
27
27
 
28
28
  __all__ = [
29
29
  "__version__",
@@ -1241,7 +1241,8 @@ def doctor() -> None:
1241
1241
  ("spacy", "spacy"),
1242
1242
  ],
1243
1243
  "telemetry": [
1244
- ("opentelemetry", "opentelemetry-api"),
1244
+ # opentelemetry-api alone comes with FastAPI (0.160+).
1245
+ ("opentelemetry.sdk", "opentelemetry-sdk"),
1245
1246
  ],
1246
1247
  }
1247
1248
  extras_status: dict[str, str] = {}
@@ -111,7 +111,7 @@ _HEX64 = re.compile(r"[0-9a-fA-F]{64}")
111
111
  #: (linux/amd64 and linux/arm64 among others). Pull it once before enabling
112
112
  #: the sandbox: nothing is pulled on the request path.
113
113
  SANDBOX_DEFAULT_IMAGE = (
114
- "python:3.12-slim@sha256:a6e34c598f2467ed0e9a8d349809fcd8b5c603269512df273a0bb1784edc11b1"
114
+ "python:3.12-slim@sha256:aa943ce411423c7582288f18707ff66eddcbaeb510502d747a72aeb34f30d159"
115
115
  )
116
116
 
117
117
  #: How a sandboxed tool's arguments become a command
@@ -675,11 +675,24 @@ def _init_clickhouse_tables(client):
675
675
 
676
676
 
677
677
  # ── FastAPI App ──────────────────────────────────────────────
678
+ # FastAPI 0.160+ traces requests, records metrics and logs validation
679
+ # failures (with the input values) through the global OpenTelemetry
680
+ # providers. The proxy exports its own governance spans, after redaction;
681
+ # FastAPI's own telemetry is off. Older FastAPI versions ignore the argument.
682
+ FASTAPI_TELEMETRY = {
683
+ "tracing": False,
684
+ "metrics": False,
685
+ "logs": False,
686
+ "operation_spans": False,
687
+ "auto_configure": False,
688
+ }
689
+
678
690
  app = FastAPI(
679
691
  title="Admina Governance Proxy",
680
692
  description="AI Governance & Security for Autonomous Agents",
681
693
  version=__version__,
682
694
  lifespan=lifespan,
695
+ telemetry=FASTAPI_TELEMETRY,
683
696
  servers=[
684
697
  {"url": "http://localhost:3000", "description": "Dashboard (nginx proxy)"},
685
698
  {"url": "http://localhost:8080", "description": "Proxy (direct)"},
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: admina
3
- Version: 0.15.2
3
+ Version: 0.15.4
4
4
  Summary: Admina — governed AI development framework
5
5
  Author-email: Stefano Noferi <info@admina.org>
6
6
  Maintainer-email: Stefano Noferi <info@admina.org>
@@ -19,6 +19,7 @@ Classifier: Programming Language :: Python :: 3
19
19
  Classifier: Programming Language :: Python :: 3.11
20
20
  Classifier: Programming Language :: Python :: 3.12
21
21
  Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Programming Language :: Python :: 3.14
22
23
  Classifier: Programming Language :: Rust
23
24
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
25
  Classifier: Topic :: Security
@@ -42,7 +43,7 @@ Requires-Dist: redis<9,>=5.0; extra == "proxy"
42
43
  Requires-Dist: boto3<2,>=1.34; extra == "proxy"
43
44
  Requires-Dist: clickhouse-connect<2,>=0.7; extra == "proxy"
44
45
  Requires-Dist: typer<1,>=0.9; extra == "proxy"
45
- Requires-Dist: numpy<2,>=1.24; extra == "proxy"
46
+ Requires-Dist: numpy<3,>=1.24; extra == "proxy"
46
47
  Requires-Dist: scikit-learn<2,>=1.3; extra == "proxy"
47
48
  Provides-Extra: proxy-minimal
48
49
  Requires-Dist: fastapi<1,>=0.104; extra == "proxy-minimal"
@@ -67,7 +68,7 @@ Requires-Dist: openai<4,>=1.0; extra == "openai"
67
68
  Provides-Extra: ollama
68
69
  Requires-Dist: ollama<1,>=0.3; extra == "ollama"
69
70
  Provides-Extra: anthropic
70
- Requires-Dist: anthropic<2,>=0.39; extra == "anthropic"
71
+ Requires-Dist: anthropic<3,>=0.39; extra == "anthropic"
71
72
  Provides-Extra: mistral
72
73
  Requires-Dist: mistralai<4,>=1.0; extra == "mistral"
73
74
  Provides-Extra: gemini
@@ -1300,7 +1301,7 @@ domains:
1300
1301
  ```
1301
1302
 
1302
1303
  ```bash
1303
- docker pull python:3.12-slim@sha256:a6e34c598f2467ed0e9a8d349809fcd8b5c603269512df273a0bb1784edc11b1
1304
+ docker pull python:3.12-slim@sha256:aa943ce411423c7582288f18707ff66eddcbaeb510502d747a72aeb34f30d159
1304
1305
  ```
1305
1306
 
1306
1307
  On `/mcp`, a `tools/call` of `python_exec` that the pipeline allows is
@@ -1903,6 +1904,29 @@ crew = Crew(agents=[agent], tasks=[task], task_callback=admina_task_callback)
1903
1904
 
1904
1905
  </details>
1905
1906
 
1907
+ <details>
1908
+ <summary><strong>Bifrost</strong> — the OpenAI-compatible gateway in front of the Bifrost LLM gateway</summary>
1909
+
1910
+ <br>
1911
+
1912
+ The gateway forwards governed chat completions to Bifrost, which selects the
1913
+ provider; requests the firewall blocks never reach it. Point the gateway at
1914
+ Bifrost and give it a Bifrost virtual key:
1915
+
1916
+ ```bash
1917
+ ADMINA_GATEWAY_UPSTREAM=http://bifrost:8080/v1
1918
+ ADMINA_GATEWAY_UPSTREAM_API_KEY_FILE=/run/secrets/bifrost_vk
1919
+ ```
1920
+
1921
+ Governed: `/v1/chat/completions` (requests, tool results in the messages,
1922
+ responses). Not governed: the other Bifrost endpoints, tools that Bifrost
1923
+ runs itself (Agent Mode) and response content in Bifrost's own logs. The
1924
+ [Bifrost guide](https://github.com/admina-org/admina/blob/main/docs/guides/bifrost.md)
1925
+ details the scope; [`examples/bifrost/`](https://github.com/admina-org/admina/tree/main/examples/bifrost) runs both with
1926
+ Docker Compose.
1927
+
1928
+ </details>
1929
+
1906
1930
  See [full integration docs](https://github.com/admina-org/admina/blob/main/docs/guides/integrations.md) for details.
1907
1931
 
1908
1932
  ## Performance — Hybrid Python + Rust engine
@@ -213,6 +213,7 @@ tests/test_engines.py
213
213
  tests/test_entrypoint_script.py
214
214
  tests/test_error_disclosure.py
215
215
  tests/test_event_loop_lag_metric.py
216
+ tests/test_fastapi_telemetry.py
216
217
  tests/test_fingerprint.py
217
218
  tests/test_firewall_heuristic_config.py
218
219
  tests/test_firewall_it_baseline.py
@@ -10,7 +10,7 @@ admina[anthropic,bedrock,gemini,mistral,ollama,openai]
10
10
  admina[adapters,nlp,presidio,proxy,telemetry]
11
11
 
12
12
  [anthropic]
13
- anthropic<2,>=0.39
13
+ anthropic<3,>=0.39
14
14
 
15
15
  [bedrock]
16
16
  boto3<2,>=1.34
@@ -47,7 +47,7 @@ redis<9,>=5.0
47
47
  boto3<2,>=1.34
48
48
  clickhouse-connect<2,>=0.7
49
49
  typer<1,>=0.9
50
- numpy<2,>=1.24
50
+ numpy<3,>=1.24
51
51
  scikit-learn<2,>=1.3
52
52
 
53
53
  [proxy-minimal]
@@ -19,7 +19,7 @@ build-backend = "setuptools.build_meta"
19
19
 
20
20
  [project]
21
21
  name = "admina"
22
- version = "0.15.2"
22
+ version = "0.15.4"
23
23
  description = "Admina — governed AI development framework"
24
24
  readme = "README.md"
25
25
  requires-python = ">=3.11"
@@ -42,6 +42,7 @@ classifiers = [
42
42
  "Programming Language :: Python :: 3.11",
43
43
  "Programming Language :: Python :: 3.12",
44
44
  "Programming Language :: Python :: 3.13",
45
+ "Programming Language :: Python :: 3.14",
45
46
  "Programming Language :: Rust",
46
47
  "Topic :: Software Development :: Libraries :: Python Modules",
47
48
  "Topic :: Security",
@@ -78,7 +79,7 @@ proxy = [
78
79
  "clickhouse-connect>=0.7,<2",
79
80
  "typer>=0.9,<1",
80
81
  # Required by the LoopBreaker (core proxy guardrail — not an NLP add-on).
81
- "numpy>=1.24,<2",
82
+ "numpy>=1.24,<3",
82
83
  "scikit-learn>=1.3,<2",
83
84
  ]
84
85
  # The proxy without Redis, ClickHouse, S3 (boto3), typer and the scientific
@@ -146,7 +147,7 @@ full = ["admina[proxy,nlp,telemetry]"]
146
147
  # extra only controls whether the provider wheel is present.
147
148
  openai = ["openai>=1.0,<4"]
148
149
  ollama = ["ollama>=0.3,<1"]
149
- anthropic = ["anthropic>=0.39,<2"]
150
+ anthropic = ["anthropic>=0.39,<3"]
150
151
  mistral = ["mistralai>=1.0,<4"]
151
152
  gemini = ["google-genai>=1.0,<3"]
152
153
  bedrock = ["boto3>=1.34,<2"]
@@ -168,13 +169,13 @@ dev = [
168
169
  # Async test support (asyncio backend)
169
170
  "anyio>=4.0,<5",
170
171
  # Coverage measurement and reporting
171
- "pytest-cov>=5.0,<7",
172
+ "pytest-cov>=5.0,<8",
172
173
  # Python linter — replaces flake8 + isort + pyupgrade
173
174
  "ruff>=0.4,<1",
174
175
  # Security linter — detects common Python security issues
175
176
  "bandit>=1.7,<2",
176
- # Dependency vulnerability scanner
177
- "safety>=3.0,<4",
177
+ # Dependency vulnerability scanner (PyPA, OSV database)
178
+ "pip-audit>=2.7,<3",
178
179
  # Documentation
179
180
  "mkdocs>=1.6,<2",
180
181
  "mkdocs-material>=9.5,<10",
@@ -247,6 +248,10 @@ exclude_lines = [
247
248
  line-length = 100
248
249
  target-version = "py311"
249
250
 
251
+ [tool.ruff.format]
252
+ # The Python examples in the Markdown docs keep their aligned comments.
253
+ exclude = ["*.md"]
254
+
250
255
  [tool.ruff.lint]
251
256
  select = ["E", "F", "I", "UP"]
252
257
  ignore = [
@@ -27,6 +27,7 @@ from __future__ import annotations
27
27
  import json
28
28
  import subprocess
29
29
  import sys
30
+ from pathlib import Path
30
31
 
31
32
  import pytest
32
33
 
@@ -225,8 +226,9 @@ def test_surfaces_that_run_the_loop_breaker_build_it(proxy, surfaces):
225
226
  # ── Routes of disabled surfaces are not mounted ───────────────
226
227
 
227
228
  _ROUTES = (
228
- "import json; from admina.proxy.main import app; "
229
- "print(json.dumps({'routes': sorted({getattr(r, 'path', '') for r in app.routes}), "
229
+ f"import json, sys; sys.path.insert(0, {str(Path(__file__).parent)!r}); "
230
+ "from _routes import route_paths; from admina.proxy.main import app; "
231
+ "print(json.dumps({'routes': sorted(route_paths(app)), "
230
232
  "'openapi': sorted(app.openapi()['paths'])}))"
231
233
  )
232
234
 
@@ -0,0 +1,68 @@
1
+ # Copyright © 2025–2026 Stefano Noferi & Admina contributors
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """FastAPI's own OpenTelemetry instrumentation is off in the proxy app.
16
+
17
+ FastAPI 0.160+ traces requests and logs validation failures, with the
18
+ input values, through the global OpenTelemetry providers. The proxy sets
19
+ a global tracer provider for its governance spans; requests must not
20
+ produce FastAPI spans next to them. The check runs in a subprocess, so the
21
+ global provider is the one it sets.
22
+ """
23
+
24
+ from __future__ import annotations
25
+
26
+ import json
27
+ import subprocess
28
+ import sys
29
+
30
+ import pytest
31
+ from _proxy_app import subprocess_env
32
+
33
+ _SCRIPT = """
34
+ import json
35
+ from opentelemetry import trace
36
+ from opentelemetry.sdk.trace import TracerProvider
37
+ from opentelemetry.sdk.trace.export import SimpleSpanProcessor
38
+ from opentelemetry.sdk.trace.export.in_memory_span_exporter import InMemorySpanExporter
39
+
40
+ spans = InMemorySpanExporter()
41
+ provider = TracerProvider()
42
+ provider.add_span_processor(SimpleSpanProcessor(spans))
43
+ trace.set_tracer_provider(provider)
44
+
45
+ from fastapi.testclient import TestClient
46
+ from admina.proxy.main import app
47
+
48
+ with TestClient(app) as client:
49
+ statuses = [
50
+ client.get("/health").status_code,
51
+ client.post("/api/v1/validate", json={"content": 1}).status_code,
52
+ ]
53
+ print(json.dumps({"statuses": statuses, "spans": [s.name for s in spans.get_finished_spans()]}))
54
+ """
55
+
56
+
57
+ def test_requests_produce_no_fastapi_spans():
58
+ pytest.importorskip("opentelemetry.sdk.trace")
59
+ env = subprocess_env(
60
+ REDIS_URL="", CLICKHOUSE_HOST="", FORENSIC_BACKEND="memory", OTEL_ENABLED="false"
61
+ )
62
+ proc = subprocess.run(
63
+ [sys.executable, "-c", _SCRIPT], env=env, capture_output=True, text=True, timeout=120
64
+ )
65
+ assert proc.returncode == 0, proc.stderr
66
+ result = json.loads(proc.stdout.strip().splitlines()[-1])
67
+ assert result["statuses"][0] == 200
68
+ assert result["spans"] == []
@@ -173,17 +173,32 @@ def _nested_lists(levels: int, leaf: object) -> object:
173
173
  return value
174
174
 
175
175
 
176
- # Deeper than the JSON parser reads on any supported Python version.
176
+ # Far past the depth limit, and past what the JSON parser reads with the
177
+ # default 8 MB stack. The depth at which the parser raises RecursionError
178
+ # depends on the platform and on the stack size (Python 3.14 measures the C
179
+ # stack), so the tests force that outcome with the out_of_stack fixture.
177
180
  _TOO_DEEP_TO_READ = 100_000
178
181
 
179
182
 
180
183
  def _arguments_too_deep_to_read(leaf: str) -> str:
181
- """JSON text of the string *leaf* inside more nested arrays than
182
- ``json.loads`` reads: parsing it raises ``RecursionError``."""
183
- arguments = "[" * _TOO_DEEP_TO_READ + leaf + "]" * _TOO_DEEP_TO_READ
184
- with pytest.raises(RecursionError):
185
- json.loads(arguments)
186
- return arguments
184
+ """JSON text of the string *leaf* inside _TOO_DEEP_TO_READ nested arrays."""
185
+ return "[" * _TOO_DEEP_TO_READ + leaf + "]" * _TOO_DEEP_TO_READ
186
+
187
+
188
+ @pytest.fixture()
189
+ def out_of_stack(monkeypatch):
190
+ """The JSON parser of the scan policy raises RecursionError on text
191
+ nested _TOO_DEEP_TO_READ levels, as it does when the stack runs out."""
192
+ from admina.domains.agent_security import scan_policy
193
+
194
+ loads = scan_policy.json.loads
195
+
196
+ def limited(text, *args, **kwargs):
197
+ if isinstance(text, str) and text.startswith("[" * _TOO_DEEP_TO_READ):
198
+ raise RecursionError("maximum recursion depth exceeded")
199
+ return loads(text, *args, **kwargs)
200
+
201
+ monkeypatch.setattr(scan_policy.json, "loads", limited)
187
202
 
188
203
 
189
204
  def _escaped(text: str) -> str:
@@ -302,12 +317,16 @@ def test_arguments_nested_past_the_depth_limit_are_blocked():
302
317
  assert recorder.request["checks"]["scan_depth"] == SCAN_DEPTH
303
318
 
304
319
 
320
+ @pytest.mark.parametrize("parser", ["as_on_this_platform", "out_of_stack"])
305
321
  @pytest.mark.parametrize(
306
322
  "leaf", [json.dumps(BENIGN), _escaped(OVERRIDE)], ids=["benign", "escaped_override"]
307
323
  )
308
- def test_arguments_too_deep_to_read_as_json_are_blocked(leaf):
309
- # Nested past what the JSON parser reads, so past the depth limit too:
310
- # the raw string is scanned and the request is blocked for its depth.
324
+ def test_arguments_too_deep_to_read_as_json_are_blocked(leaf, parser, request):
325
+ # Nested far past the depth limit: whether the parser reads them (the
326
+ # walk stops at the limit) or runs out of stack (the raw string is
327
+ # scanned), the request is blocked for its depth.
328
+ if parser == "out_of_stack":
329
+ request.getfixturevalue("out_of_stack")
311
330
  arguments = _arguments_too_deep_to_read(leaf)
312
331
  body = {"model": "example-model", "messages": [QUESTION, _tool_call(arguments)]}
313
332
  resp, upstream, recorder = _send(body)
@@ -442,7 +461,7 @@ def test_request_texts_hold_arguments_that_are_not_json_as_they_are(arguments):
442
461
  assert scanned.truncated is False
443
462
 
444
463
 
445
- def test_request_texts_hold_arguments_too_deep_to_read_as_they_are_and_truncated():
464
+ def test_request_texts_hold_arguments_too_deep_to_read_as_they_are_and_truncated(out_of_stack):
446
465
  from admina.domains.agent_security.scan_policy import request_texts
447
466
 
448
467
  arguments = _arguments_too_deep_to_read(json.dumps("leaf text"))
@@ -76,7 +76,7 @@ _MINIMAL = textwrap.dedent(
76
76
 
77
77
  class Blocker:
78
78
  def find_spec(self, name, path=None, target=None):
79
- if name.split(".")[0] in BLOCKED:
79
+ if any(name == b or name.startswith(b + ".") for b in BLOCKED):
80
80
  raise ModuleNotFoundError(f"blocked: {{name}}")
81
81
  return None
82
82
 
@@ -132,7 +132,10 @@ NOT_IN_PROXY_MINIMAL = (
132
132
  "scipy",
133
133
  "sklearn",
134
134
  "spacy",
135
- "opentelemetry",
135
+ # opentelemetry-api is a dependency of FastAPI from 0.160 on; the SDK and
136
+ # the exporters come with the telemetry extra.
137
+ "opentelemetry.sdk",
138
+ "opentelemetry.exporter",
136
139
  "typer",
137
140
  "admina_core",
138
141
  )
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