admina-framework 0.13.0__tar.gz → 0.13.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (296) hide show
  1. {admina_framework-0.13.0/admina_framework.egg-info → admina_framework-0.13.2}/PKG-INFO +58 -13
  2. {admina_framework-0.13.0 → admina_framework-0.13.2}/README.md +56 -11
  3. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/__init__.py +1 -1
  4. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/cli/main.py +33 -5
  5. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/cli/templates/admina.yaml.j2 +2 -1
  6. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/cli/templates/docker-compose.yml.j2 +46 -10
  7. admina_framework-0.13.2/admina/cli/templates/env.j2 +7 -0
  8. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/core/config_schema.py +24 -5
  9. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/dashboard/static/index.html +1 -1
  10. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/domains/agent_security/egress.py +8 -7
  11. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/domains/agent_security/firewall.py +2 -7
  12. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/domains/compliance/forensic.py +35 -1
  13. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/domains/compliance/oisg.py +47 -17
  14. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/domains/governance.py +25 -1
  15. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/engines/__init__.py +4 -5
  16. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/integrations/_engines.py +17 -2
  17. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/plugins/builtin/transports/mcp.py +64 -2
  18. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/proxy/api/dashboard.py +25 -10
  19. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/proxy/forensic_backend.py +11 -2
  20. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/proxy/main.py +14 -6
  21. {admina_framework-0.13.0 → admina_framework-0.13.2/admina_framework.egg-info}/PKG-INFO +58 -13
  22. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina_framework.egg-info/SOURCES.txt +2 -0
  23. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina_framework.egg-info/requires.txt +1 -1
  24. {admina_framework-0.13.0 → admina_framework-0.13.2}/pyproject.toml +2 -2
  25. admina_framework-0.13.2/tests/test_admina_alias.py +56 -0
  26. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_check_versions.py +15 -2
  27. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_config_schema_validation.py +2 -1
  28. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_egress_analyze.py +38 -11
  29. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_egress_pipeline.py +36 -8
  30. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_enabled_surfaces.py +44 -0
  31. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_firewall_heuristic_config.py +57 -1
  32. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_forensic_fail_mode.py +99 -0
  33. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_iban_it.py +3 -0
  34. admina_framework-0.13.2/tests/test_mcp_block_reason.py +148 -0
  35. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_metrics_gateway.py +24 -0
  36. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_pipeline_executor.py +15 -5
  37. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_request_size_cap.py +14 -0
  38. admina_framework-0.13.0/admina/cli/templates/env.j2 +0 -8
  39. {admina_framework-0.13.0 → admina_framework-0.13.2}/LICENSE +0 -0
  40. {admina_framework-0.13.0 → admina_framework-0.13.2}/NOTICE +0 -0
  41. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/cli/__init__.py +0 -0
  42. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/cli/commands/__init__.py +0 -0
  43. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/cli/forensic.py +0 -0
  44. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/cli/redteam.py +0 -0
  45. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/cli/templates/main.py.j2 +0 -0
  46. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/cli/templates/plugin.py.j2 +0 -0
  47. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/cli/templates/plugin_pyproject.toml.j2 +0 -0
  48. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/cli/templates/plugin_readme.md.j2 +0 -0
  49. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/cli/templates/plugin_test.py.j2 +0 -0
  50. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/core/__init__.py +0 -0
  51. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/core/config.py +0 -0
  52. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/core/event_bus.py +0 -0
  53. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/core/exception_log.py +0 -0
  54. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/core/jcs.py +0 -0
  55. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/core/offline.py +0 -0
  56. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/core/secretfile.py +0 -0
  57. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/core/secrets.py +0 -0
  58. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/core/trace_context.py +0 -0
  59. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/core/types.py +0 -0
  60. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/dashboard/__init__.py +0 -0
  61. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/dashboard/static/heimdall.png +0 -0
  62. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/dashboard/static/vendor/alpinejs.min.js +0 -0
  63. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/domains/__init__.py +0 -0
  64. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/domains/agent_security/__init__.py +0 -0
  65. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/domains/agent_security/coordination.py +0 -0
  66. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/domains/agent_security/fingerprint.py +0 -0
  67. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/domains/agent_security/loop_breaker.py +0 -0
  68. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/domains/agent_security/pattern_packs.py +0 -0
  69. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/domains/agent_security/pattern_timing.py +0 -0
  70. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/domains/agent_security/ruleset.py +0 -0
  71. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/domains/agent_security/scan_policy.py +0 -0
  72. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/domains/ai_infra/__init__.py +0 -0
  73. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/domains/ai_infra/llm_engine.py +0 -0
  74. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/domains/ai_infra/rag.py +0 -0
  75. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/domains/ai_infra/webui.py +0 -0
  76. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/domains/compliance/__init__.py +0 -0
  77. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/domains/compliance/ai_act_terms.py +0 -0
  78. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/domains/compliance/cross_regulation.py +0 -0
  79. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/domains/compliance/eu_ai_act.py +0 -0
  80. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/domains/compliance/forensic_files.py +0 -0
  81. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/domains/compliance/forensic_integrity.py +0 -0
  82. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/domains/compliance/gdpr.py +0 -0
  83. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/domains/compliance/nis2.py +0 -0
  84. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/domains/compliance/oisg_evidence.py +0 -0
  85. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/domains/compliance/otel.py +0 -0
  86. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/domains/compliance/schemas/oisg-evidence.schema.json +0 -0
  87. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/domains/data_sovereignty/__init__.py +0 -0
  88. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/domains/data_sovereignty/classification.py +0 -0
  89. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/domains/data_sovereignty/email_matching.py +0 -0
  90. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/domains/data_sovereignty/iban.py +0 -0
  91. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/domains/data_sovereignty/masking.py +0 -0
  92. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/domains/data_sovereignty/pii.py +0 -0
  93. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/domains/data_sovereignty/residency.py +0 -0
  94. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/engines/pii_plugins.py +0 -0
  95. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/engines/presidio.py +0 -0
  96. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/integrations/__init__.py +0 -0
  97. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/integrations/cheshirecat/__init__.py +0 -0
  98. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/integrations/cheshirecat/admina-plugin/admina_governance.py +0 -0
  99. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/integrations/crewai/__init__.py +0 -0
  100. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/integrations/crewai/callbacks.py +0 -0
  101. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/integrations/langchain/__init__.py +0 -0
  102. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/integrations/langchain/callbacks.py +0 -0
  103. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/integrations/n8n/__init__.py +0 -0
  104. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/integrations/openclaw/__init__.py +0 -0
  105. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/plugins/__init__.py +0 -0
  106. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/plugins/base.py +0 -0
  107. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/plugins/builtin/__init__.py +0 -0
  108. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/plugins/builtin/adapters/__init__.py +0 -0
  109. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/plugins/builtin/adapters/_streaming.py +0 -0
  110. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/plugins/builtin/adapters/anthropic.py +0 -0
  111. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/plugins/builtin/adapters/bedrock.py +0 -0
  112. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/plugins/builtin/adapters/gemini.py +0 -0
  113. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/plugins/builtin/adapters/mistral.py +0 -0
  114. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/plugins/builtin/adapters/ollama.py +0 -0
  115. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/plugins/builtin/adapters/openai.py +0 -0
  116. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/plugins/builtin/adapters/vllm.py +0 -0
  117. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/plugins/builtin/alerts/__init__.py +0 -0
  118. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/plugins/builtin/alerts/log.py +0 -0
  119. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/plugins/builtin/alerts/webhook.py +0 -0
  120. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/plugins/builtin/auth/__init__.py +0 -0
  121. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/plugins/builtin/auth/apikey.py +0 -0
  122. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/plugins/builtin/compliance/__init__.py +0 -0
  123. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/plugins/builtin/compliance/eu_ai_act.py +0 -0
  124. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/plugins/builtin/connectors/__init__.py +0 -0
  125. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/plugins/builtin/connectors/chromadb.py +0 -0
  126. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/plugins/builtin/connectors/filesystem.py +0 -0
  127. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/plugins/builtin/forensic/__init__.py +0 -0
  128. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/plugins/builtin/forensic/filesystem.py +0 -0
  129. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/plugins/builtin/guards/__init__.py +0 -0
  130. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/plugins/builtin/guards/guardrailsai_guard.py +0 -0
  131. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/plugins/builtin/pii/__init__.py +0 -0
  132. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/plugins/builtin/pii/spacy_regex.py +0 -0
  133. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/plugins/builtin/transports/__init__.py +0 -0
  134. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/plugins/builtin/transports/http_rest.py +0 -0
  135. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/plugins/registry.py +0 -0
  136. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/proxy/__init__.py +0 -0
  137. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/proxy/api/__init__.py +0 -0
  138. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/proxy/api/gateway.py +0 -0
  139. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/proxy/api/integration.py +0 -0
  140. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/proxy/body_limit.py +0 -0
  141. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/proxy/config.py +0 -0
  142. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/proxy/dashboard_session.py +0 -0
  143. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/proxy/decisions.py +0 -0
  144. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/proxy/engine_bridge.py +0 -0
  145. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/proxy/engine_report.py +0 -0
  146. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/proxy/env_check.py +0 -0
  147. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/proxy/forensic_probe.py +0 -0
  148. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/proxy/gateway_body.py +0 -0
  149. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/proxy/gateway_correlation.py +0 -0
  150. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/proxy/gateway_outcome.py +0 -0
  151. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/proxy/gateway_response_scan.py +0 -0
  152. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/proxy/gateway_scan.py +0 -0
  153. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/proxy/gateway_transport.py +0 -0
  154. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/proxy/gateway_upstreams.py +0 -0
  155. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/proxy/governance.py +0 -0
  156. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/proxy/log_format.py +0 -0
  157. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/proxy/loop_lag.py +0 -0
  158. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/proxy/multi_upstream.py +0 -0
  159. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/proxy/pipeline_executor.py +0 -0
  160. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/proxy/request_metrics.py +0 -0
  161. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/proxy/state.py +0 -0
  162. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/proxy/surfaces.py +0 -0
  163. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/py.typed +0 -0
  164. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/redteam/__init__.py +0 -0
  165. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/redteam/baselines/baseline.json +0 -0
  166. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/redteam/corpora/SHA256SUMS +0 -0
  167. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/redteam/corpora/coordination.jsonl +0 -0
  168. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/redteam/corpora/injection.jsonl +0 -0
  169. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/redteam/corpora/loop.jsonl +0 -0
  170. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/redteam/corpora/pii.jsonl +0 -0
  171. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/redteam/corpora.py +0 -0
  172. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/redteam/detectors.py +0 -0
  173. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/redteam/gate.py +0 -0
  174. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/redteam/metrics.py +0 -0
  175. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/redteam/report.py +0 -0
  176. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/redteam/runner.py +0 -0
  177. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/sdk/__init__.py +0 -0
  178. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/sdk/_compat.py +0 -0
  179. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/sdk/compliance_kit.py +0 -0
  180. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/sdk/errors.py +0 -0
  181. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/sdk/governed_agent.py +0 -0
  182. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/sdk/governed_data.py +0 -0
  183. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/sdk/governed_model.py +0 -0
  184. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/sdk/retry.py +0 -0
  185. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina/sdk/streaming.py +0 -0
  186. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina_framework.egg-info/dependency_links.txt +0 -0
  187. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina_framework.egg-info/entry_points.txt +0 -0
  188. {admina_framework-0.13.0 → admina_framework-0.13.2}/admina_framework.egg-info/top_level.txt +0 -0
  189. {admina_framework-0.13.0 → admina_framework-0.13.2}/setup.cfg +0 -0
  190. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_admina_config_path.py +0 -0
  191. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_ai_act_terms.py +0 -0
  192. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_audit_api_source.py +0 -0
  193. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_auth_middleware_errors.py +0 -0
  194. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_banner_engine_info.py +0 -0
  195. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_benchmark_14us.py +0 -0
  196. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_bus_event_metadata.py +0 -0
  197. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_canary_no_content.py +0 -0
  198. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_cli_forensic_export.py +0 -0
  199. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_cli_redteam.py +0 -0
  200. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_coordination.py +0 -0
  201. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_coordination_cli.py +0 -0
  202. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_coordination_corpus.py +0 -0
  203. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_coordination_wiring.py +0 -0
  204. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_core_config.py +0 -0
  205. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_dashboard_container.py +0 -0
  206. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_data_classifier_restricted.py +0 -0
  207. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_domains.py +0 -0
  208. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_domains_governance.py +0 -0
  209. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_egress_cli.py +0 -0
  210. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_egress_policy.py +0 -0
  211. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_egress_surfaces.py +0 -0
  212. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_engine_effective.py +0 -0
  213. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_engine_startup_errors.py +0 -0
  214. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_engines.py +0 -0
  215. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_entrypoint_script.py +0 -0
  216. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_error_disclosure.py +0 -0
  217. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_event_loop_lag_metric.py +0 -0
  218. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_fingerprint.py +0 -0
  219. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_firewall_it_baseline.py +0 -0
  220. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_firewall_it_benign.py +0 -0
  221. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_firewall_parity.py +0 -0
  222. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_firewall_pattern_ids.py +0 -0
  223. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_firewall_pattern_packs.py +0 -0
  224. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_firewall_pattern_timing.py +0 -0
  225. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_forensic_atomic_write.py +0 -0
  226. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_forensic_blackbox.py +0 -0
  227. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_forensic_config_coherence.py +0 -0
  228. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_forensic_gateway_records.py +0 -0
  229. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_forensic_incremental_verify.py +0 -0
  230. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_forensic_integrity.py +0 -0
  231. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_forensic_rebuilt_and_duplicates.py +0 -0
  232. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_forensic_record_signature.py +0 -0
  233. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_forensic_restart.py +0 -0
  234. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_forensic_s3_reads.py +0 -0
  235. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_forensic_volume.py +0 -0
  236. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_gateway_block_status.py +0 -0
  237. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_gateway_config.py +0 -0
  238. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_gateway_correlation.py +0 -0
  239. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_gateway_endpoints.py +0 -0
  240. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_gateway_errors.py +0 -0
  241. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_gateway_forward_body.py +0 -0
  242. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_gateway_governed_stream.py +0 -0
  243. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_gateway_guard_fail_mode.py +0 -0
  244. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_gateway_helpers.py +0 -0
  245. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_gateway_latency_bench.py +0 -0
  246. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_gateway_mount.py +0 -0
  247. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_gateway_outcome_headers.py +0 -0
  248. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_gateway_passthrough.py +0 -0
  249. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_gateway_pii_contract.py +0 -0
  250. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_gateway_ruleset_endpoint.py +0 -0
  251. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_gateway_scan_coverage.py +0 -0
  252. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_gateway_upstream_auth.py +0 -0
  253. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_gateway_upstream_routes.py +0 -0
  254. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_governance_pipeline.py +0 -0
  255. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_guard_fail_mode.py +0 -0
  256. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_health_fields.py +0 -0
  257. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_health_forensic_probe.py +0 -0
  258. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_jcs.py +0 -0
  259. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_lazy_imports.py +0 -0
  260. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_log_format.py +0 -0
  261. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_mcp_transport.py +0 -0
  262. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_metrics_docs_auth.py +0 -0
  263. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_model_allowlist_post.py +0 -0
  264. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_offline_guarantee.py +0 -0
  265. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_oisg_evidence.py +0 -0
  266. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_otel_enabled_flag.py +0 -0
  267. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_pattern_probe.py +0 -0
  268. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_pii_email_matching.py +0 -0
  269. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_pii_mask_style.py +0 -0
  270. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_pii_plugin_engines.py +0 -0
  271. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_presidio_engine.py +0 -0
  272. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_proxy_dashboard_session.py +0 -0
  273. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_proxy_forensic_would_action.py +0 -0
  274. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_proxy_governance_mode_config.py +0 -0
  275. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_proxy_guard_fail_mode.py +0 -0
  276. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_proxy_mcp_response_pii.py +0 -0
  277. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_proxy_metrics_endpoint.py +0 -0
  278. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_proxy_minimal_extra.py +0 -0
  279. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_proxy_plugins.py +0 -0
  280. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_proxy_security.py +0 -0
  281. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_query_api_key_deprecation.py +0 -0
  282. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_record_decision.py +0 -0
  283. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_redaction_values_only.py +0 -0
  284. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_redteam_efficacy.py +0 -0
  285. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_redteam_external_corpora.py +0 -0
  286. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_redteam_lib.py +0 -0
  287. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_release_workflows.py +0 -0
  288. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_request_sha256.py +0 -0
  289. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_response_scan_option.py +0 -0
  290. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_ruleset_parity.py +0 -0
  291. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_ruleset_sha256.py +0 -0
  292. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_scan_depth.py +0 -0
  293. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_scan_policy.py +0 -0
  294. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_secret_files.py +0 -0
  295. {admina_framework-0.13.0 → admina_framework-0.13.2}/tests/test_unknown_admina_env.py +0 -0
  296. {admina_framework-0.13.0 → admina_framework-0.13.2}/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.2
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>
@@ -69,7 +69,7 @@ Requires-Dist: ollama<1,>=0.3; extra == "ollama"
69
69
  Provides-Extra: anthropic
