Skip to main content

Compliance-grade audit logging for agent systems.

Project description

AuditGate

Compliance-grade audit logging for agent systems.

Every decision, every verdict, every override — structured, queryable, and tamper-evident.

pip install auditgate

What It Does

AuditGate records every gate decision as a structured audit entry with optional tamper-evidence via content hashing or hash chaining. It pairs with ActionGate, BudgetGate, and RuleGate as the fourth composable primitive in the agent execution layer.

AuditGate does not make allow/block decisions. It records what other gates decided and guarantees the record exists.

Vendoring encouraged. This is a small, stable primitive. Copy it, fork it, reimplement it. If you vendor AuditGate, you must preserve the LICENSE file, preserve copyright headers in source files, and not remove or modify the BSL terms. The production use restriction applies to vendored copies. See SEMANTICS.md for the behavioral contract if you reimplement.

Quick Start

from auditgate import (
    Engine, Trail, AuditPolicy, Verdict, Severity, IntegrityMode
)

engine = Engine()

# Define an audit trail with hash chain integrity
trail = Trail("billing", "actiongate", "user:123")
policy = AuditPolicy(integrity=IntegrityMode.CHAIN)
engine.register(trail, policy)

# Record a decision from ActionGate
decision = engine.record(
    trail=trail,
    verdict=Verdict.ALLOW,
    severity=Severity.INFO,
    gate_type="actiongate",
    gate_identity="billing:refund@user:123",
    reason="Rate limit check passed",
    detail={"calls_in_window": 3, "max_calls": 10},
)

assert decision.recorded
assert decision.entry.entry_hash is not None

Integrity Modes

Mode Behavior Use Case
NONE No hashing Maximum throughput, trust the store
HASH SHA-256 per entry Detect tampering of individual entries
CHAIN Hash includes previous entry's hash Detect tampering or deletion of any entry

Failure Modes

Policy Behavior
HARD + FAIL_CLOSED No action can proceed without a recorded audit entry
HARD + FAIL_OPEN Raises on failure but allows unaudited actions
SOFT + FAIL_CLOSED Returns DROPPED decision, caller decides
SOFT + FAIL_OPEN Fire-and-forget audit (best-effort)

Decorator API

# Raises AuditError if audit recording fails (HARD mode default)
@engine.guard(
    Trail("api", "combined", "global"),
    policy=AuditPolicy(integrity=IntegrityMode.HASH),
    severity=Severity.INFO,
    gate_type="auditgate",
)
def process_order(order_id: str) -> dict:
    return {"status": "processed", "id": order_id}

# Or use guard_result for no-exception handling
@engine.guard_result(
    Trail("api", "combined", "global"),
    policy=AuditPolicy(mode=Mode.SOFT),
    severity=Severity.INFO,
    gate_type="auditgate",
)
def fetch_data(query: str) -> list:
    return db.search(query)

result = fetch_data(query="recent orders")
data = result.unwrap_or([])

Querying the Audit Trail

from auditgate import QueryFilter, Verdict, Severity

# All blocked decisions in the last hour
entries = engine._store.query(QueryFilter(
    trail=trail,
    verdict=Verdict.BLOCK,
    after_ts=time.monotonic() - 3600,
))

# All critical events across all trails
critical = engine._store.query(QueryFilter(
    min_severity=Severity.CRITICAL,
))

Composing with Other Gates

from actiongate import Engine as ActionEngine, Gate, Policy
from auditgate import Engine as AuditEngine, Trail, AuditPolicy, Verdict, Severity

action_engine = ActionEngine()
audit_engine = AuditEngine()

trail = Trail("api", "actiongate", "global")
audit_engine.register(trail, AuditPolicy())

# Listen to ActionGate decisions and auto-audit them
def audit_listener(action_decision):
    audit_engine.record(
        trail=trail,
        verdict=Verdict.ALLOW if action_decision.allowed else Verdict.BLOCK,
        severity=Severity.INFO if action_decision.allowed else Severity.WARN,
        gate_type="actiongate",
        gate_identity=str(action_decision.gate),
        reason=str(action_decision.reason) if action_decision.reason else None,
    )

action_engine.on_decision(audit_listener)

Performance

Sub-20µs per audit entry with MemoryStore and SHA-256 hashing (benchmarked). Hash chain mode adds negligible overhead. For context, a single LLM API call is 200ms–2s.

File Structure

auditgate/
├── __init__.py   # Public API, exports, version
├── core.py       # All value types (Trail, AuditPolicy, AuditEntry, Decision, Result)
├── engine.py     # Engine class (record, guard, guard_result)
└── store.py      # Store protocol + MemoryStore

Specification

See SEMANTICS.md for the normative behavior specification. When this document and the code conflict, the specification governs.

License

AuditGate is licensed under the Business Source License 1.1.

Licensor:             actiongate-oss
Licensed Work:        AuditGate
Additional Use Grant: None
Change Date:          2030-02-28 (four years from initial publication)
Change License:       Mozilla Public License 2.0

What this means: You may copy, modify, create derivative works, redistribute, and make non-production use of AuditGate. The Additional Use Grant is "None", which means any use in a live environment that provides value to end users or internal business operations — including SaaS, internal enterprise deployment, and paid betas — requires a commercial license from the licensor. On the Change Date, AuditGate becomes available under MPL 2.0 and the production restriction terminates. Each version has its own Change Date calculated from its publication.

If you vendor AuditGate: Preserve the LICENSE file and copyright headers. Do not remove or modify the BSL terms. The production restriction applies to all copies, vendored or otherwise.

Licensing difference from siblings: ActionGate and BudgetGate are Apache 2.0. AuditGate is BSL 1.1. If composing all three, ensure your use complies with both license terms.

See LICENSE for the legally binding text.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

auditgate-0.2.0.tar.gz (26.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

auditgate-0.2.0-py3-none-any.whl (16.2 kB view details)

Uploaded Python 3

File details

Details for the file auditgate-0.2.0.tar.gz.

File metadata

  • Download URL: auditgate-0.2.0.tar.gz
  • Upload date:
  • Size: 26.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.0

File hashes

Hashes for auditgate-0.2.0.tar.gz
Algorithm Hash digest
SHA256 f0a0118a8a200cf7a03c30b51f50c7812eee3d61535e7c3e0d6fecd9f5d9e48f
MD5 a72a5dafaa9dbb3f06be7e51deafeb0f
BLAKE2b-256 6153a89cf39832e35e8130db63986400eea1f72008d89daa1ae65568de5061c6

See more details on using hashes here.

File details

Details for the file auditgate-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: auditgate-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 16.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.0

File hashes

Hashes for auditgate-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 af2027c3b5f9978dc6e193e5cb175603eb2e5e5754413f2013812d7fa7d24da2
MD5 02280dc524c60384442babe0b272b8c5
BLAKE2b-256 82bd2b2fd2c2bfc9e217012085bc8715cb5c4b591bc27c7ab1349146d39e26e3

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page