admina-framework 0.13.0__tar.gz → 0.13.1__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 (295) hide show
  1. {admina_framework-0.13.0/admina_framework.egg-info → admina_framework-0.13.1}/PKG-INFO +52 -12
  2. {admina_framework-0.13.0 → admina_framework-0.13.1}/README.md +51 -11
  3. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/__init__.py +1 -1
  4. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/cli/main.py +33 -5
  5. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/cli/templates/admina.yaml.j2 +2 -1
  6. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/cli/templates/docker-compose.yml.j2 +46 -10
  7. admina_framework-0.13.1/admina/cli/templates/env.j2 +7 -0
  8. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/core/config_schema.py +24 -5
  9. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/dashboard/static/index.html +1 -1
  10. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/domains/agent_security/egress.py +8 -7
  11. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/domains/agent_security/firewall.py +2 -7
  12. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/domains/compliance/forensic.py +35 -1
  13. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/domains/compliance/oisg.py +47 -17
  14. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/domains/governance.py +25 -1
  15. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/engines/__init__.py +4 -5
  16. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/integrations/_engines.py +17 -2
  17. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/plugins/builtin/transports/mcp.py +64 -2
  18. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/proxy/api/dashboard.py +25 -10
  19. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/proxy/forensic_backend.py +11 -2
  20. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/proxy/main.py +14 -6
  21. {admina_framework-0.13.0 → admina_framework-0.13.1/admina_framework.egg-info}/PKG-INFO +52 -12
  22. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina_framework.egg-info/SOURCES.txt +1 -0
  23. {admina_framework-0.13.0 → admina_framework-0.13.1}/pyproject.toml +1 -1
  24. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_config_schema_validation.py +2 -1
  25. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_egress_analyze.py +38 -11
  26. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_egress_pipeline.py +36 -8
  27. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_enabled_surfaces.py +44 -0
  28. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_firewall_heuristic_config.py +57 -1
  29. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_forensic_fail_mode.py +99 -0
  30. admina_framework-0.13.1/tests/test_mcp_block_reason.py +148 -0
  31. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_metrics_gateway.py +24 -0
  32. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_pipeline_executor.py +15 -5
  33. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_request_size_cap.py +14 -0
  34. admina_framework-0.13.0/admina/cli/templates/env.j2 +0 -8
  35. {admina_framework-0.13.0 → admina_framework-0.13.1}/LICENSE +0 -0
  36. {admina_framework-0.13.0 → admina_framework-0.13.1}/NOTICE +0 -0
  37. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/cli/__init__.py +0 -0
  38. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/cli/commands/__init__.py +0 -0
  39. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/cli/forensic.py +0 -0
  40. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/cli/redteam.py +0 -0
  41. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/cli/templates/main.py.j2 +0 -0
  42. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/cli/templates/plugin.py.j2 +0 -0
  43. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/cli/templates/plugin_pyproject.toml.j2 +0 -0
  44. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/cli/templates/plugin_readme.md.j2 +0 -0
  45. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/cli/templates/plugin_test.py.j2 +0 -0
  46. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/core/__init__.py +0 -0
  47. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/core/config.py +0 -0
  48. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/core/event_bus.py +0 -0
  49. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/core/exception_log.py +0 -0
  50. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/core/jcs.py +0 -0
  51. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/core/offline.py +0 -0
  52. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/core/secretfile.py +0 -0
  53. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/core/secrets.py +0 -0
  54. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/core/trace_context.py +0 -0
  55. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/core/types.py +0 -0
  56. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/dashboard/__init__.py +0 -0
  57. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/dashboard/static/heimdall.png +0 -0
  58. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/dashboard/static/vendor/alpinejs.min.js +0 -0
  59. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/domains/__init__.py +0 -0
  60. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/domains/agent_security/__init__.py +0 -0
  61. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/domains/agent_security/coordination.py +0 -0
  62. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/domains/agent_security/fingerprint.py +0 -0
  63. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/domains/agent_security/loop_breaker.py +0 -0
  64. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/domains/agent_security/pattern_packs.py +0 -0
  65. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/domains/agent_security/pattern_timing.py +0 -0
  66. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/domains/agent_security/ruleset.py +0 -0
  67. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/domains/agent_security/scan_policy.py +0 -0
  68. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/domains/ai_infra/__init__.py +0 -0
  69. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/domains/ai_infra/llm_engine.py +0 -0
  70. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/domains/ai_infra/rag.py +0 -0
  71. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/domains/ai_infra/webui.py +0 -0
  72. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/domains/compliance/__init__.py +0 -0
  73. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/domains/compliance/ai_act_terms.py +0 -0
  74. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/domains/compliance/cross_regulation.py +0 -0
  75. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/domains/compliance/eu_ai_act.py +0 -0
  76. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/domains/compliance/forensic_files.py +0 -0
  77. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/domains/compliance/forensic_integrity.py +0 -0
  78. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/domains/compliance/gdpr.py +0 -0
  79. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/domains/compliance/nis2.py +0 -0
  80. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/domains/compliance/oisg_evidence.py +0 -0
  81. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/domains/compliance/otel.py +0 -0
  82. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/domains/compliance/schemas/oisg-evidence.schema.json +0 -0
  83. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/domains/data_sovereignty/__init__.py +0 -0
  84. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/domains/data_sovereignty/classification.py +0 -0
  85. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/domains/data_sovereignty/email_matching.py +0 -0
  86. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/domains/data_sovereignty/iban.py +0 -0
  87. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/domains/data_sovereignty/masking.py +0 -0
  88. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/domains/data_sovereignty/pii.py +0 -0
  89. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/domains/data_sovereignty/residency.py +0 -0
  90. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/engines/pii_plugins.py +0 -0
  91. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/engines/presidio.py +0 -0
  92. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/integrations/__init__.py +0 -0
  93. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/integrations/cheshirecat/__init__.py +0 -0
  94. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/integrations/cheshirecat/admina-plugin/admina_governance.py +0 -0
  95. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/integrations/crewai/__init__.py +0 -0
  96. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/integrations/crewai/callbacks.py +0 -0
  97. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/integrations/langchain/__init__.py +0 -0
  98. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/integrations/langchain/callbacks.py +0 -0
  99. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/integrations/n8n/__init__.py +0 -0
  100. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/integrations/openclaw/__init__.py +0 -0
  101. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/plugins/__init__.py +0 -0
  102. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/plugins/base.py +0 -0
  103. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/plugins/builtin/__init__.py +0 -0
  104. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/plugins/builtin/adapters/__init__.py +0 -0
  105. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/plugins/builtin/adapters/_streaming.py +0 -0
  106. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/plugins/builtin/adapters/anthropic.py +0 -0
  107. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/plugins/builtin/adapters/bedrock.py +0 -0
  108. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/plugins/builtin/adapters/gemini.py +0 -0
  109. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/plugins/builtin/adapters/mistral.py +0 -0
  110. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/plugins/builtin/adapters/ollama.py +0 -0
  111. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/plugins/builtin/adapters/openai.py +0 -0
  112. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/plugins/builtin/adapters/vllm.py +0 -0
  113. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/plugins/builtin/alerts/__init__.py +0 -0
  114. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/plugins/builtin/alerts/log.py +0 -0
  115. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/plugins/builtin/alerts/webhook.py +0 -0
  116. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/plugins/builtin/auth/__init__.py +0 -0
  117. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/plugins/builtin/auth/apikey.py +0 -0
  118. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/plugins/builtin/compliance/__init__.py +0 -0
  119. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/plugins/builtin/compliance/eu_ai_act.py +0 -0
  120. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/plugins/builtin/connectors/__init__.py +0 -0
  121. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/plugins/builtin/connectors/chromadb.py +0 -0
  122. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/plugins/builtin/connectors/filesystem.py +0 -0
  123. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/plugins/builtin/forensic/__init__.py +0 -0
  124. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/plugins/builtin/forensic/filesystem.py +0 -0
  125. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/plugins/builtin/guards/__init__.py +0 -0
  126. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/plugins/builtin/guards/guardrailsai_guard.py +0 -0
  127. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/plugins/builtin/pii/__init__.py +0 -0
  128. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/plugins/builtin/pii/spacy_regex.py +0 -0
  129. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/plugins/builtin/transports/__init__.py +0 -0
  130. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/plugins/builtin/transports/http_rest.py +0 -0
  131. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/plugins/registry.py +0 -0
  132. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/proxy/__init__.py +0 -0
  133. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/proxy/api/__init__.py +0 -0
  134. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/proxy/api/gateway.py +0 -0
  135. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/proxy/api/integration.py +0 -0
  136. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/proxy/body_limit.py +0 -0
  137. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/proxy/config.py +0 -0
  138. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/proxy/dashboard_session.py +0 -0
  139. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/proxy/decisions.py +0 -0
  140. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/proxy/engine_bridge.py +0 -0
  141. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/proxy/engine_report.py +0 -0
  142. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/proxy/env_check.py +0 -0
  143. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/proxy/forensic_probe.py +0 -0
  144. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/proxy/gateway_body.py +0 -0
  145. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/proxy/gateway_correlation.py +0 -0
  146. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/proxy/gateway_outcome.py +0 -0
  147. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/proxy/gateway_response_scan.py +0 -0
  148. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/proxy/gateway_scan.py +0 -0
  149. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/proxy/gateway_transport.py +0 -0
  150. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/proxy/gateway_upstreams.py +0 -0
  151. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/proxy/governance.py +0 -0
  152. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/proxy/log_format.py +0 -0
  153. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/proxy/loop_lag.py +0 -0
  154. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/proxy/multi_upstream.py +0 -0
  155. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/proxy/pipeline_executor.py +0 -0
  156. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/proxy/request_metrics.py +0 -0
  157. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/proxy/state.py +0 -0
  158. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/proxy/surfaces.py +0 -0
  159. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/py.typed +0 -0
  160. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/redteam/__init__.py +0 -0
  161. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/redteam/baselines/baseline.json +0 -0
  162. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/redteam/corpora/SHA256SUMS +0 -0
  163. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/redteam/corpora/coordination.jsonl +0 -0
  164. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/redteam/corpora/injection.jsonl +0 -0
  165. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/redteam/corpora/loop.jsonl +0 -0
  166. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/redteam/corpora/pii.jsonl +0 -0
  167. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/redteam/corpora.py +0 -0
  168. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/redteam/detectors.py +0 -0
  169. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/redteam/gate.py +0 -0
  170. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/redteam/metrics.py +0 -0
  171. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/redteam/report.py +0 -0
  172. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/redteam/runner.py +0 -0
  173. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/sdk/__init__.py +0 -0
  174. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/sdk/_compat.py +0 -0
  175. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/sdk/compliance_kit.py +0 -0
  176. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/sdk/errors.py +0 -0
  177. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/sdk/governed_agent.py +0 -0
  178. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/sdk/governed_data.py +0 -0
  179. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/sdk/governed_model.py +0 -0
  180. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/sdk/retry.py +0 -0
  181. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina/sdk/streaming.py +0 -0
  182. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina_framework.egg-info/dependency_links.txt +0 -0
  183. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina_framework.egg-info/entry_points.txt +0 -0
  184. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina_framework.egg-info/requires.txt +0 -0
  185. {admina_framework-0.13.0 → admina_framework-0.13.1}/admina_framework.egg-info/top_level.txt +0 -0
  186. {admina_framework-0.13.0 → admina_framework-0.13.1}/setup.cfg +0 -0
  187. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_admina_config_path.py +0 -0
  188. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_ai_act_terms.py +0 -0
  189. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_audit_api_source.py +0 -0
  190. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_auth_middleware_errors.py +0 -0
  191. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_banner_engine_info.py +0 -0
  192. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_benchmark_14us.py +0 -0
  193. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_bus_event_metadata.py +0 -0
  194. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_canary_no_content.py +0 -0
  195. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_check_versions.py +0 -0
  196. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_cli_forensic_export.py +0 -0
  197. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_cli_redteam.py +0 -0
  198. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_coordination.py +0 -0
  199. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_coordination_cli.py +0 -0
  200. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_coordination_corpus.py +0 -0
  201. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_coordination_wiring.py +0 -0
  202. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_core_config.py +0 -0
  203. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_dashboard_container.py +0 -0
  204. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_data_classifier_restricted.py +0 -0
  205. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_domains.py +0 -0
  206. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_domains_governance.py +0 -0
  207. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_egress_cli.py +0 -0
  208. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_egress_policy.py +0 -0
  209. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_egress_surfaces.py +0 -0
  210. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_engine_effective.py +0 -0
  211. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_engine_startup_errors.py +0 -0
  212. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_engines.py +0 -0
  213. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_entrypoint_script.py +0 -0
  214. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_error_disclosure.py +0 -0
  215. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_event_loop_lag_metric.py +0 -0
  216. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_fingerprint.py +0 -0
  217. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_firewall_it_baseline.py +0 -0
  218. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_firewall_it_benign.py +0 -0
  219. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_firewall_parity.py +0 -0
  220. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_firewall_pattern_ids.py +0 -0
  221. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_firewall_pattern_packs.py +0 -0
  222. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_firewall_pattern_timing.py +0 -0
  223. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_forensic_atomic_write.py +0 -0
  224. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_forensic_blackbox.py +0 -0
  225. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_forensic_config_coherence.py +0 -0
  226. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_forensic_gateway_records.py +0 -0
  227. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_forensic_incremental_verify.py +0 -0
  228. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_forensic_integrity.py +0 -0
  229. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_forensic_rebuilt_and_duplicates.py +0 -0
  230. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_forensic_record_signature.py +0 -0
  231. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_forensic_restart.py +0 -0
  232. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_forensic_s3_reads.py +0 -0
  233. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_forensic_volume.py +0 -0
  234. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_gateway_block_status.py +0 -0
  235. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_gateway_config.py +0 -0
  236. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_gateway_correlation.py +0 -0
  237. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_gateway_endpoints.py +0 -0
  238. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_gateway_errors.py +0 -0
  239. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_gateway_forward_body.py +0 -0
  240. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_gateway_governed_stream.py +0 -0
  241. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_gateway_guard_fail_mode.py +0 -0
  242. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_gateway_helpers.py +0 -0
  243. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_gateway_latency_bench.py +0 -0
  244. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_gateway_mount.py +0 -0
  245. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_gateway_outcome_headers.py +0 -0
  246. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_gateway_passthrough.py +0 -0
  247. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_gateway_pii_contract.py +0 -0
  248. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_gateway_ruleset_endpoint.py +0 -0
  249. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_gateway_scan_coverage.py +0 -0
  250. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_gateway_upstream_auth.py +0 -0
  251. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_gateway_upstream_routes.py +0 -0
  252. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_governance_pipeline.py +0 -0
  253. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_guard_fail_mode.py +0 -0
  254. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_health_fields.py +0 -0
  255. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_health_forensic_probe.py +0 -0
  256. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_iban_it.py +0 -0
  257. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_jcs.py +0 -0
  258. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_lazy_imports.py +0 -0
  259. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_log_format.py +0 -0
  260. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_mcp_transport.py +0 -0
  261. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_metrics_docs_auth.py +0 -0
  262. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_model_allowlist_post.py +0 -0
  263. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_offline_guarantee.py +0 -0
  264. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_oisg_evidence.py +0 -0
  265. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_otel_enabled_flag.py +0 -0
  266. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_pattern_probe.py +0 -0
  267. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_pii_email_matching.py +0 -0
  268. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_pii_mask_style.py +0 -0
  269. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_pii_plugin_engines.py +0 -0
  270. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_presidio_engine.py +0 -0
  271. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_proxy_dashboard_session.py +0 -0
  272. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_proxy_forensic_would_action.py +0 -0
  273. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_proxy_governance_mode_config.py +0 -0
  274. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_proxy_guard_fail_mode.py +0 -0
  275. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_proxy_mcp_response_pii.py +0 -0
  276. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_proxy_metrics_endpoint.py +0 -0
  277. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_proxy_minimal_extra.py +0 -0
  278. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_proxy_plugins.py +0 -0
  279. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_proxy_security.py +0 -0
  280. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_query_api_key_deprecation.py +0 -0
  281. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_record_decision.py +0 -0
  282. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_redaction_values_only.py +0 -0
  283. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_redteam_efficacy.py +0 -0
  284. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_redteam_external_corpora.py +0 -0
  285. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_redteam_lib.py +0 -0
  286. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_release_workflows.py +0 -0
  287. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_request_sha256.py +0 -0
  288. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_response_scan_option.py +0 -0
  289. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_ruleset_parity.py +0 -0
  290. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_ruleset_sha256.py +0 -0
  291. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_scan_depth.py +0 -0
  292. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_scan_policy.py +0 -0
  293. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_secret_files.py +0 -0
  294. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_unknown_admina_env.py +0 -0
  295. {admina_framework-0.13.0 → admina_framework-0.13.1}/tests/test_version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: admina-framework
