[project] name = "defenseclaw" version = "0.8.10" description = "Enterprise governance layer for OpenClaw — secures agentic AI deployments" readme = "README.md" requires-python = ">=3.10,<3.14" license = "Apache-2.0" license-files = ["LICENSE", "NOTICE", "THIRD_PARTY_LICENSES.txt"] dependencies = [ "click>=8.3.3,<9", "pyyaml==6.0.3", "requests==2.33.0", # uv overrides are resolver-only and are not emitted as Requires-Dist. # Keep every advisory-backed transitive floor direct and unmarked so plain # wheel installs enforce the same minimums on every supported Python line. # CVE-2026-69247 is fixed in 50.0.0; keep the next-major ceiling so # published wheels and managed installs share a reviewable upgrade line. "cryptography>=50.0.0,<51", "python-dotenv>=1.2.2", "python-multipart>=0.0.31", "urllib3>=2.7.0", "idna>=3.15", "pydantic-settings>=2.14.2", # CVE-2026-59881 and CVE-2026-69243/69244 are fixed by 3.14.3. "aiohttp>=3.14.3,<4", "pyjwt>=2.13.0", "starlette>=1.3.1,<1.4", "fastapi>=0.137.1,<0.138", # The scanner/TUI runtime is one dependency set. DefenseClaw uses the # Textual 8.2 ANSI-theme and Tabs APIs, and Textual 8 requires Rich >=14.2. # Keep the tested 8.x bounds in wheel metadata so managed installs do not # depend on uv's development-only overrides or float to a future major. "rich>=14.2,<15", "textual>=8.2.8,<9", # PYSEC-2026-2987 is fixed in 2.20.0. Keep the floor in wheel metadata # because Rich renders untrusted scanner and gateway output through it. "pygments>=2.20,<3", # Runtime validation of config_version: 8 uses the schema bundled in the # wheel. The 0.8.4 bridge already carries this transitively; the hard-cut # controller verifies that exact pre-existing runtime before mutation. "jsonschema>=4.23.0,<5", # Used by `defenseclaw setup galileo test` to emit a real, minimal OTLP # protobuf canary span without starting the gateway. "opentelemetry-proto>=1.28.0,<2", # PyPI's Simple API has returned package-specific 503s for this # project while the JSON API and locked file URL remain healthy. # Pin the exact audited wheel URL so fresh CI venvs do not depend on # resolving this package through /simple/. # 2.0.5 through 2.0.9 pin older LiteLLM/Textual releases, while 2.0.10 # through 2.0.13 cap Textual below 8. 2.0.4 is the newest non-yanked # release whose wheel metadata permits both Textual 8 and the secure # LiteLLM floor. Keep the audited PyPI wheel URL and hash explicit. "cisco-ai-skill-scanner @ https://files.pythonhosted.org/packages/ad/c0/90b74836fd9a9e5b6530cbd1b3fe778266e863e9a8bc214db96d08c0e0ee/cisco_ai_skill_scanner-2.0.4-py3-none-any.whl#sha256=8ac399d4542870fad7b09027b9d45f0668788dfff3a5a95603c6f195430a5d74", # Magika 1.0.2 removes its obsolete Windows onnxruntime<=1.20.1 cap and # selects a supported ONNX Runtime for each Python line. Keep that floor in # published-wheel metadata as well as the native installer's uv lock. "magika>=1.0.2,<2", # MCP scanner >=4.3.1 pins vulnerable LiteLLM releases exactly. 4.3.0 is # the newest trusted release whose METADATA permits the project's secure # LiteLLM floor. Pin its PyPI-attested wheel and hash until upstream ships # a release compatible with LiteLLM >=1.84.0. "cisco-ai-mcp-scanner @ https://files.pythonhosted.org/packages/af/40/d42943f9e3da40ee9b5f00439fda38b62fc379034383f85a6e06d7825796/cisco_ai_mcp_scanner-4.3.0-py3-none-any.whl#sha256=ea1a30d6bc282f2b4081bc4eced4287a20326891588624d5b2e07b388710b812 ; python_version>='3.11'", # CVE-2026-52869, CVE-2026-52870, and CVE-2026-59950 affect older MCP # SDK releases. DefenseClaw imports the SDK directly for stdio scanning, # so keep the fixed floor in published-wheel metadata as well as uv.lock. "mcp>=1.28.1,<2", # Declare MCP Scanner's YARA engine directly so uv can select the local, # Native Setup substitutes the repository-owned, YARA-X-backed compatibility # wheel and validates the exact MCP Scanner API; source installs use # VirusTotal's upstream yara-python distribution. "yara-python>=4.5.4; python_version>='3.11'", # CVE-2026-40217 is fixed in 1.83.10; CVE-2026-49468 is fixed in 1.84.0. # Stable LiteLLM releases currently declare Python <3.14. Version 1.92.0 # also dropped the portable wheel required by Windows and macOS, so keep # the latest portable line until upstream restores cross-platform wheels. "litellm>=1.84.0,<1.92.0", # LiteLLM requires <9 and the development OpenTelemetry API requires # <8.8; retain the security floor while expressing their intersection. "importlib-metadata>=8.7.1,<8.8", # AWS Bedrock support is bundled. LiteLLM lazy-imports boto3 for # SigV4 (iam_credentials / profile / instance_role) and for the # Anthropic-on-Bedrock route used by ABSK bearer tokens. Bundling # it costs ~30 MB on top of the existing 428 MB base install # (~7%) and removes a recurring first-run failure for the largest # enterprise LLM provider in the matrix. Vertex AI's SDK is ~286 # MB and kept as an opt-in extra (see ``[vertex]``) — flip there # if usage analytics ever justify the disk cost. "boto3>=1.34", # ``tomllib`` only entered the stdlib in 3.11; on 3.10 (allowed by # ``requires-python = ">=3.10,<3.14"``) the code falls back to ``tomli``, # so it must be installed there to parse TOML. "tomli>=2.0.1; python_version < '3.11'", ] [project.optional-dependencies] # Vertex AI auth (service-account JSON, ADC, workload identity). # LiteLLM lazy-imports ``google-cloud-aiplatform`` for this route, and # the SDK pulls ~286 MB of transitive deps (BigQuery, Cloud Storage, # Cloud Resource Manager, gRPC, protobuf). That nearly doubles the # base install, so we keep it opt-in. Source checkouts enable it with # ``uv sync --extra vertex``. Bedrock is bundled by # default — see the ``boto3`` entry under ``[project].dependencies``. vertex = ["google-cloud-aiplatform>=1.60", "google-auth>=2.30"] [dependency-groups] dev = [ "pytest==9.0.3", "pytest-cov==7.1.0", "pytest-xdist==3.8.0", "pytest-asyncio==1.3.0", "hypothesis==6.140.4", "freezegun==1.5.5", "jsonschema>=4.23.0", "ruff==0.15.7", "opentelemetry-api>=1.28.0", "opentelemetry-sdk>=1.28.0", ] [project.scripts] defenseclaw = "defenseclaw.main:main" defenseclaw-observability = "defenseclaw.observability.local_stack:main" [build-system] requires = ["setuptools==82.0.1"] build-backend = "setuptools.build_meta" [tool.setuptools.packages.find] where = ["cli"] exclude = ["tests", "tests.*"] [tool.setuptools.package-data] defenseclaw = [ "_data/policies/*.yaml", "_data/policies/rego/*.rego", "_data/policies/rego/*.json", "_data/envvars/*.json", "_data/plugin/*.json", "_data/skills/codeguard/*.md", "_data/skills/codeguard/*.yaml", "_data/skills/codeguard/*.py", "_data/splunk_local_bridge/bin/*", "_data/splunk_local_bridge/compose/*", "_data/splunk_local_bridge/env/.env.example", "_data/splunk_local_bridge/s3_exporter/*", "_data/splunk_local_bridge/s3_exporter/tests/*", "_data/splunk_local_bridge/splunk/*", "_data/splunk_local_bridge/splunk/ansible/*", "_data/splunk_local_bridge/splunk/bin/*", "_data/splunk_local_bridge/splunk/apps/defenseclaw_local_mode/bin/*", "_data/splunk_local_bridge/splunk/apps/defenseclaw_local_mode/default/*", "_data/splunk_local_bridge/splunk/apps/defenseclaw_local_mode/default/data/ui/nav/*", "_data/splunk_local_bridge/splunk/apps/defenseclaw_local_mode/default/data/ui/views/*", "_data/splunk_local_bridge/splunk/apps/defenseclaw_local_mode/lookups/*", "_data/splunk_local_bridge/splunk/apps/defenseclaw_local_mode/metadata/*", "_data/scripts/*.sh", "_data/llm/*.json", "_data/config/v8/*.json", "_data/config/v8/*.yaml", "_data/config/v8/*.md", "_data/telemetry/v8/telemetry.schema.json", "_data/telemetry/v8/catalog.json", "_data/telemetry/v8/v7-exporter-selection.json", "_data/telemetry/v8/galileo-rich-v2.json", "_data/telemetry/v8/local-observability-v1.json", "_data/telemetry/v8/openinference-v1.json", "inventory/ai_signatures.json", "inventory/hook_contracts.json", "_data/policies/openshell/*.rego", "_data/policies/openshell/*.yaml", "_data/policies/guardrail/default/*.yaml", "_data/policies/guardrail/default/judge/*.yaml", "_data/policies/guardrail/default/rules/*.yaml", "_data/policies/guardrail/strict/*.yaml", "_data/policies/guardrail/strict/judge/*.yaml", "_data/policies/guardrail/strict/rules/*.yaml", "_data/policies/guardrail/permissive/*.yaml", "_data/policies/guardrail/permissive/judge/*.yaml", "_data/policies/guardrail/permissive/rules/*.yaml", "_data/local_observability_stack/*.md", "_data/local_observability_stack/*.yml", "_data/local_observability_stack/*.sh", "_data/local_observability_stack/.gitignore", "_data/local_observability_stack/bin/*", "_data/local_observability_stack/otel-collector/*.yaml", "_data/local_observability_stack/prometheus/*.yml", "_data/local_observability_stack/prometheus/rules/*.yml", "_data/local_observability_stack/loki/*.yaml", "_data/local_observability_stack/tempo/*.yaml", "_data/local_observability_stack/grafana/dashboards/*.json", "_data/local_observability_stack/grafana/provisioning/dashboards/*.yml", "_data/local_observability_stack/grafana/provisioning/datasources/*.yml", "_data/splunk_o11y_dashboards/*.md", "_data/splunk_o11y_dashboards/terraform/*.tf", ] [tool.uv] default-groups = ["dev"] override-dependencies = [ "rich>=14.2,<15", # CVE-2026-39892 fixed in 46.0.7; GHSA-537c-gmf6-5ccf fixed in 48.0.1; # CVE-2026-69248/69249 fixed in 49.0.0; CVE-2026-69247 fixed in 50.0.0; # PYSEC-2026-3552 / -3553 / -3554 fixed in 50.0.0. "cryptography>=50.0.0,<51", # CVE-2026-40217 fixed in 1.83.10; CVE-2026-49468 fixed in 1.84.0. "litellm>=1.84.0,<1.92.0", # litellm pins exact transitive versions that conflict with what # cisco-ai-skill-scanner 2.0.11 (and our own pins) expect. We # override to a single compatible version per package — the newer # of the two — and rely on litellm's runtime API surface being # compatible with the bumped versions (verified via Python tests # in CI). "python-dotenv>=1.2.2", # CVE-2026-28684 fixed in 1.2.2; scanner >=2.0.10 allows it. "openai==2.30.0", "importlib-metadata>=8.7.1,<8.8", "jsonschema>=4.26.0", # CVE-2026-40347/42561 fixed by 0.0.27; CVE-2026-53537..53540 fixed by 0.0.31. "python-multipart>=0.0.31", "urllib3>=2.7.0", # CVE-2026-44431, CVE-2026-44432 fixed in 2.7.0 "idna>=3.15", # CVE-2026-45409 fixed in 3.15 "pydantic-settings>=2.14.2", # GHSA-4xgf-cpjx-pc3j fixed in 2.14.2 # aiohttp 3.13.4 fixes a batch of HTTP-parser CVEs (CVE-2026-22815, # CVE-2026-34513..34520, CVE-2026-34525); 3.14.0 additionally fixes # CVE-2026-34993 and CVE-2026-47265; 3.14.1 fixes CVE-2026-54273..54280; # 3.14.2 fixes PYSEC-2026-3546 and PYSEC-2026-3547; 3.14.3 fixes # CVE-2026-59881, CVE-2026-69243/69244, and PYSEC-2026-3545. # LiteLLM's transitive pin floats aiohttp downward without this override. "aiohttp>=3.14.3,<4", # pyjwt 2.13.0 fixes PYSEC-2026-175, PYSEC-2026-177, PYSEC-2026-178 and # PYSEC-2026-179. Pulled in transitively; pin it forward so the audit # stays clean. "pyjwt>=2.13.0", # PYSEC-2026-161 (GHSA-86qp-5c8j-p5mr): Host-header validation # fixed in starlette 1.0.1. fastapi pins starlette<0.51 until # 0.130.0, so we also force fastapi forward to a release whose # upper bound permits 1.x. Scanner 2.0.11 broadens its fastapi # pin to <1,>=0.115 so this override no longer conflicts with # upstream. # # IMPORTANT: fastapi==0.136.3 is flagged malicious in OSV # (MAL-2026-4750, published 2026-05-23) — it inserts a "fastar" # typosquat into its ``[standard]`` optional-dependencies group. # We don't install ``fastapi[standard]`` so we don't pull the # typosquat in practice, but we still skip that release to keep # the audit clean. FastAPI 0.137.x allows the Starlette 1.3.x line, # which carries CVE-2026-48817/48818 and CVE-2026-54282/54283 fixes. "starlette>=1.3.1,<1.4", "fastapi>=0.137.1,<0.138", "textual>=8.2.8,<9", "pygments>=2.20,<3", ] [tool.ruff] target-version = "py310" line-length = 120 [tool.ruff.lint] select = ["E", "F", "I", "N", "W", "UP"] [tool.ruff.lint.per-file-ignores] # Test suites lean on conventions ruff dislikes by default: descriptive # CapWords_Suffix class names, ``MockScanner`` / ``MockPE`` mock locals, # short ``C`` aliases for credential modules, deliberately-unused # binding placeholders, and ``sys.path``-bootstrap imports above # top-of-file. None of these are bugs and rewriting them all carries # no review benefit, so silence the ruff codes there. "cli/tests/**" = ["E501", "E402", "E702", "F841", "N801", "N803", "N806", "N812"] # Hand-written migrations occasionally need slightly-long error lines # for grep-friendly messages. "cli/defenseclaw/migrations.py" = ["E501"] # TUI panels embed wide ASCII tables / banner strings that we want # kept on one line for readability. "cli/defenseclaw/tui/**" = ["E501"] [tool.pytest.ini_options] testpaths = ["cli/tests"] # Every `async def test_*` in the TUI suite needs `pytest-asyncio` to # actually be awaited; ``auto`` mode lets us drop the per-test # ``@pytest.mark.asyncio`` decorations the codebase has 100+ of today. asyncio_mode = "auto" markers = [ "tui_snapshot: marks SVG snapshot tests (slow on first run)", "tui_property: marks Hypothesis-driven invariant tests", "allow_subprocess: opts test out of the autouse subprocess ban (use only for executor.py integration tests)", "agent_tty: marks tests that spawn an interactive agent under a PTY (legacy marker)", "supported_connector_host: runs platform-neutral connector behavior on an explicitly supported host", ] filterwarnings = [ "ignore::DeprecationWarning:textual.*", ]