70
70
  Requires-Dist: anthropic<2,>=0.39; extra == "anthropic"
71
71
  Provides-Extra: mistral
72
- Requires-Dist: mistralai<3,>=1.0; extra == "mistral"
72
+ Requires-Dist: mistralai<4,>=1.0; extra == "mistral"
73
73
  Provides-Extra: gemini
74
74
  Requires-Dist: google-genai<3,>=1.0; extra == "gemini"
75
75
  Provides-Extra: bedrock
@@ -258,6 +258,11 @@ pip install admina-framework
258
258
  > matters more than that extra coverage. See
259
259
  > [Performance](#performance--hybrid-python--rust-engine) for the trade-off.
260
260
 
261
+ The PyPI package `admina` is an alias: `pip install admina` installs
262
+ `admina-framework` at the same version, and `admina[X]` installs
263
+ `admina-framework[X]` for every extra above. It has no code of its own, so
264
+ both names install the same `admina` module.
265
+
261
266
  ### Or install from source
262
267
 
263
268
  ```bash
@@ -439,6 +444,17 @@ dependency: one uvicorn serves the proxy API and the dashboard SPA on the
439
444
  same port. Use `--stack` for the production-like Docker compose, or
440
445
  `--with-llm` to also boot local LLM services.
441
446
 
447
+ Local mode uses the forensic backend of `FORENSIC_BACKEND` or of
448
+ `admina.yaml`, and memory when neither sets one. In the compose file that
449
+ `admina init` writes, the dashboard (`127.0.0.1:3000`), OTEL and the
450
+ `--with-llm` services listen on the loopback interface only; the dashboard
451
+ asks for `ADMINA_DASHBOARD_PASSWORD` and the API key (both shown by
452
+ `admina password show`). The proxy reaches the MCP server at
453
+ `UPSTREAM_MCP_URL` (default `http://host.docker.internal:9000`, an MCP
454
+ server on the host). `CLICKHOUSE_PASSWORD` and `GRAFANA_ADMIN_PASSWORD`
455
+ come from the `.env` that `admina dev` writes; a plain `docker compose up`
456
+ stops when they are not set.
457
+
442
458
  ## Dashboard