3
- Version: 0.13.0
3
+ Version: 0.13.1
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>
@@ -439,6 +439,17 @@ dependency: one uvicorn serves the proxy API and the dashboard SPA on the
439
439
  same port. Use `--stack` for the production-like Docker compose, or
440
440
  `--with-llm` to also boot local LLM services.
441
441
 
442
+ Local mode uses the forensic backend of `FORENSIC_BACKEND` or of
443
+ `admina.yaml`, and memory when neither sets one. In the compose file that
444
+ `admina init` writes, the dashboard (`127.0.0.1:3000`), OTEL and the
445
+ `--with-llm` services listen on the loopback interface only; the dashboard
446
+ asks for `ADMINA_DASHBOARD_PASSWORD` and the API key (both shown by
447
+ `admina password show`). The proxy reaches the MCP server at
448
+ `UPSTREAM_MCP_URL` (default `http://host.docker.internal:9000`, an MCP
449
+ server on the host). `CLICKHOUSE_PASSWORD` and `GRAFANA_ADMIN_PASSWORD`
450
+ come from the `.env` that `admina dev` writes; a plain `docker compose up`
451
+ stops when they are not set.
452
+
442
453
  ## Dashboard
443
454
 
444
455
  Real-time governance dashboard on port 3000:
@@ -858,6 +869,12 @@ one trailing newline removed. A missing, unreadable or empty file, or a key
858
869
  set both directly and as a file, stops the proxy; the error names the
