# Copyright (c) 2026 Juan Luna. All rights reserved. # SPDX-License-Identifier: LicenseRef-Aegis-Commercial-1.0 # Licensed under the Aegis Commercial License 1.0; see LICENSE and NOTICE. [build-system] requires = ["hatchling==1.28.0"] build-backend = "hatchling.build" [project] name = "aegis-latent-core" version = "5.0.3" description = "Fail-closed LLM gateway with durable signed forensic evidence and bounded response enrichment" readme = "README.md" license = "LicenseRef-Aegis-Commercial-1.0" license-files = ["LICENSE", "NOTICE", "LICENSE-THIRD-PARTY.md"] requires-python = ">=3.11" authors = [{ name = "Juan Luna", email = "juan.c.luna04@gmail.com" }] maintainers = [{ name = "Juan Luna", email = "juan.c.luna04@gmail.com" }] keywords = [ "llm", "ai-safety", "forensics", "telemetry", "audit", "openai", "anthropic", "gemini", "openrouter", "proxy", "entropy", "merkle", "chain-of-custody", ] classifiers = [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "Intended Audience :: Information Technology", "Intended Audience :: Science/Research", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Topic :: Security", "Topic :: Scientific/Engineering :: Artificial Intelligence", "Typing :: Typed", ] dependencies = [ "fastapi>=0.111.0", "uvicorn[standard]>=0.29.0", # uvloop 0.23.0 (2026-10-01) opens an io_uring instance even with # UV_USE_IO_URING=0, so SeccompGuard refuses to load the filter (REG-D67). "uvloop<0.23; sys_platform != 'win32'", "httpx>=0.27.0", "pydantic>=2.7.0", "pydantic-settings>=2.3.0", "numpy>=1.26.0,<2.5", "python-dotenv>=1.0.0", "structlog>=24.1.0", "protobuf>=5.0.0", "redis>=5.0.0", "requests>=2.31.0", "cryptography>=50.0.0,<51.0.0", "cbor2>=5.9.0", # Rate-limiter TTL eviction (MEDIUM-01 fix). Soft dependency — graceful # fallback to plain dict with a one-time warning when not installed. "cachetools>=5.3.0", # Security floor for transitive dep (PYSEC-2026-215 / CVE-2026-45409). "idna>=3.15", # Security floor for transitive dep via requests (PYSEC-2026-141 / -142; # 2.8.0 for GHSA-8988-9cw3-xx77, GHSA-gh4c-6fx4-qh6g, GHSA-vxq7-64xx-v4gw). "urllib3>=2.8.0", ] [project.optional-dependencies] # ── Storage backends ───────────────────────────────────────────────────────── storage-sqlite = ["aiosqlite>=0.20.0"] storage-postgres = ["asyncpg>=0.29.0"] storage-dynamodb = ["aioboto3>=13.0.0"] storage-s3 = ["boto3>=1.35.0"] storage-all = [ "aegis-latent-core[storage-sqlite,storage-postgres,storage-dynamodb,storage-s3]", ] # ── Enterprise connectors ──────────────────────────────────────────────────── # The Splunk HEC and Vault Transit connectors need only httpx, which is already # a runtime dependency; the Parquet exporter is the one that pulls a new wheel. lakehouse = ["pyarrow>=16.0.0"] # ── Signing / secrets ──────────────────────────────────────────────────────── vault = ["hvac>=2.1.0"] ldap = ["ldap3>=2.9.1"] oidc = ["PyJWT[crypto]>=2.10.1,<3"] # ── Provider extras (no extra Python deps needed — all HTTP-based) ─────────── # Install the relevant SDK for SDK-based integration (optional convenience). anthropic-sdk = ["anthropic>=0.25.0"] google-sdk = ["google-generativeai>=0.7.0"] # ── ML / inference extras ──────────────────────────────────────────────────── gpu = ["torch>=2.0.0"] vllm = ["vllm>=0.4.0", "torch>=2.0.0"] hf = ["transformers>=4.40.0", "torch>=2.0.0"] # ── Observability ──────────────────────────────────────────────────────────── metrics = ["prometheus-fastapi-instrumentator>=6.1.0", "prometheus-client>=0.20.0"] otel = [ "opentelemetry-sdk>=1.24.0", "opentelemetry-exporter-otlp-proto-grpc>=1.24.0", ] # ── Post-quantum cryptography ───────────────────────────────────────────────── # `oqs-python` was declared here and imported by nothing in this tree, so the # extra installed an unused liboqs binding while leaving the backend the code # actually imports undeclared. Removed rather than kept: an unimported # dependency in a security-relevant extra is supply-chain surface for no # capability. pqc = ["kyber-py>=1.2.0"] # ── Rate limiter ───────────────────────────────────────────────────────────── ratelimit = ["cachetools>=5.3.0"] # ── Development ────────────────────────────────────────────────────────────── dev = [ "pytest>=9.0.3", "pytest-asyncio>=0.23", "pytest-cov>=5.0", "pytest-httpserver>=1.0", # Parallel test execution. The suite is ~6,700 tests; `-n auto` takes the # wall clock from ~119 s to ~48 s, which is the difference between a gate a # contributor runs before pushing and one they skip. "pytest-xdist>=3.6", "kyber-py>=1.2.0", "hypothesis>=6.100", "httpx>=0.27.0", "ruff>=0.4", "mypy>=1.10", "bandit>=1.7", "pip-audit>=2.10,<3", "aiosqlite>=0.20.0", "cachetools>=5.3.0", "ldap3>=2.9.1", "PyJWT[crypto]>=2.10.1,<3", # The Parquet exporter's tests module-skip on this import (see # tests/test_optional_backend_declarations.py). Declared here as well as in # the lakehouse extra so the suite that CI runs actually executes them, # rather than reporting the connector green while never importing it. "pyarrow>=16.0.0", # Same rule, and the same reason: `prometheus-client` gates `pytest.skip` # calls in tests/test_observability.py, both tests/security/test_*_metric.py # and tests/compat/test_public_api_compat.py — including the end-to-end # registry test CLM-102's evidence cell cites as its LOCALLY TESTED proof. # The `metrics` extra is installed by no job, so every one of those skipped. "prometheus-client>=0.20.0", # The SDK's client tests (sdk/python/tests) import the provider SDKs # directly, so a dev environment without them fails collection instead of # exercising the adapter. Declared here for the same reason as pyarrow # above: the gate must run the code, not report it green while skipping it. # The SDK package itself is installed with `pip install -e sdk/python`. "openai>=3.35", "anthropic>=1.17", "llama-index-core>=0.14", ] # ── Full install (all optional runtime extras) ─────────────────────────────── # `dev` is deliberately absent (REG-D74): `[all]` used to pull pytest, ruff, # mypy, bandit, pip-audit and hypothesis into a runtime install. Contributors # install `.[dev]` explicitly, as CI does. all = [ "aegis-latent-core[storage-all,vault,oidc,gpu,metrics,otel,pqc]", ] [project.scripts] aegis = "aegis.proxy.app:main" aegis-server = "aegis.proxy.app:main" [project.urls] Homepage = "https://github.com/JuanLunaIA/aegis-latent-core" Documentation = "https://github.com/JuanLunaIA/aegis-latent-core#readme" Repository = "https://github.com/JuanLunaIA/aegis-latent-core" "Bug Tracker" = "https://github.com/JuanLunaIA/aegis-latent-core/issues" Changelog = "https://github.com/JuanLunaIA/aegis-latent-core/blob/main/CHANGELOG.md" [tool.hatch.build.targets.wheel] packages = ["aegis", "aegis_server", "integrations"] [tool.pytest.ini_options] asyncio_mode = "auto" testpaths = ["tests"] addopts = "" markers = [ "slow: marks tests as slow-running (e.g. real network / subprocess calls)", ] filterwarnings = [ # Third-party transition warnings. Keep message/category/module exact so # unrelated deprecations remain visible and fail future -W error gates. "ignore:^Using `httpx` with `starlette\\.testclient` is deprecated; install `httpx2` instead\\.$:starlette.exceptions.StarletteDeprecationWarning:fastapi.testclient", "ignore:^tagMap is deprecated\\. Please use TAG_MAP instead\\.$:DeprecationWarning:ldap3.utils.asn1", "ignore:^typeMap is deprecated\\. Please use TYPE_MAP instead\\.$:DeprecationWarning:ldap3.utils.asn1", ] [tool.ruff] line-length = 100 target-version = "py311" # AUD-18 / REG-D22: one canonical formatter scope for the Makefile and CI. # Both now run over the whole tree, so the two invocations cannot drift; the # markdown exclusion keeps *linting* of Python fences inside documentation # (which `ruff check` still covers) separate from *reformatting* the host # document, which would rewrite 9 doc/README files whose content the doc gates # verify and which this defect never asked for. [tool.ruff.format] exclude = ["*.md"] [tool.ruff.lint] select = ["E", "F", "I", "N", "W", "UP", "S", "B", "A", "COM", "C4", "PT"] ignore = ["S101", "COM812", "E501", "S104", "N801", "N806", "S607", "S110"] [tool.ruff.lint.per-file-ignores] "tests/**" = ["PT009", "PT011", "PT012", "PT017", "PT027", "S101", "S108", "N802", "C408", "E701", "S106", "S105", "N805", "B017", "F841", "N818", "S311", "C416"] "aegis/core/audit_node_pb2.py" = ["E712", "E501"] "aegis/core/**" = ["S311", "S603", "S108", "B904", "B007", "B006", "F841", "N813", "E701"] "aegis_server/**" = ["S311"] [tool.mypy] python_version = "3.11" strict = true ignore_missing_imports = true # Modules that soft-import an optional dependency inside try/except and fall # back when it is absent: the native `aegis_rust` extension (built only when # maturin runs), `torch`, `httpx`, `cachetools`, `elftools` and `Kyber1024`. # # Their `# type: ignore[import]` comments are load-bearing when the dependency # is missing and redundant when it is installed, so `warn_unused_ignores` # reports them in exactly one of the two environments. Suppressing that one # check here keeps `mypy --strict` environment-independent; every other strict # check, this file's own annotations included, still applies. [[tool.mypy.overrides]] module = [ "aegis.core.cfi_manager", "aegis.core.crypto_audit", "aegis.core.mlkem_session", "aegis.core.mmr", "aegis.core.pqc_signer", "aegis.core.ratelimiter", "aegis.core.rust_integration", "aegis.core.telemetry", "aegis.core.ti_sharing", "aegis.proxy.app", ] warn_unused_ignores = false [tool.bandit] exclude_dirs = ["tests"] skips = ["B101", "B104", "B108"] [tool.coverage.run] source_pkgs = ["aegis"] relative_files = true omit = [ "tests/*", # Roadmap / platform-specific modules (not required for proxy runtime). # This list is cross-checked by scripts/verify_import_reachability.py # against the real entrypoint import graph: an entry that has become # reachable is a drift finding, not a silent pass. Six entries below were # removed by that audit on 2026-09-15 because they are now reachable in # the live proxy/engine paths: adversarial_filter, blockchain_anchor, # entropy_analysis, sandbox_l1, taint_analysis, xdp_dynamic_segmentation. # sandbox_l2.py, also removed, no longer exists in the tree. "aegis/core/anchoring.py", "aegis/core/audit_node_pb2.py", "aegis/core/boot_attestation.py", "aegis/core/boot_guard.py", "aegis/core/build_hardener.py", "aegis/core/build_reproducibility.py", "aegis/core/cfi_manager.py", "aegis/core/codeql_config.py", "aegis/core/dependency_audit.py", "aegis/core/dpdk_engine.py", "aegis/core/ebpf_monitor.py", "aegis/core/enclave_provider.py", "aegis/core/forensic_sealing.py", "aegis/core/formal_proofs.py", "aegis/core/formal_specs.py", "aegis/core/identity.py", "aegis/core/kernel_hardener.py", "aegis/core/memory.py", "aegis/core/memory_invariants.py", "aegis/core/mte_guard.py", "aegis/core/network_isolation.py", "aegis/core/panic_mode.py", "aegis/core/red_team_framework.py", "aegis/core/root_ca_gateway.py", "aegis/core/sandbox.py", "aegis/core/secure_runtime.py", "aegis/core/semantic_defense.py", "aegis/core/state_snapshotter.py", "aegis/core/tpm.py", "aegis/core/transparency_log.py", "aegis/core/transport_hardener.py", "aegis/core/tsa_provider.py", "aegis/core/worm_storage.py", "aegis/proxy/mtls.py", ] [tool.coverage.report] # `--cov-fail-under` is decided with this precision, and coverage.py's default is # 0. At 0 the gate's message and its enforcement disagree inside a half-point # band below the floor: a run at 89.87% against --cov-fail-under=90 prints # "FAIL Required test coverage of 90% not reached" and the process still exits 0, # because should_fail_under rounds the total up to 90 before comparing. Measured # against coverage 7.x: should_fail_under(89.87, 90, 0) is False while # (89.4, 90, 0) is True; at precision 2 the whole band fails, which is what the # printed verdict already said. This applies to every invocation -- the Makefile # target and the CI step both pass --cov-fail-under=65 without a precision flag. precision = 2 exclude_lines = [ "pragma: no cover", "if TYPE_CHECKING:", "raise NotImplementedError", "@abstractmethod", ]