443
459
 
444
460
  Real-time governance dashboard on port 3000:
@@ -858,6 +874,12 @@ one trailing newline removed. A missing, unreadable or empty file, or a key
858
874
  set both directly and as a file, stops the proxy; the error names the
859
875
  setting and the path, never the key. `ADMINA_FORENSIC_STATE_KEY_FILE` inside
860
876
  the forensic directory stops it too: the key must be kept outside the store.
877
+ The built-in `apikey` auth provider reads `ADMINA_API_KEY` from the
878
+ environment only, and is loaded only when it is set there. A key given only
879
+ through `ADMINA_API_KEY_FILE` or `.env` is checked by the authentication
880
+ middleware itself (the same headers, the same constant-time comparison), and
881
+ `POST /api/v1/audit` then stamps `submitted_by: "api_key"` instead of
882
+ `"user:api_key_user"`.
861
883
 
862
884
  **Forensic store.** `FORENSIC_BACKEND` (`memory`, `filesystem`, `s3`) and
863
885
  `FORENSIC_BASE_DIR` choose where the forensic records go. When they are not
@@ -899,7 +921,12 @@ directory (UTC hour of the write, sequence number on eight digits), with
899
921
  `admina-forensic/1 record signature` under the chain-state key
900
922
  (`ADMINA_FORENSIC_STATE_KEY` or `ADMINA_FORENSIC_STATE_KEY_FILE`, kept
901
923
  outside the forensic directory); `record_sig_alg`: `hmac-sha256`. Without