859
870
  setting and the path, never the key. `ADMINA_FORENSIC_STATE_KEY_FILE` inside
860
871
  the forensic directory stops it too: the key must be kept outside the store.
872
+ The built-in `apikey` auth provider reads `ADMINA_API_KEY` from the
873
+ environment only, and is loaded only when it is set there. A key given only
874
+ through `ADMINA_API_KEY_FILE` or `.env` is checked by the authentication
875
+ middleware itself (the same headers, the same constant-time comparison), and
876
+ `POST /api/v1/audit` then stamps `submitted_by: "api_key"` instead of
877
+ `"user:api_key_user"`.
861
878
 
862
879
  **Forensic store.** `FORENSIC_BACKEND` (`memory`, `filesystem`, `s3`) and
863
880
  `FORENSIC_BASE_DIR` choose where the forensic records go. When they are not
@@ -899,7 +916,12 @@ directory (UTC hour of the write, sequence number on eight digits), with
899
916
  `admina-forensic/1 record signature` under the chain-state key
900
917
  (`ADMINA_FORENSIC_STATE_KEY` or `ADMINA_FORENSIC_STATE_KEY_FILE`, kept
901
918
  outside the forensic directory); `record_sig_alg`: `hmac-sha256`. Without
902
- a key a record has `record_sig_alg: "none"` and no `record_sig`.
919
+ a key a record has `record_sig_alg: "none"` and no `record_sig`. Since
920
+ 0.13.1, when a store that holds signed records is opened without its
921
+ key, the proxy does not start in `closed` fail mode
922
+ (`ADMINA_FORENSIC_FAIL_MODE`) and logs a warning in `open` mode, where
923
+ the records it then writes are unsigned (a later verification with the
924
+ key reports `unsigned`).
903
925
 
