๐Ÿฆ€ Rust Core ๐Ÿ Python API v0.3.1 ๐Ÿ“ฆ PyPI

Audit logs you can
actually trust

Drop-in audit trail for FastAPI, Django, and any Python backend.
Every event is chained with SHA-256 โ€” tampering doesn't go unnoticed. Ship the same events to ImmutableLog when you need an external, verifiable receipt.

$ pip install rust-py-audit
python
>>> from rust_py_audit import AuditLogger
>>> audit = AuditLogger(app_name="billing-api")
>>> audit.log(action="DELETE_INVOICE", ...)
{'hash': '5eac3612da...', 'previous_hash': None}
>>> audit.verify()
{'valid': True, 'total_events': 1}
>>> โ–ˆ
88Tests passing
SHA-256Hash chain
3Delivery modes
0Runtime deps

Everything an audit trail needs

Rust handles the hashing and I/O. Python stays simple.

๐Ÿ“

Structured Events

id, timestamp, actor_id, action, resource and free-form metadata โ€” generated automatically on every log() call.

๐Ÿ”—

Hash Chain Integrity

Each event embeds the SHA-256 hash of the one before it. Edit, delete, or reorder a line and verify() catches it.

๐Ÿ“‚

JSONL Storage

One event per line, append-only. No database, no migrations โ€” just a file you can tail -f.

โšก

FastAPI Middleware

Add AuditMiddleware in one line. Logs every state-changing request (POST/PUT/PATCH/DELETE) automatically.

๐ŸŽธ

Django Middleware

Works with both WSGI and ASGI Django apps. Drop it in MIDDLEWARE and it logs the rest.

๐Ÿ”—

ImmutableLog Integration

mode="local" (default, no network), "remote", or "hybrid" โ€” ship events to ImmutableLog with retry, idempotency keys, and a flush_pending() queue for anything that didn't land.

๐Ÿฆ€

Rust Core via PyO3

Hashing, serialization, file I/O, and the ImmutableLog HTTP client run in Rust and compile to a native .so extension. No Rust needed to use it.

๐Ÿงต

Thread-safe

Share a single AuditLogger across threads โ€” multi-threaded WSGI workers or one middleware instance serving concurrent requests. The hash chain stays linear under load.

Works with your stack

One middleware line, or call the core API directly.

Python
from fastapi import FastAPI
from rust_py_audit.fastapi import AuditMiddleware

app = FastAPI()

# Logs every POST/PUT/PATCH/DELETE automatically
app.add_middleware(AuditMiddleware, app_name="billing-api")

@app.delete("/invoices/{invoice_id}")
async def delete_invoice(invoice_id: str):
    return {"deleted": invoice_id}
Python
# settings.py
MIDDLEWARE = [
    "rust_py_audit.django.AuditMiddleware",
    # ... rest of your middleware
]

# optional configuration
RUST_PY_AUDIT_APP_NAME = "billing-django"
RUST_PY_AUDIT_FILE_PATH = "./audit.jsonl"
Python
from rust_py_audit import AuditLogger

audit = AuditLogger(app_name="billing-api", file_path="./audit.jsonl")

event = audit.log(
    actor_id="user_123",
    action="DELETE_INVOICE",
    resource="invoice",
    resource_id="inv_987",
    metadata={"ip": "192.168.0.10"},
)
print(event["hash"])      # 64-char SHA-256 hex digest
print(audit.last_hash())  # same hash, O(1) lookup

result = audit.verify()
print(result)               # {"valid": True, "total_events": 1, ...}
Python
from rust_py_audit import AuditLogger

# mode="hybrid": writes audit.jsonl locally AND ships to ImmutableLog
audit = AuditLogger(
    app_name="billing-api",
    file_path="./audit.jsonl",
    mode="hybrid",
    immutablelog_url="https://api.immutablelog.com",
    immutablelog_api_key="iml_live_xxxxx",
)

event = audit.log(
    actor_id="user_123",
    action="DELETE_INVOICE",
    resource="invoice",
    resource_id="inv_987",
)
print(event["immutablelog"])
# {"status": "delivered", "tx_id": "tx_...", ...}
# or {"status": "pending", ...}  on a transient failure (queued) โ€” never raises
# or {"status": "failed", ...}   on a permanent failure (not queued)

# Retry anything still marked "pending" (e.g. on a cron):
audit.flush_pending()
# {"flushed": 1, "failed": 0, "still_pending": 0, "total": 1}

Tamper-evident by design

Every event links to the one before it. Break the chain and verify() tells you exactly where.

LOGIN
prev: null
hash: 5eac36...
โ†’
DELETE_INVOICE
prev: 5eac36...
hash: 2c5483...
โ†’
โœ• LOGOUT (edited)
prev: 2c5483...
hash: mismatch!

What gets caught

  • hash_mismatch edited event
  • broken_chain deleted event
  • broken_chain reordered events
  • broken_chain forged previous_hash

How it works

  • SHA-256 content + previous_hash
  • JSONL stable field order
  • verify() rereads & recomputes everything
audit.verify() โ€” intact chain
{
  "valid": True,
  "total_events": 10,
  "last_hash": "a1b2c3..."
}
audit.verify() โ€” tampered chain
{
  "valid": False,
  "total_events": 10,
  "error_index": 4,
  "reason": "hash_mismatch"
}

How it works

Rust hashes and persists. Python integrates. You verify.

Your App
FastAPI Django Script
โ†’
Middleware / API
AuditMiddleware AuditLogger.log() flush_pending()
โ†’
๐Ÿฆ€ Rust Core
hash.rs (SHA-256) storage.rs (JSONL) verifier.rs immutablelog_client.rs retry.rs
โ†’
Output
audit.jsonl dict / verify() ImmutableLog receipt

The native .so extension is compiled once at publish time via maturin + PyO3.
Your users just pip install โ€” no Rust toolchain required. ImmutableLog delivery is fully optional โ€” mode="local" (the default) never touches the network.

Ready in seconds

Install from PyPI. No Rust, no compilers, no configuration.

Basic

pip install rust-py-audit

With FastAPI

pip install "rust-py-audit[fastapi]"

With Django

pip install "rust-py-audit[django]"

Full stack

pip install "rust-py-audit[fastapi,django]"
Requires Python 3.10+ ยท Linux ยท macOS ยท Windows ยท MIT License
Copied!