ai-governance-middleware (aimw)
Reference implementation of the runtime governance middleware described in Part III of the AI Governance & Runtime Protection Framework, covering the L1 "Pragmatic Lite" and L2 "Growth Tier" maturity levels (Section 13). It intercepts an agent's proposed tool calls and enforces policy, guardrails, sandboxing, and tamper-evident audit logging at runtime, structured so L3 ("Enterprise Mesh": real OPA/Cedar, E2B microVM sandboxing, full compound identity) can be added later as new implementations of the same abstract interfaces — no rewrite required.
This build requires no external services, accounts, or API keys. Every integration point (LLM calls, PII detection, the DB-backed policy store, the circuit breaker) is a local/hermetic implementation, with an optional real Docker backend for the sandbox and an optional real Redis backend for the circuit breaker.
Architecture
User / Context
-> LiteLLM Gateway shim (rate limits, identity check, PII pre-pass)
-> Guardrail.inspect_input (prompt-injection / control-token checks)
-> LLM Reasoning Loop (FakeLLMClient stub)
-> ToolCallInterceptor per proposed tool call:
-> CircuitBreaker.check (skip everything below if open)
-> PolicyEngine.evaluate_tool_call
allowed -> Sandbox.execute -> CircuitBreaker.record_result
denied / needs-approval -> HITL approval callback
-> Guardrail.inspect_output
-> WORM Audit Log (hash-chained JSONL, + optional SIEM sinks)
Maturity tiers
| Dimension | L1 "Pragmatic Lite" (this repo) | L2 "Growth Tier" (this repo) |
|---|---|---|
| Gateway | LiteLLMGatewayShim — in-process rate limit |
same shim, pluggable identity + SemanticGuardrail layer |
| PII detection | RegexPIIGuardrail — regex masking, stand-in for Presidio |
+ DLPClassifier — sensitivity tiering (LOW/MEDIUM/RESTRICTED) |
| Policy engine | StaticPolicyEngine — YAML-declared allow/deny rules |
DbBackedPolicyEngine — SQLite-backed, live-updatable RBAC |
| Identity | StaticBearerTokenVerifier — single deployment-wide token |
SessionTokenIssuer — HMAC-signed, session+agent-scoped, expiring |
| Reliability | token caps & sandbox timeouts only | CircuitBreaker — trips per (agent, tool) after a failure-rate threshold |
| Sandboxing | SubprocessSandbox (default stub) or DockerSandbox |
RestrictedDockerSandbox — non-root, read-only rootfs, all caps dropped |
| Audit | HashChainedJSONLLogger — local hash-chained JSONL |
+ BaseAuditSink forwarding (LocalSiemForwarder stand-in for Datadog/Elastic) |
Every concrete class implements one of the abstract interfaces in
aimw.interfaces (BasePolicyEngine, BaseGuardrail, BaseRegistry), or
the analogous BaseSandbox / BaseIdentityVerifier /
BaseCircuitBreakerBackend / BaseAuditSink hooks built the same way. An
L1 deployment upgrades to L2 by swapping which concrete class is passed
into ToolCallInterceptor / LiteLLMGatewayShim / HashChainedJSONLLogger
— the pipeline, interceptor, and callers never change. DbBackedPolicyEngine
and DbBackedToolRegistry share one DbRuleStore so their view of "what a
context can do" and "what a context can see" never drifts apart, and also
add a Global RBAC layer (Section 15.1) that L1 didn't have: a context
whose roles aren't recognized in the store at all is denied before any
per-tool check runs.
A note on the audit log
HashChainedJSONLLogger detects tampering after the fact: each record's
hash is chained to the previous one, and verify_chain() can be run by a
completely separate process to confirm no record has been altered. It does
not prevent tampering the way real WORM storage does (OS-level
immutability, S3 Object Lock, Azure immutable blobs) — an attacker with
filesystem write access could rewrite the whole file with new, internally
consistent hashes. Real tamper-prevention is an explicit L3 upgrade. L2's
SIEM forwarding (BaseAuditSink) is best-effort and does not change this:
a sink failure is logged and swallowed, never allowed to break the local
write that already succeeded.
A note on the circuit breaker
InMemoryCircuitBreakerBackend (the hermetic default) and
RedisCircuitBreakerBackend (opt-in, needs the redis extra and a running
Redis) implement the same BaseCircuitBreakerBackend contract — a key
(agent_id:tool_name) trips open once its recent sandbox-failure rate
crosses a threshold, and stays open for a cooldown window. ToolCallInterceptor
checks the breaker before the policy engine runs, so a misbehaving tool
stops costing sandbox time even while it's still "allowed" by policy.
Install
python -m venv .venv
. .venv/Scripts/activate # or: source .venv/bin/activate on Linux/macOS
pip install -e ".[dev]"
pip install -e ".[redis]" # optional: only needed for RedisCircuitBreakerBackend
Test
pytest -q # hermetic suite, no Docker/Redis/network/API keys required
pytest -q -m docker # opt-in: also exercises DockerSandbox / RestrictedDockerSandbox (needs a local Docker daemon)
mypy src/aimw --strict
ruff check .
bandit -r src/aimw -c pyproject.toml
RedisCircuitBreakerBackend's logic is covered by tests against an
in-memory fake Redis client (see tests/unit/test_redis_circuit_breaker.py)
— no real Redis server is required to run the suite.
Run the demos
python examples/run_demo.py # L1: allowed / denied / approval-required / tamper-evidence
python examples/run_demo_l2.py # L2: session tokens, DB-backed RBAC, semantic guardrail,
# DLP classification, circuit breaker, SIEM forwarding
run_demo.py walks through an allowed tool call, a denied call (SQL
deny-pattern match), an approval-required call (shown both approved and
denied by a stub HITL queue), then prints the full audit trail, verifies
its hash chain (valid=True), tampers with one byte on disk, and
re-verifies (valid=False, with the exact broken record index).
run_demo_l2.py additionally shows: a session-scoped token rejected for
the wrong session/agent; a context with an unrecognized role denied at the
Global RBAC layer; a paraphrased prompt-injection attempt caught by the
semantic guardrail where an exact regex would miss it; DLP sensitivity
classification of masked PII; and a circuit breaker tripping after
repeated sandbox failures, denying the third call before policy even runs.
Out of scope for this build
L3 concrete engines, real E2B/OPA/Cedar/Presidio/Datadog/Elastic integration, a demo agent product, and the framework document's governance-policy (Part I) and security-assessment-methodology (Part II) content — this repository is the middleware SDK only.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ai_governance_middleware-0.2.0.tar.gz.
File metadata
- Download URL: ai_governance_middleware-0.2.0.tar.gz
- Upload date:
- Size: 44.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a3b1f4ea919db6eaa067a24781d84aaad784017109cdeb8177127bbabb7a70dc
|
|
| MD5 |
2a61e58e7e965f28cf031aaadc11ebc8
|
|
| BLAKE2b-256 |
361a40e7e1ede2f83dac0851977b8fc705afc9fac945d79677daeeaeb881584f
|
File details
Details for the file ai_governance_middleware-0.2.0-py3-none-any.whl.
File metadata
- Download URL: ai_governance_middleware-0.2.0-py3-none-any.whl
- Upload date:
- Size: 46.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ef228221d6fce97387f24ae7a7b54235dd71d690bb40091df12dc1a13af72198
|
|
| MD5 |
ed3afe94361f9e11499d52906547f066
|
|
| BLAKE2b-256 |
c0923075f9b85d1b966f38212b1c0c6b3abac4323df6e1ad1f42267084b2389f
|