904
926
  The chain state (`_chain_state.json`, with its HMAC-SHA256 in
905
927
  `_chain_state.json.sig` when a key is set) holds `record_count`,
@@ -974,7 +996,10 @@ introduced.
974
996
  **Audit records.** `POST /api/v1/audit` records the event it receives with
975
997
  `source: "api_v1_audit"` (a `source` in the request is kept as
976
998
  `client_source`) and `submitted_by`: the credential the request was admitted
977
- with (`api_key`, `append_key`, `user:<id>` or `unauthenticated`). An
999
+ with (`api_key`, `append_key`, `user:<id>` or `unauthenticated`). With
1000
+ `ADMINA_API_KEY` in the environment the built-in `apikey` auth provider
1001
+ admits API-key requests, stamped `user:api_key_user`; `api_key` is the stamp
1002
+ when the key comes only from `ADMINA_API_KEY_FILE` or `.env`. An
978
1003
  `event_type` of the records the proxy writes itself (`mcp_request`,
979
1004
  `mcp_response`, `gateway_request`, `gateway_response`, `gateway_response_scan`,
980
1005
  `policy_violation`, `chain_state_rebuilt`) is refused with `400`.
@@ -1423,18 +1448,18 @@ fields are always scanned.
1423
1448
 
1424
1449
  The scan follows the body 32 levels deep: the body is level 0, its fields
1425
1450
  level 1, and the JSON of tool call arguments is at the level of its string.
1426
- A request with a string nested deeper is blocked in `enforce` mode
1427
- (`X-Admina-Would-Action: BLOCK` in `observe` and `dry-run`), and its record
1428
- has `checks.scan_depth = {"action": "BLOCK", "reason":
1451
+ With the firewall on, a request with a string nested deeper is blocked in
1452
+ `enforce` mode (`X-Admina-Would-Action: BLOCK` in `observe` and `dry-run`),
1453
+ and its record has `checks.scan_depth = {"action": "BLOCK", "reason":
1429
1454
  "depth_limit_exceeded"}`. Tool call arguments nested deeper than the JSON
1430
1455
  parser reads are scanned as they are, and the request is blocked the same
1431
1456
  way.
1432
1457
 
1433
- `/mcp` and `/api/v1/validate` scan and redact to the same depth. With the
1434
- firewall or PII redaction on, a request holding a string, or a non-empty
1435
- object or array, past level 32 is blocked the same way, since that text
1436
- would be neither scanned nor redacted. `content` of `/api/v1/validate` must
1437
- be a string.
1458
+ `/mcp` scans and redacts to the same depth. With the firewall or PII
1459
+ redaction on, a request holding a string, or a non-empty object or array,
1460
+ past level 32 is blocked the same way, since that text would be neither
1461
+ scanned nor redacted. `content` of `/api/v1/validate` must be a string, so
1462
+ that block does not apply there.
1438
1463
 
1439
1464
  #### Scan scope
1440
1465
 
@@ -1479,6 +1504,10 @@ case-sensitive. The caller must keep these tags out of text written by
1479
1504
  untrusted parties, because the gateway cannot tell such text from its own
1480
1505
  blocks.
1481
1506
 
1507
+ `ruleset_sha256()` hashes the Admina version too (and the `admina-core`
1508
+ version with the Rust engine), so a ruleset hash changes with every release:
1509
+ recompute the hashes in `gateway.prescan_rulesets` after each upgrade.
1510
+
1482
1511
  Trust model: with scan policies on, the gateway takes the caller's word for
1483
1512
  what it has scanned. Any caller that holds the API key can send the header,
1484
1513
  and the ruleset it must declare is not a secret (it is on every response and
@@ -1719,7 +1748,10 @@ cd integrations/cheshirecat/admina-plugin
1719
1748
 
1720
1749
  <br>
1721
1750
 
1722
- Governs every LLM call and tool invocation in-process:
1751
+ Governs every LLM call and tool invocation in-process. Install
1752
+ `admina-framework[proxy,nlp]`: the loop detection that the callbacks turn
1753
+ on by default needs scikit-learn from `[proxy]` (or pass
1754
+ `loop_detection=False`).
1723
1755
 
1724
1756
  ```python
1725
1757
  from admina.integrations.langchain.callbacks import AdminaCallbackHandler
@@ -1967,6 +1999,14 @@ curl -X POST http://localhost:8080/api/compliance/classify \
1967
1999
  curl http://localhost:8080/api/dashboard/score
1968
2000
  ```
1969
2001
 
2002
+ A blocked `/mcp` call is answered with a JSON-RPC error (`-32600`, "Request
2003
+ blocked by Admina governance") whose `error.data` holds the `event_id` of
2004
+ the forensic record and a `reason`: `injection_detected` (firewall),
2005
+ `scan_depth_exceeded` (text nested deeper than the scan depth),
2006
+ `egress_refused` (egress policy), `guard_blocked` (a request guard, also a
2007
+ guard error under `ADMINA_GUARD_FAIL_MODE=closed`) or `response_blocked`
2008
+ (a response guard). Before 0.13.1 every block reported `injection_detected`.
2009
+
1970
2010
  </details>
1971
2011
 
1972
2012
  ## Project documents
@@ -355,6 +355,17 @@ dependency: one uvicorn serves the proxy API and the dashboard SPA on the
355
355
  same port. Use `--stack` for the production-like Docker compose, or
356
356
  `--with-llm` to also boot local LLM services.
357
357
 
358
+ Local mode uses the forensic backend of `FORENSIC_BACKEND` or of
359
+ `admina.yaml`, and memory when neither sets one. In the compose file that
360
+ `admina init` writes, the dashboard (`127.0.0.1:3000`), OTEL and the
361
+ `--with-llm` services listen on the loopback interface only; the dashboard
362
+ asks for `ADMINA_DASHBOARD_PASSWORD` and the API key (both shown by
363
+ `admina password show`). The proxy reaches the MCP server at
364
+ `UPSTREAM_MCP_URL` (default `http://host.docker.internal:9000`, an MCP
365
+ server on the host). `CLICKHOUSE_PASSWORD` and `GRAFANA_ADMIN_PASSWORD`
366
+ come from the `.env` that `admina dev` writes; a plain `docker compose up`
367
+ stops when they are not set.
368
+
358
369
  ## Dashboard
359
370
 
360
371
  Real-time governance dashboard on port 3000:
@@ -774,6 +785,12 @@ one trailing newline removed. A missing, unreadable or empty file, or a key
774
785
  set both directly and as a file, stops the proxy; the error names the
775
786
  setting and the path, never the key. `ADMINA_FORENSIC_STATE_KEY_FILE` inside
776
787
  the forensic directory stops it too: the key must be kept outside the store.