902
- a key a record has `record_sig_alg: "none"` and no `record_sig`.
924
+ a key a record has `record_sig_alg: "none"` and no `record_sig`. Since
925
+ 0.13.1, when a store that holds signed records is opened without its
926
+ key, the proxy does not start in `closed` fail mode
927
+ (`ADMINA_FORENSIC_FAIL_MODE`) and logs a warning in `open` mode, where
928
+ the records it then writes are unsigned (a later verification with the
929
+ key reports `unsigned`).
903
930
 
904
931
  The chain state (`_chain_state.json`, with its HMAC-SHA256 in
905
932
  `_chain_state.json.sig` when a key is set) holds `record_count`,
@@ -974,7 +1001,10 @@ introduced.
974
1001
  **Audit records.** `POST /api/v1/audit` records the event it receives with
975
1002
  `source: "api_v1_audit"` (a `source` in the request is kept as
976
1003
  `client_source`) and `submitted_by`: the credential the request was admitted
977
- with (`api_key`, `append_key`, `user:<id>` or `unauthenticated`). An
1004
+ with (`api_key`, `append_key`, `user:<id>` or `unauthenticated`). With
1005
+ `ADMINA_API_KEY` in the environment the built-in `apikey` auth provider
1006
+ admits API-key requests, stamped `user:api_key_user`; `api_key` is the stamp
1007
+ when the key comes only from `ADMINA_API_KEY_FILE` or `.env`. An
978
1008
  `event_type` of the records the proxy writes itself (`mcp_request`,
979
1009
  `mcp_response`, `gateway_request`, `gateway_response`, `gateway_response_scan`,
980
1010
  `policy_violation`, `chain_state_rebuilt`) is refused with `400`.
