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