788
+ The built-in `apikey` auth provider reads `ADMINA_API_KEY` from the
789
+ environment only, and is loaded only when it is set there. A key given only
790
+ through `ADMINA_API_KEY_FILE` or `.env` is checked by the authentication
791
+ middleware itself (the same headers, the same constant-time comparison), and
792
+ `POST /api/v1/audit` then stamps `submitted_by: "api_key"` instead of
793
+ `"user:api_key_user"`.
777
794
 
778
795
  **Forensic store.** `FORENSIC_BACKEND` (`memory`, `filesystem`, `s3`) and
779
796
  `FORENSIC_BASE_DIR` choose where the forensic records go. When they are not
@@ -815,7 +832,12 @@ directory (UTC hour of the write, sequence number on eight digits), with
815
832
  `admina-forensic/1 record signature` under the chain-state key
816
833
  (`ADMINA_FORENSIC_STATE_KEY` or `ADMINA_FORENSIC_STATE_KEY_FILE`, kept
817
834
  outside the forensic directory); `record_sig_alg`: `hmac-sha256`. Without
818
- a key a record has `record_sig_alg: "none"` and no `record_sig`.
835
+ a key a record has `record_sig_alg: "none"` and no `record_sig`. Since
836
+ 0.13.1, when a store that holds signed records is opened without its
837
+ key, the proxy does not start in `closed` fail mode
838
+ (`ADMINA_FORENSIC_FAIL_MODE`) and logs a warning in `open` mode, where
839
+ the records it then writes are unsigned (a later verification with the
840
+ key reports `unsigned`).
819
841
 
820
842
  The chain state (`_chain_state.json`, with its HMAC-SHA256 in
821
843
  `_chain_state.json.sig` when a key is set) holds `record_count`,
@@ -890,7 +912,10 @@ introduced.
890
912
  **Audit records.** `POST /api/v1/audit` records the event it receives with
891
913
  `source: "api_v1_audit"` (a `source` in the request is kept as
892
914
  `client_source`) and `submitted_by`: the credential the request was admitted
893
- with (`api_key`, `append_key`, `user:<id>` or `unauthenticated`). An
915
+ with (`api_key`, `append_key`, `user:<id>` or `unauthenticated`). With
916
+ `ADMINA_API_KEY` in the environment the built-in `apikey` auth provider
917
+ admits API-key requests, stamped `user:api_key_user`; `api_key` is the stamp
918
+ when the key comes only from `ADMINA_API_KEY_FILE` or `.env`. An
894
919
  `event_type` of the records the proxy writes itself (`mcp_request`,
895
920
  `mcp_response`, `gateway_request`, `gateway_response`, `gateway_response_scan`,
896
921
  `policy_violation`, `chain_state_rebuilt`) is refused with `400`.
@@ -1339,18 +1364,18 @@ fields are always scanned.
1339
1364
 
1340
1365
  The scan follows the body 32 levels deep: the body is level 0, its fields
1341
1366
  level 1, and the JSON of tool call arguments is at the level of its string.
1342
- A request with a string nested deeper is blocked in `enforce` mode
1343
- (`X-Admina-Would-Action: BLOCK` in `observe` and `dry-run`), and its record
1344
- has `checks.scan_depth = {"action": "BLOCK", "reason":
1367
+ With the firewall on, a request with a string nested deeper is blocked in
1368
+ `enforce` mode (`X-Admina-Would-Action: BLOCK` in `observe` and `dry-run`),
1369
+ and its record has `checks.scan_depth = {"action": "BLOCK", "reason":
1345
1370
  "depth_limit_exceeded"}`. Tool call arguments nested deeper than the JSON
1346
1371
  parser reads are scanned as they are, and the request is blocked the same
1347
1372
  way.
1348
1373
 
1349
- `/mcp` and `/api/v1/validate` scan and redact to the same depth. With the
1350
- firewall or PII redaction on, a request holding a string, or a non-empty
1351
- object or array, past level 32 is blocked the same way, since that text
1352
- would be neither scanned nor redacted. `content` of `/api/v1/validate` must
1353
- be a string.
1374
+ `/mcp` scans and redacts to the same depth. With the firewall or PII
1375
+ redaction on, a request holding a string, or a non-empty object or array,
1376
+ past level 32 is blocked the same way, since that text would be neither
1377
+ scanned nor redacted. `content` of `/api/v1/validate` must be a string, so
1378
+ that block does not apply there.
1354
1379
 
1355
1380
  #### Scan scope
1356
1381
 
@@ -1395,6 +1420,10 @@ case-sensitive. The caller must keep these tags out of text written by
1395
1420
  untrusted parties, because the gateway cannot tell such text from its own
1396
1421
  blocks.
1397
1422
 
1423
+ `ruleset_sha256()` hashes the Admina version too (and the `admina-core`
1424
+ version with the Rust engine), so a ruleset hash changes with every release:
1425
+ recompute the hashes in `gateway.prescan_rulesets` after each upgrade.
1426
+
1398
1427
  Trust model: with scan policies on, the gateway takes the caller's word for
1399
1428
  what it has scanned. Any caller that holds the API key can send the header,
1400
1429
  and the ruleset it must declare is not a secret (it is on every response and
@@ -1635,7 +1664,10 @@ cd integrations/cheshirecat/admina-plugin
1635
1664
 
1636
1665
  <br>
1637
1666
 
1638
- Governs every LLM call and tool invocation in-process:
1667
+ Governs every LLM call and tool invocation in-process. Install
1668
+ `admina-framework[proxy,nlp]`: the loop detection that the callbacks turn
1669
+ on by default needs scikit-learn from `[proxy]` (or pass
1670
+ `loop_detection=False`).
1639
1671
 
1640
1672
  ```python
1641
1673
  from admina.integrations.langchain.callbacks import AdminaCallbackHandler
@@ -1883,6 +1915,14 @@ curl -X POST http://localhost:8080/api/compliance/classify \
1883
1915
  curl http://localhost:8080/api/dashboard/score