@@ -1423,18 +1453,18 @@ fields are always scanned.
1423
1453
 
1424
1454
  The scan follows the body 32 levels deep: the body is level 0, its fields
1425
1455
  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":
1456
+ With the firewall on, a request with a string nested deeper is blocked in
1457
+ `enforce` mode (`X-Admina-Would-Action: BLOCK` in `observe` and `dry-run`),
1458
+ and its record has `checks.scan_depth = {"action": "BLOCK", "reason":
1429
1459
  "depth_limit_exceeded"}`. Tool call arguments nested deeper than the JSON
1430
1460
  parser reads are scanned as they are, and the request is blocked the same
1431
1461
  way.
1432
1462
 
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.
1463
+ `/mcp` scans and redacts to the same depth. With the firewall or PII
1464
+ redaction on, a request holding a string, or a non-empty object or array,
1465
+ past level 32 is blocked the same way, since that text would be neither
1466
+ scanned nor redacted. `content` of `/api/v1/validate` must be a string, so
1467
+ that block does not apply there.
1438
1468
 
1439
1469
  #### Scan scope
1440
1470
 
@@ -1479,6 +1509,10 @@ case-sensitive. The caller must keep these tags out of text written by
1479
1509
  untrusted parties, because the gateway cannot tell such text from its own