1884
1916
  ```
1885
1917
 
1918
+ A blocked `/mcp` call is answered with a JSON-RPC error (`-32600`, "Request
1919
+ blocked by Admina governance") whose `error.data` holds the `event_id` of
1920
+ the forensic record and a `reason`: `injection_detected` (firewall),
1921
+ `scan_depth_exceeded` (text nested deeper than the scan depth),
1922
+ `egress_refused` (egress policy), `guard_blocked` (a request guard, also a
1923
+ guard error under `ADMINA_GUARD_FAIL_MODE=closed`) or `response_blocked`
1924
+ (a response guard). Before 0.13.1 every block reported `injection_detected`.
1925
+
1886
1926
  </details>
1887
1927
 
1888
1928
  ## Project documents
@@ -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.13.0"
26
+ __version__ = "0.13.1"
27
27
 
28
28
  __all__ = [
29
29
  "__version__",
@@ -251,8 +251,10 @@ def init(
251
251
  for f in created:
252
252
  click.echo(f" ✓ {f}")
253
253
 
254
- # 4. Bootstrap secrets (first-time setup)
255
- _bootstrap_secrets(project_dir)
254
+ # 4. Bootstrap secrets (first-time setup). A project whose vault exists
255
+ # gets the vault's secrets in a .env created by this run.
256
+ if _bootstrap_secrets(project_dir) is None and ".env" in created:
257
+ SecretVault(project_dir).write_dotenv(project_dir / ".env")
256
258
 
257
259
  # 5. Docker compose pull (optional)
258
260
  if not no_pull and shutil.which("docker"):
@@ -570,8 +572,28 @@ def _require_proxy_extra_for_local_dev() -> None:
570
572
  raise SystemExit(1)
571
573
 
572
574
 
575
+ def _local_forensic_backend(env: dict[str, str], data: dict[str, object]) -> tuple[str, str]:
576
+ """The forensic backend the local proxy uses and where it comes from:
577
+ ``FORENSIC_BACKEND`` when set and not empty, else
578
+ ``domains.compliance.forensic.backend`` (or ``storage``) of admina.yaml,
579
+ else ``memory`` (the proxy's default, see admina.proxy.forensic_backend).
580
+ """
581
+ value = env.get("FORENSIC_BACKEND", "").strip().lower()
582
+ if value:
583
+ return value, "FORENSIC_BACKEND"
584
+ domains = data.get("domains")
585
+ compliance = domains.get("compliance") if isinstance(domains, dict) else None
586
+ forensic = compliance.get("forensic") if isinstance(compliance, dict) else None
587
+ if isinstance(forensic, dict):
588
+ value = str(forensic.get("backend") or forensic.get("storage") or "").strip().lower()
589
+ if value:
590
+ return ("s3" if value == "minio" else value), "admina.yaml"
591
+ return "memory", ""
592
+
593
+
573
594
  def _run_local(
574
595
  project_dir: Path,
596
+ data: dict[str, object],
575
597
  vault: SecretVault,
576
598
  *,
577
599
  no_browser: bool,
@@ -594,8 +616,9 @@ def _run_local(
594
616
 
595
617
  env = os.environ.copy()
596
618
  env.update(vault.export_env())
597
- # Local dev defaults — sane for single-user localhost.
598
- env.setdefault("FORENSIC_BACKEND", "memory")
619
+ # Local dev defaults — sane for single-user localhost. The forensic
620
+ # backend is not set here: the proxy reads FORENSIC_BACKEND, else the
621
+ # backend of admina.yaml, else uses memory.
599
622
  env.setdefault("OTEL_ENDPOINT", "")
600
623
  env.setdefault("REDIS_URL", "")
601
624
  env.setdefault("CLICKHOUSE_HOST", "")
@@ -622,7 +645,11 @@ def _run_local(
622
645
 
623
646
  click.echo(f"\n Starting Admina proxy + dashboard on http://{display_host}:{port}")
624
647
  click.echo(" Mode: local (no Docker)")
625
- click.echo(" Forensic backend: in-memory (events live for the process lifetime)")
648
+ forensic_backend, forensic_source = _local_forensic_backend(env, data)
649
+ if forensic_source:
650
+ click.echo(f" Forensic backend: {forensic_backend} ({forensic_source})")
651
+ else:
652
+ click.echo(" Forensic backend: in-memory (events live for the process lifetime)")
626
653
  if is_public:
627
654
  click.echo(
628
655
  f" ⚠ Listening on {host}:{port} — accessible from the LAN. "
@@ -848,6 +875,7 @@ def dev(
848
875
  bind_host = "0.0.0.0" if public else host
849
876
  _run_local(
850
877
  project_dir,
878
+ data,
851
879
  vault,
852
880
  no_browser=no_browser,
853
881
  port=port,
@@ -58,7 +58,8 @@ domains:
58
58
  forensic:
59
59
  # The proxy's forensic backend and directory. FORENSIC_BACKEND and
60
60
  # FORENSIC_BASE_DIR, when set, take precedence (the generated
61
- # docker-compose.yml sets both; `admina dev` sets FORENSIC_BACKEND).
61
+ # docker-compose.yml sets both). Without either, the proxy, `admina dev`
62
+ # included, keeps the records in memory.
62
63
  # backend: filesystem
63
64
  # base_dir: .admina/forensic
64
65
  bucket: forensic-blackbox
@@ -1,6 +1,9 @@
1
1
  # Docker Compose — {{ project_name }}
2
2
  # Generated by: admina init
3
3
  # Docs: https://admina.org/docs/docker
4
+ #
5
+ # Secrets come from .env, which `admina init` and `admina dev` write from the
6
+ # project's secrets vault (show them with `admina password show`).
4
7
 
5
8
  services:
6
9
 
@@ -17,13 +20,29 @@ services:
17
20
  - .env
18
21
  environment:
19
22
  - REDIS_URL=redis://redis:6379/0
23
+ {% if domains.compliance %}
20
24
  - CLICKHOUSE_HOST=clickhouse
21
25
  - CLICKHOUSE_PORT=8123
22
26
  - CLICKHOUSE_DB=admina
27
+ {% else %}
28
+ # No ClickHouse and no OTEL collector without the compliance domain.
29
+ - CLICKHOUSE_HOST=
30
+ {% endif %}
23
31
  - FORENSIC_BACKEND=filesystem
24
32
  - FORENSIC_BASE_DIR=/app/.admina/forensic
33
+ {% if domains.compliance %}
25
34
  - OTEL_ENDPOINT=http://otel-collector:4317
35
+ {% else %}
36
+ - OTEL_ENABLED=false
37
+ {% endif %}
38
+ # The MCP server the proxy forwards /mcp to. The default is port 9000
39
+ # of the Docker host; export UPSTREAM_MCP_URL before `docker compose up`
40
+ # (or `admina dev --stack`) to use another server.
41
+ - UPSTREAM_MCP_URL=${UPSTREAM_MCP_URL:-http://host.docker.internal:9000}
26
42
  - LOG_LEVEL=INFO
43
+ extra_hosts:
44
+ # host.docker.internal on Linux too (Docker Desktop defines it).
45
+ - "host.docker.internal:host-gateway"
27
46
  volumes:
28
47
  # Forensic records and chain state (FORENSIC_BASE_DIR), kept when the
29
48
  # container is re-created.
@@ -31,8 +50,10 @@ services:
31
50
  depends_on:
32
51
  redis:
33
52
  condition: service_healthy
53
+ {% if domains.compliance %}
34
54
  clickhouse:
35
55
  condition: service_healthy
56
+ {% endif %}
36
57
  healthcheck:
37
58
  test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
38
59
  interval: 10s
@@ -47,13 +68,27 @@ services:
47
68
  image: ghcr.io/admina-org/admina-dashboard:{{ admina_version }}
48
69
  container_name: {{ project_name }}-dashboard
49
70
  ports:
50
- - "3000:80"
71
+ # Loopback only. To reach the dashboard from other hosts, publish it
72
+ # behind TLS; it asks for ADMINA_DASHBOARD_PASSWORD (HTTP Basic Auth).
73
+ - "127.0.0.1:3000:80"
74
+ environment:
75
+ # With the API key the container needs a password: nginx adds the
76
+ # key only to the dashboard's read-only routes, behind Basic Auth.
77
+ - ADMINA_API_KEY=${ADMINA_API_KEY:-}
78
+ - ADMINA_DASHBOARD_PASSWORD=${ADMINA_DASHBOARD_PASSWORD:-}
51
79
  {% if domains.agent_security %}
52
80
  depends_on:
53
81
  - proxy
54
82
  {% endif %}
55
83
  healthcheck:
56
- test: ["CMD", "wget", "-qO-", "http://localhost:80/"]
84
+ # BusyBox wget on nginx:alpine resolves "localhost" to ::1 first and
85
+ # nginx listens on 0.0.0.0; force IPv4 to avoid spurious "Connection
86
+ # refused" failures.
87
+ {% if domains.agent_security %}
88
+ test: ["CMD", "wget", "-qO-", "http://127.0.0.1:80/health"]
89
+ {% else %}
90
+ test: ["CMD", "wget", "-qO-", "http://127.0.0.1:80/"]
91
+ {% endif %}
57
92
  interval: 30s
58
93
  timeout: 3s
59
94
  retries: 3
@@ -68,12 +103,12 @@ services:
68
103
  environment:
69
104
  - CLICKHOUSE_DB=admina
70
105
  - CLICKHOUSE_USER=default
71
- - CLICKHOUSE_PASSWORD=${CLICKHOUSE_PASSWORD:-changeme}
106
+ - CLICKHOUSE_PASSWORD=${CLICKHOUSE_PASSWORD:?CLICKHOUSE_PASSWORD must be set (admina dev writes it to .env)}
72
107
  - CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT=1
73
108
  volumes:
74
109
  - clickhouse-data:/var/lib/clickhouse
75
110
  healthcheck:
76
- test: ["CMD", "clickhouse-client", "--query", "SELECT 1"]
111
+ test: ["CMD", "clickhouse-client", "--user", "default", "--password", "${CLICKHOUSE_PASSWORD}", "--query", "SELECT 1"]
77
112
  interval: 5s
78
113
  timeout: 3s
79
114
  retries: 10
@@ -87,7 +122,7 @@ services:
87
122
  image: ollama/ollama:latest
88
123
  container_name: {{ project_name }}-ollama
89
124
  ports:
90
- - "11434:11434"
125
+ - "127.0.0.1:11434:11434" # no authentication: localhost only
91
126
  volumes:
92
127
  - ollama-data:/root/.ollama
93
128
  {% if gpu_vendor | default("none") == "nvidia" %}
@@ -119,7 +154,7 @@ services:
119
154
  image: chromadb/chroma:0.5.23
120
155
  container_name: {{ project_name }}-chromadb
121
156
  ports:
122
- - "8000:8000"
157
+ - "127.0.0.1:8000:8000" # no authentication: localhost only
123
158
  volumes:
124
159
  - chromadb-data:/chroma/chroma
125
160
  environment:
@@ -142,7 +177,8 @@ services:
142
177
  image: ghcr.io/open-webui/open-webui:main
143
178
  container_name: {{ project_name }}-webui
144
179
  ports:
145
- - "{{ ai_infra_webui_port | default(3080) }}:8080"
180
+ # Localhost only: sign-up is open, and the first account is the admin.
181
+ - "127.0.0.1:{{ ai_infra_webui_port | default(3080) }}:8080"
146
182
  volumes:
147
183
  - webui-data:/app/backend/data
148
184
  environment:
@@ -183,8 +219,8 @@ services:
183
219
  image: otel/opentelemetry-collector-contrib:0.96.0
184
220
  container_name: {{ project_name }}-otel
185
221
  ports:
186
- - "4317:4317"
187
- - "4318:4318"
222
+ - "127.0.0.1:4317:4317" # OTLP gRPC (localhost only)
223
+ - "127.0.0.1:4318:4318" # OTLP HTTP (localhost only)
188
224
  depends_on:
189
225
  clickhouse:
190
226
  condition: service_healthy
@@ -201,7 +237,7 @@ services:
201
237
  - "3001:3000"
202
238
  environment:
203
239
  - GF_SECURITY_ADMIN_USER=admin
204
- - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD:-admina}
240
+ - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD:?GRAFANA_ADMIN_PASSWORD must be set (admina dev writes it to .env)}
205
241
  - GF_USERS_ALLOW_SIGN_UP=false
206
242
  volumes:
207
243
  - grafana-data:/var/lib/grafana
@@ -0,0 +1,7 @@
1
+ # {{ project_name }} — Environment variables
2
+ # Generated by: admina init
3
+ # The secrets (ADMINA_API_KEY, ADMINA_DASHBOARD_PASSWORD, CLICKHOUSE_PASSWORD,
4
+ # GRAFANA_ADMIN_PASSWORD, WEBUI_SECRET_KEY) are written here from the
5
+ # project's secrets vault by `admina init` and `admina dev`.
6
+
7
+ LOG_LEVEL=INFO
@@ -19,8 +19,8 @@ paths (``domains.agent_security.firewall.pattern_packs``,
19
19
  ``alert_channels[0].url``):
20
20
 
21
21
  - **errors**: values of the wrong type, each as ``<path>: must be …``
22
- (true or false, an integer, a number, a string, a list of strings, a list
23
- of mappings, a mapping);
22
+ (true or false, an integer, a number, a finite number greater than 0, a
23
+ string, a list of strings, a list of mappings, a mapping);
24
24
  - **unknown**: keys the schema does not know.
25
25
 
26
26
  An empty value (null) is not checked: the reader of the key treats it as
@@ -35,28 +35,43 @@ malformed entry is skipped with a warning).
35
35
 
36
36
  from __future__ import annotations
37
37
 
38
+ import math
38
39
  from collections.abc import Mapping
39
40
  from dataclasses import dataclass, field
40
41
  from typing import Any
41
42
 
42
- __all__ = ["SCHEMA", "SchemaProblems", "find_problems"]
43
+ __all__ = ["SCHEMA", "SchemaProblems", "find_problems", "positive_finite_number"]
44
+
45
+
46
+ def positive_finite_number(value: Any) -> bool:
47
+ """Whether *value* is a finite number greater than 0 (an int or a float,
48
+ not a bool)."""
49
+ return (
50
+ not isinstance(value, bool)
51
+ and isinstance(value, int | float)
52
+ and math.isfinite(value)
53
+ and value > 0
54
+ )
43
55
 
44
56
 
45
57
  @dataclass(frozen=True)
46
58
  class _Scalar:
47
- kind: str # bool | int | number | str
59
+ kind: str # bool | int | number | positive | str
48
60
 
49
61
  def describe(self) -> str:
50
62
  return {
51
63
  "bool": "true or false",
52
64
  "int": "an integer",
53
65
  "number": "a number",
66
+ "positive": "a finite number greater than 0",
54
67
  "str": "a string",
55
68
  }[self.kind]
56
69
 
57
70
  def accepts(self, value: Any) -> bool:
58
71
  if self.kind == "bool":
59
72
  return isinstance(value, bool)
73
+ if self.kind == "positive":
74
+ return positive_finite_number(value)
60
75
  if isinstance(value, bool):
61
76
  return False
62
77
  if self.kind == "int":
@@ -117,6 +132,7 @@ class _List:
117
132
  BOOL = _Scalar("bool")
118
133
  INT = _Scalar("int")
119
134
  NUMBER = _Scalar("number")
135
+ POSITIVE = _Scalar("positive")
120
136
  STR = _Scalar("str")
121
137
  STRINGS = _List(STR)
122
138
  ANY = _Any()
@@ -181,7 +197,10 @@ SCHEMA = _Section(
181
197
  {
182
198
  "enabled": BOOL,
183
199
  "mode": STR,
184
- "heuristic_threshold": NUMBER,
200
+ # Read by the Python firewall only, and
201
+ # refused here so that an invalid value
202
+ # stops either engine.
203
+ "heuristic_threshold": POSITIVE,
185
204
  "allowed_tags": STRINGS,
186
205
  "custom_patterns": _List(ANY),
187
206
  "disabled_categories": STRINGS,
@@ -921,7 +921,7 @@ function dashboard() {
921
921
  max: 25,
922
922
  hint: noAssessment ? 'No gap analysis run yet — see EU AI Act card' : null,
923
923
  },
924
- { key: 'no_recent_attacks', label: 'No blocked attacks (24h)', value: bd.no_recent_attacks ?? 0, max: 15 },
924
+ { key: 'no_recent_attacks', label: 'No blocked requests (since start)', value: bd.no_recent_attacks ?? 0, max: 15 },
925
925
  { key: 'forensic_chain_valid', label: 'Forensic chain valid', value: bd.forensic_chain_valid ?? 0, max: 10 },
926
926
  ];
927
927
  },
@@ -41,6 +41,7 @@ from typing import Any
41
41
  from urllib.parse import urlsplit
42
42
 
43
43
  from admina.core.types import RiskLevel
44
+ from admina.domains.governance import SCAN_DEPTH
44
45
 
45
46
  __all__ = [
46
47
  "EGRESS_SURFACES",
@@ -60,9 +61,9 @@ logger = logging.getLogger("admina.egress")
60
61
  #: Surfaces the egress stage can run on (``agent_security.egress.surfaces``).
61
62
  EGRESS_SURFACES = ("gateway", "mcp", "integration", "sdk")
62
63
 
63
- # Mirrors _MAX_SCAN_DEPTH in admina/domains/governance.py so the egress walk
64
- # and the PII/firewall walk agree on how deep a payload is inspected.
65
- _MAX_SCAN_DEPTH = 6
64
+ # The walks below stop at the pipeline's SCAN_DEPTH, so egress and the
65
+ # PII/firewall walk agree on how deep a payload is inspected: a call the
66
+ # firewall scans in full is never refused by egress for its depth alone.
66
67
 
67
68
  # Argument names that declare a network destination. Their presence means the
68
69
  # call is an egress attempt even when the value cannot be resolved.
@@ -182,7 +183,7 @@ def _walk(
182
183
  A truncated walk means part of the arguments was never inspected, so the
183
184
  caller cannot claim the call has no destination — see :func:`analyze`.
184
185
  """
185
- if depth > _MAX_SCAN_DEPTH:
186
+ if depth > SCAN_DEPTH:
186
187
  # Only a string, dict or list could have hidden a destination; an
187
188
  # int, float, bool or None could not, so skipping one loses nothing
188
189
  # and must not be reported as an incomplete scan.
@@ -221,7 +222,7 @@ def _walk(
221
222
 
222
223
  def _classify_write_shaped(obj: Any, depth: int) -> str | None:
223
224
  """Return the reason the call is payload-bearing, or None."""
224
- if depth > _MAX_SCAN_DEPTH:
225
+ if depth > SCAN_DEPTH:
225
226
  return None
226
227
  if isinstance(obj, str):
227
228
  # Bare hostnames are recognised here regardless of the key: the
@@ -275,7 +276,7 @@ def _collect_payload_fields(obj: Any, depth: int, found: list[str]) -> None:
275
276
  destination and carries a payload, and the payload is what this
276
277
  function is for.
277
278
  """
278
- if depth > _MAX_SCAN_DEPTH:
279
+ if depth > SCAN_DEPTH:
279
280
  return
280
281
  if isinstance(obj, str):
281
282
  # A host or URL says where the call goes, which is what the fan-in
@@ -351,7 +352,7 @@ def payload_fields(params: Any) -> list[str]:
351
352
 
352
353
 
353
354
  def _remote_hint(obj: Any, depth: int = 0) -> bool | None:
354
- if depth > _MAX_SCAN_DEPTH:
355
+ if depth > SCAN_DEPTH:
355
356
  return None
356
357
  if isinstance(obj, dict):
357
358
  for key, value in obj.items():
@@ -19,13 +19,13 @@ Dual-layer defense: regex pattern matching + heuristic analysis.
19
19
 
20
20
  import base64
21
21
  import logging
22
- import math
23
22
  import re
24
23
  import time
25
24
  import unicodedata
26
25
  from collections.abc import Callable, Iterable
27
26
  from typing import TYPE_CHECKING, Any, NamedTuple
28
27
 
28
+ from admina.core.config_schema import positive_finite_number
29
29
  from admina.core.types import RiskLevel
30
30
 
31
31
  if TYPE_CHECKING:
@@ -809,12 +809,7 @@ def parse_custom_patterns(
809
809
 
810
810
 
811
811
  def _threshold(value: Any) -> float:
812
- if (
813
- isinstance(value, bool)
814
- or not isinstance(value, (int, float))
815
- or not math.isfinite(value)
816
- or value <= 0
817
- ):
812
+ if not positive_finite_number(value):
818
813
  raise ValueError(
819
814
  "agent_security.firewall.heuristic_threshold must be a finite number "
820
815
  f"greater than 0 (got {value!r})"