1480
1510
  blocks.
1481
1511
 
1512
+ `ruleset_sha256()` hashes the Admina version too (and the `admina-core`
1513
+ version with the Rust engine), so a ruleset hash changes with every release:
1514
+ recompute the hashes in `gateway.prescan_rulesets` after each upgrade.
1515
+
1482
1516
  Trust model: with scan policies on, the gateway takes the caller's word for
1483
1517
  what it has scanned. Any caller that holds the API key can send the header,
1484
1518
  and the ruleset it must declare is not a secret (it is on every response and
@@ -1719,7 +1753,10 @@ cd integrations/cheshirecat/admina-plugin
1719
1753
 
1720
1754
  <br>
1721
1755
 
1722
- Governs every LLM call and tool invocation in-process:
1756
+ Governs every LLM call and tool invocation in-process. Install
1757
+ `admina-framework[proxy,nlp]`: the loop detection that the callbacks turn
1758
+ on by default needs scikit-learn from `[proxy]` (or pass
1759
+ `loop_detection=False`).
1723
1760
 
1724
1761
  ```python
1725
1762
  from admina.integrations.langchain.callbacks import AdminaCallbackHandler
@@ -1967,6 +2004,14 @@ curl -X POST http://localhost:8080/api/compliance/classify \
1967
2004
  curl http://localhost:8080/api/dashboard/score
1968
2005
  ```
1969
2006
 
2007
+ A blocked `/mcp` call is answered with a JSON-RPC error (`-32600`, "Request
2008
+ blocked by Admina governance") whose `error.data` holds the `event_id` of
2009
+ the forensic record and a `reason`: `injection_detected` (firewall),
2010
+ `scan_depth_exceeded` (text nested deeper than the scan depth),
2011
+ `egress_refused` (egress policy), `guard_blocked` (a request guard, also a
2012
+ guard error under `ADMINA_GUARD_FAIL_MODE=closed`) or `response_blocked`
2013
+ (a response guard). Before 0.13.1 every block reported `injection_detected`.
2014
+
1970
2015
  </details>
1971
2016
 
1972
2017
  ## Project documents
@@ -174,6 +174,11 @@ pip install admina-framework
174
174
  > matters more than that extra coverage. See
175
175
  > [Performance](#performance--hybrid-python--rust-engine) for the trade-off.
176
176
 
177
+ The PyPI package `admina` is an alias: `pip install admina` installs
178
+ `admina-framework` at the same version, and `admina[X]` installs
179
+ `admina-framework[X]` for every extra above. It has no code of its own, so
180
+ both names install the same `admina` module.
181
+
177
182
  ### Or install from source
178
183
 
179
184
  ```bash
@@ -355,6 +360,17 @@ dependency: one uvicorn serves the proxy API and the dashboard SPA on the
355
360
  same port. Use `--stack` for the production-like Docker compose, or
356
361
  `--with-llm` to also boot local LLM services.
357
362
 
363
+ Local mode uses the forensic backend of `FORENSIC_BACKEND` or of
364
+ `admina.yaml`, and memory when neither sets one. In the compose file that
365
+ `admina init` writes, the dashboard (`127.0.0.1:3000`), OTEL and the
366
+ `--with-llm` services listen on the loopback interface only; the dashboard
367
+ asks for `ADMINA_DASHBOARD_PASSWORD` and the API key (both shown by
368
+ `admina password show`). The proxy reaches the MCP server at
369
+ `UPSTREAM_MCP_URL` (default `http://host.docker.internal:9000`, an MCP
370
+ server on the host). `CLICKHOUSE_PASSWORD` and `GRAFANA_ADMIN_PASSWORD`
371
+ come from the `.env` that `admina dev` writes; a plain `docker compose up`
372
+ stops when they are not set.
373
+
358
374
  ## Dashboard
359
375
 
360
376
  Real-time governance dashboard on port 3000:
@@ -774,6 +790,12 @@ one trailing newline removed. A missing, unreadable or empty file, or a key
774
790
  set both directly and as a file, stops the proxy; the error names the
775
791
  setting and the path, never the key. `ADMINA_FORENSIC_STATE_KEY_FILE` inside
776
792
  the forensic directory stops it too: the key must be kept outside the store.
793
+ The built-in `apikey` auth provider reads `ADMINA_API_KEY` from the
794
+ environment only, and is loaded only when it is set there. A key given only
795
+ through `ADMINA_API_KEY_FILE` or `.env` is checked by the authentication
796
+ middleware itself (the same headers, the same constant-time comparison), and
797
+ `POST /api/v1/audit` then stamps `submitted_by: "api_key"` instead of
798
+ `"user:api_key_user"`.
777
799
 
778
800
  **Forensic store.** `FORENSIC_BACKEND` (`memory`, `filesystem`, `s3`) and
779
801
  `FORENSIC_BASE_DIR` choose where the forensic records go. When they are not
@@ -815,7 +837,12 @@ directory (UTC hour of the write, sequence number on eight digits), with
815
837
  `admina-forensic/1 record signature` under the chain-state key
816
838
  (`ADMINA_FORENSIC_STATE_KEY` or `ADMINA_FORENSIC_STATE_KEY_FILE`, kept
817
839
  outside the forensic directory); `record_sig_alg`: `hmac-sha256`. Without
818
- a key a record has `record_sig_alg: "none"` and no `record_sig`.
840
+ a key a record has `record_sig_alg: "none"` and no `record_sig`. Since
841
+ 0.13.1, when a store that holds signed records is opened without its
842
+ key, the proxy does not start in `closed` fail mode
843
+ (`ADMINA_FORENSIC_FAIL_MODE`) and logs a warning in `open` mode, where
844
+ the records it then writes are unsigned (a later verification with the
845
+ key reports `unsigned`).
819
846
 
820
847
  The chain state (`_chain_state.json`, with its HMAC-SHA256 in
821
848
  `_chain_state.json.sig` when a key is set) holds `record_count`,
@@ -890,7 +917,10 @@ introduced.
890
917
  **Audit records.** `POST /api/v1/audit` records the event it receives with
891
918
  `source: "api_v1_audit"` (a `source` in the request is kept as
892
919
  `client_source`) and `submitted_by`: the credential the request was admitted
893
- with (`api_key`, `append_key`, `user:<id>` or `unauthenticated`). An
920
+ with (`api_key`, `append_key`, `user:<id>` or `unauthenticated`). With
921
+ `ADMINA_API_KEY` in the environment the built-in `apikey` auth provider
922
+ admits API-key requests, stamped `user:api_key_user`; `api_key` is the stamp
923
+ when the key comes only from `ADMINA_API_KEY_FILE` or `.env`. An
894
924
  `event_type` of the records the proxy writes itself (`mcp_request`,
895
925
  `mcp_response`, `gateway_request`, `gateway_response`, `gateway_response_scan`,
896
926
  `policy_violation`, `chain_state_rebuilt`) is refused with `400`.
@@ -1339,18 +1369,18 @@ fields are always scanned.
1339
1369
 
1340
1370
  The scan follows the body 32 levels deep: the body is level 0, its fields
1341
1371
  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":
1372
+ With the firewall on, a request with a string nested deeper is blocked in
1373
+ `enforce` mode (`X-Admina-Would-Action: BLOCK` in `observe` and `dry-run`),
1374
+ and its record has `checks.scan_depth = {"action": "BLOCK", "reason":
1345
1375
  "depth_limit_exceeded"}`. Tool call arguments nested deeper than the JSON
1346
1376
  parser reads are scanned as they are, and the request is blocked the same
1347
1377
  way.
1348
1378
 
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.
1379
+ `/mcp` scans and redacts to the same depth. With the firewall or PII
1380
+ redaction on, a request holding a string, or a non-empty object or array,
1381
+ past level 32 is blocked the same way, since that text would be neither
1382
+ scanned nor redacted. `content` of `/api/v1/validate` must be a string, so
1383
+ that block does not apply there.
1354
1384
 
1355
1385
  #### Scan scope
1356
1386
 
@@ -1395,6 +1425,10 @@ case-sensitive. The caller must keep these tags out of text written by
1395
1425
  untrusted parties, because the gateway cannot tell such text from its own
1396
1426
  blocks.
1397
1427
 
1428
+ `ruleset_sha256()` hashes the Admina version too (and the `admina-core`
1429
+ version with the Rust engine), so a ruleset hash changes with every release:
1430
+ recompute the hashes in `gateway.prescan_rulesets` after each upgrade.
1431
+
1398
1432
  Trust model: with scan policies on, the gateway takes the caller's word for
1399
1433
  what it has scanned. Any caller that holds the API key can send the header,
1400
1434
  and the ruleset it must declare is not a secret (it is on every response and
@@ -1635,7 +1669,10 @@ cd integrations/cheshirecat/admina-plugin
1635
1669
 
1636
1670
  <br>
1637
1671
 
1638
- Governs every LLM call and tool invocation in-process:
1672
+ Governs every LLM call and tool invocation in-process. Install
1673
+ `admina-framework[proxy,nlp]`: the loop detection that the callbacks turn
1674
+ on by default needs scikit-learn from `[proxy]` (or pass
1675
+ `loop_detection=False`).
1639
1676
 
1640
1677
  ```python
1641
1678
  from admina.integrations.langchain.callbacks import AdminaCallbackHandler
@@ -1883,6 +1920,14 @@ curl -X POST http://localhost:8080/api/compliance/classify \
1883
1920
  curl http://localhost:8080/api/dashboard/score
1884
1921
  ```
1885
1922
 
1923
+ A blocked `/mcp` call is answered with a JSON-RPC error (`-32600`, "Request
1924
+ blocked by Admina governance") whose `error.data` holds the `event_id` of
1925
+ the forensic record and a `reason`: `injection_detected` (firewall),
1926
+ `scan_depth_exceeded` (text nested deeper than the scan depth),
1927
+ `egress_refused` (egress policy), `guard_blocked` (a request guard, also a
1928
+ guard error under `ADMINA_GUARD_FAIL_MODE=closed`) or `response_blocked`
1929
+ (a response guard). Before 0.13.1 every block reported `injection_detected`.
1930
+
1886
1931
  </details>
1887
1932
 
1888
1933
  ## 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.2"
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():