Skip to main content

HMAC-SHA256 chained, append-only audit log — Python bindings

Project description

ogentic-audit

CI License: Apache-2.0 Format v0.1

HMAC-SHA256 chained, append-only audit log library. Tamper-evident, language-agnostic on-disk format, built for evidence.

Status: v0.3.0. The on-disk format is specified in docs/spec/v0.1.md and the wire bytes are pinned by committed golden vectors. The format is the stable surface (0x0001, unchanged since v0.1); the Rust / Python APIs follow semantic versioning. See Status & versioning.

Why

Regulated industries and audit-grade AI tooling need an audit log that:

  • Cannot be silently edited — every record is HMAC-chained to the previous, so an edit by anyone without the key is detectable. The verifier reports the exact (segment, record_id) of the first violation, with a structured evidence payload an auditor can act on.
  • Can prove it wasn't rewritten — but only with a checkpoint. Chained HMACs verify the log against itself, which someone holding the key also satisfies after re-chaining fabricated history. ogentic-audit checkpoint pins the current head; ogentic-audit verify --checkpoint proves the log still extends the head you saw before. That only helps if the checkpoint is held by someone who can't rewrite the log — see the threat model, and cargo run -p ogentic-audit-core --example rewrite_attack to see the attack and the detection.
  • Survives crashes — append-only with atomic flush + F_FULLFSYNC on macOS; partial writes never produce a half-record. On reopen, the writer detects any torn tail (len_trailer != len_prefix) and truncates to the last fully-written record, surfacing a structured RecoveryReport to the caller.
  • Travels across languages — the on-disk format is documented byte-by-byte, with golden vectors that conforming implementations MUST round-trip. v0.1 ships Rust + Python; the format is intentionally implementable in any language that has HMAC-SHA256.
  • Is court-defensible — paired threat model and court-defensibility brief; the CLI ships a bit-reproducible export --pdf command for self-contained evidence packages.

Components

Quickstart

Rust

Add to Cargo.toml:

[dependencies]
# Not on crates.io yet — depend on the repo until the release lands:
ogentic-audit-core = { git = "https://github.com/OgenticAI/ogentic-audit" }
use ogentic_audit_core::{InMemoryKey, RecordInput, Writer, Verifier, PayloadValue};
use std::collections::BTreeMap;

fn main() -> anyhow::Result<()> {
    // 32 raw bytes; in real use load via ogentic-audit-keychain or a vault.
    let key = InMemoryKey::from_bytes([0u8; 32]);
    let session_id = [0u8; 16]; // UUIDv4 in real use

    let mut writer = Writer::open("./audit-logs", Box::new(key), session_id)?;
    let mut payload = BTreeMap::new();
    payload.insert("vault_id".into(), PayloadValue::Text("v-001".into()));
    writer.append(RecordInput {
        ts_wall: "2026-05-21T05:00:00.000Z".into(),
        ts_mono_delta: 0,
        actor: "user:alice".into(),
        event: "vault.unlocked".into(),
        payload,
        schema_version: 1,
    })?;
    writer.flush()?;
    drop(writer);

    // Verify the log end-to-end.
    let key = InMemoryKey::from_bytes([0u8; 32]);
    let verifier = Verifier::new(Box::new(key));
    let report = verifier.verify("./audit-logs")?;
    assert_eq!(report.compact_verdict(), "Verified");
    Ok(())
}

Python

# Not on PyPI yet — build the bindings from this repo:
pip install maturin && maturin develop -m python/ogentic-audit-py/Cargo.toml
from ogentic_audit import Writer, Reader, KeyHandle, verify

key = KeyHandle.from_env("OGENTIC_AUDIT_KEY_HEX")  # 64 hex chars

with Writer.open("./audit-logs", key=key) as w:
    w.append({"actor": "user:alice", "event": "vault.unlocked",
              "payload": {"vault_id": "v-001"}})

for record in Reader.open("./audit-logs"):
    print(record["record_id"], record["actor"], record["event"])

report = verify("./audit-logs", key=key)
assert report.ok

CLI — quick start

Not yet on Homebrew or crates.io. Until the release lands (OGE-1407), build the CLI from a clone: cargo build --release --bin ogentic-audit. The brew install ogenticai/tap/ogentic-audit and cargo install ogentic-audit paths below are what will work once it ships.

macOS (Homebrew) — after release

brew install ogenticai/tap/ogentic-audit

Linux / cross-platform (Cargo) — after release

cargo install ogentic-audit

Codesigning status (v0.1.0)

macOS binaries are sigstore-keyless-signed (cosign + GitHub OIDC) but not Apple Developer ID signed in v0.1.0. First launch on macOS may show a Gatekeeper dialog — right-click → Open to bypass. Apple Developer ID + notarization lands in v0.1.1.

Verify the sample log shipped with the project

The sample uses the public all-zeros fixture key; the CLI reads it from OGENTIC_AUDIT_KEY_HEX under the default --key-source=env. Set it first, then run the verify:

export OGENTIC_AUDIT_KEY_HEX=0000000000000000000000000000000000000000000000000000000000000000
ogentic-audit verify ./samples/matter-2024-CV-3047/matter-2024-CV-3047.log/ --summary
# ✓ Verified · 4 events · chain head 5c643f56

A tampered companion is also shipped — same four events with one byte flipped inside record 2's HMAC field — so you can see a failing verification end-to-end:

ogentic-audit verify ./samples/matter-2024-CV-3047-tampered/matter-2024-CV-3047.log/ --summary
# ✗ Verification failed · HmacMismatch at segment 0 record 2
echo $?
# 1

Prove the log was not rewritten

Chain verification alone cannot detect a rewrite by someone holding the key — it validates the log against itself. Pin the head, hand the pin to someone who does not control the log, and check against it later:

# Observe the current head and store it somewhere the writer can't reach.
ogentic-audit checkpoint ./samples/matter-2024-CV-3047/matter-2024-CV-3047.log/ --out head.json

# Later: prove the log still contains that history.
ogentic-audit verify ./samples/matter-2024-CV-3047/matter-2024-CV-3047.log/ --checkpoint head.json --summary

A rewritten log reports CheckpointMismatch; a truncated one reports CheckpointTruncated. Both exit 1. Keeping head.json next to the log achieves nothing — whoever can rewrite one can rewrite the other.

Exit codes (CI-friendly): 0 success, 1 verification failed, 2 I/O error, 3 argument error, 64 clap usage error.

The samples/ directory ships inside the release tarball (ogentic-audit-<target>.tar.gz) and inside the source repo. brew install and cargo install users get the binary only; either download the tarball, or git clone the repo, to follow the demo block above against the shipped sample.

Verify cosign signatures on the released binaries

Every release artifact is sigstore-keyless-signed (cosign + GitHub OIDC). The workflow uploads a split .sig + .pem pair alongside each tarball/zip; the certificate anchors the signature back to the GitHub Actions workflow that built it.

For the macOS arm64 build of v0.1.0:

cosign verify-blob \
  --certificate-identity "https://github.com/OgenticAI/ogentic-audit/.github/workflows/release-cli.yml@refs/tags/v0.1.0" \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --signature ogentic-audit-macos-arm64.tar.gz.sig \
  --certificate ogentic-audit-macos-arm64.tar.gz.pem \
  ogentic-audit-macos-arm64.tar.gz

Swap the artifact filename for the target you downloaded: ogentic-audit-macos-arm64.tar.gz, ogentic-audit-macos-x86_64.tar.gz, ogentic-audit-linux-x86_64.tar.gz, ogentic-audit-linux-aarch64.tar.gz, or ogentic-audit-windows-x86_64.zip. Each ships with a sibling .sig + .pem.

Daily-driver subcommands

# verify a vault's log (64 hex chars = 32 raw bytes)
export OGENTIC_AUDIT_KEY_HEX=$(openssl rand -hex 32)
ogentic-audit verify ./audit-logs            # exit 0 verified, 1 violation

# verify only segment 0 (useful for spot-checking a specific segment)
ogentic-audit verify ./audit-logs --segment 0

# machine-readable output (see "verify JSON output" below)
ogentic-audit verify ./audit-logs --format json

# pretty-print the last 100 records
ogentic-audit show ./audit-logs --from 0 --to 100

# spot-check the chain head
ogentic-audit head ./audit-logs --format json

verify JSON output (v0.2 shape — OGE-1063)

The --format json output uses status (not verdict) and segments_verified (not compact). If you have automation that reads the old keys, update it:

Old key New key Notes
verdict status Values: "ok" or "tampered"
compact removed Use status instead
segments_verified Count of segments walked

Clean example:

{
  "status": "ok",
  "format_version": 1,
  "segments_verified": 1,
  "log": { "segments_inspected": 1, "records_inspected": 1, ... }
}

Tampered example:

{
  "status": "tampered",
  "format_version": 1,
  "segments_verified": 1,
  "violation": { "kind": "HmacMismatch", "segment_index": 0, "record_id": 2, ... },
  "additional_violations": [],
  "log": { ... }
}

Violation detail text (kind, message, coordinates) is written to stderr; the JSON summary on stdout is clean for jq-based pipelines.

--segment <id> flag

Verify a single named segment. Useful for forensic spot-checks on large logs:

ogentic-audit verify ./audit-logs --segment 0          # verify segment 0 only
ogentic-audit verify ./audit-logs --segment 42         # verify segment 42 only

Exit codes for --segment:

  • 0 — segment verified clean
  • 1 — segment has a chain violation
  • 2 — segment index > 65535, or the segment file does not exist in the log directory

Design

The format is HMAC-SHA256 chained records framed inside per-segment files. Every record carries its prev_hash (the previous record's HMAC) inside the canonical-CBOR-encoded payload, and the segment header binds the genesis HMAC to the header bytes themselves. The verifier walks records, recomputes HMACs against the running chain, and short-circuits at the first deviation with structured evidence.

  • Hash: HMAC-SHA256 (FIPS 198-1)
  • Encoding: Canonical CBOR per RFC 8949 §4.2 (deterministic)
  • Segment header CRC: CRC32 (IEEE 802.3)
  • Key fingerprint: BLAKE3-256
  • Constant-time comparison: subtle on HMAC and key_id

Full spec: docs/spec/v0.1.md. Architecture rationale: docs/adr/0001-on-disk-format.md.

Comparative positioning

ogentic-audit Database audit logs (PostgreSQL, MySQL audit plugin) syslog / journald Blockchain (Hyperledger, Ethereum)
Tamper evidence HMAC chained; every record links to previous None — DB admin can rewrite None — root can rewrite Distributed consensus
Crash safety Atomic per-record framing, F_FULLFSYNC, structured recovery report Depends on the underlying storage engine Best-effort; rotation can drop records Block-level atomicity
Cross-language Spec'd byte format + golden vectors Vendor-specific Vendor-specific (rsyslog vs systemd-journald) EVM / chaincode-specific
Independent verifier verify is a 10-line function; CLI ships a JSON report Trust the DB Trust the OS Trust the chain
Latency / cost Microseconds per record, no network Microseconds; coupled to DB load Microseconds Seconds to minutes per record, gas fees
Court-defensibility narrative First-class: paired threat model + brief + PDF export Requires expert testimony per vendor Requires expert testimony Requires expert testimony + chain explanation

Use ogentic-audit when you need a portable, tamper-evident audit log for a single product (a vault, an AI agent, a compliance event stream) and you want the option to swap implementations later without rewriting the wire format. Skip ogentic-audit when you need distributed consensus across multiple writers (use a blockchain) or you're fine extending the DB you already operate (just turn on its audit plugin).

Court-defensibility

The legal narrative is documented in docs/legal/court-defensibility.md and pairs with the threat model. Three pieces in combination:

  1. Cryptographic invariants — HMAC chain, constant-time compare, subtle crate; refuses to resume from in-place-tampered logs.
  2. Operational invariants — append-only, F_FULLFSYNC on macOS, structured RecoveryReport for crash recovery, golden-vector conformance asserted in CI.
  3. Independent verification — verifier is a thin function (Rust + Python today, format-spec'd for any language); not a black box.

⚖️ The court-defensibility brief is currently engineering's read; the legal-team sign-off lands before v0.1.0 GA.

Status & versioning

  • Library API (Rust + Python): alpha until v0.1.0. Pre-v0.1.0, the surface MAY change between alpha tags; we'll call out breaking moves in CHANGELOG.
  • On-disk format: the segment-header layout, record schema, and HMAC chain are pinned by the committed golden vectors. Once v0.1.0 ships, the format is frozen until v0.2 (which lands under tests/vectors/v0.2/ so v0.1 readers continue to compile and pass).
  • MSRV: Rust 1.85 (edition 2024).
  • Python: 3.9 + (abi3 wheels per pyo3's abi3-py39 feature).

Choose your key source

Three options, all implementing the same KeyHandle trait:

Source Crate Best for
In-memory ogentic-audit-core Tests, CI, transient workloads
OS keychain ogentic-audit-keychain Desktop apps (macOS / Linux / Windows)
KMS (server-side) ogentic-audit-kms Server-side, containerised, multi-tenant deployments
// KMS (server-side):
// let key = KmsKey::new(AwsKmsProvider::from_arn(arn).await?)?;

Full integration guide for the KMS option: docs/integrations/server-side-kms.md.

Documentation

License

Apache License 2.0 — see LICENSE and NOTICE.

Security

  • SECURITY.md — responsible-disclosure address for vulnerability reports. Do not open public issues for tamper-evidence, HMAC, or cryptographic findings; email the listed address.

Contributing

See CONTRIBUTING.md and CODE_OF_CONDUCT.md. The project plan and open tickets live on Linear.

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

ogentic_audit-0.3.0.tar.gz (154.7 kB view details)

Uploaded Source

Built Distributions

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

ogentic_audit-0.3.0-cp39-abi3-win_amd64.whl (834.1 kB view details)

Uploaded CPython 3.9+Windows x86-64

ogentic_audit-0.3.0-cp39-abi3-manylinux_2_28_x86_64.whl (1.2 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.28+ x86-64

ogentic_audit-0.3.0-cp39-abi3-manylinux_2_28_aarch64.whl (1.2 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.28+ ARM64

ogentic_audit-0.3.0-cp39-abi3-macosx_11_0_arm64.whl (389.2 kB view details)

Uploaded CPython 3.9+macOS 11.0+ ARM64

ogentic_audit-0.3.0-cp39-abi3-macosx_10_12_x86_64.whl (423.7 kB view details)

Uploaded CPython 3.9+macOS 10.12+ x86-64

File details

Details for the file ogentic_audit-0.3.0.tar.gz.

File metadata

  • Download URL: ogentic_audit-0.3.0.tar.gz
  • Upload date:
  • Size: 154.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for ogentic_audit-0.3.0.tar.gz
Algorithm Hash digest
SHA256 b6d2f54315a3087c86c0396af4720308f775e5dcf0afbbe738b2e0839e939347
MD5 e1f32a383ffe905d78f07d39817a5849
BLAKE2b-256 8a4c170beab9c623c3243a3399002a2e3c1a4eb71728fd2cdbddd90a4cd0be96

See more details on using hashes here.

Provenance

The following attestation bundles were made for ogentic_audit-0.3.0.tar.gz:

Publisher: wheels.yml on OgenticAI/ogentic-audit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ogentic_audit-0.3.0-cp39-abi3-win_amd64.whl.

File metadata

  • Download URL: ogentic_audit-0.3.0-cp39-abi3-win_amd64.whl
  • Upload date:
  • Size: 834.1 kB
  • Tags: CPython 3.9+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for ogentic_audit-0.3.0-cp39-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 f5d3271731f15d19e258fd0f21c8843e67335deba38ffb991958908036c115bd
MD5 661aef2f2e3fa96151180363217b10b5
BLAKE2b-256 0850f25e81b7370ab350f1552629a12f3842068e06a2c3d2c8b50761df29ad09

See more details on using hashes here.

Provenance

The following attestation bundles were made for ogentic_audit-0.3.0-cp39-abi3-win_amd64.whl:

Publisher: wheels.yml on OgenticAI/ogentic-audit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ogentic_audit-0.3.0-cp39-abi3-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for ogentic_audit-0.3.0-cp39-abi3-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 da2994ffba4b7c5016d53f08c89ef7f751dcf86cff0a2aca36486333a44290e8
MD5 f8a2dc5faa99f49bbd9e4f82e16b16ae
BLAKE2b-256 80baeda97b2f5181d55e6dc47dcd53f9990d1a4c8b0389fe72d03a81b1618786

See more details on using hashes here.

Provenance

The following attestation bundles were made for ogentic_audit-0.3.0-cp39-abi3-manylinux_2_28_x86_64.whl:

Publisher: wheels.yml on OgenticAI/ogentic-audit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ogentic_audit-0.3.0-cp39-abi3-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for ogentic_audit-0.3.0-cp39-abi3-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 9689a3a666fd7b08b9723a46e1034ae0162a6dcaad58014b6f5108d236c87547
MD5 fc1c981d935331f80672aac2cd64a1ab
BLAKE2b-256 6e34273aa162f51049f32040c2b5aa73f2b3ff7449207d440e64be65b4f134c7

See more details on using hashes here.

Provenance

The following attestation bundles were made for ogentic_audit-0.3.0-cp39-abi3-manylinux_2_28_aarch64.whl:

Publisher: wheels.yml on OgenticAI/ogentic-audit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ogentic_audit-0.3.0-cp39-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for ogentic_audit-0.3.0-cp39-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 9ba39fee39da445b899f488ff58a2a72afcedb545be8a29d00e9bbcadb2bcb5e
MD5 a6f2f4ef70aecdfc4081e8f49aa5f008
BLAKE2b-256 eb11fbb9ef8a2b3ee5748fae9f04370125b4e02e29d2fe474cebdd8d041972c2

See more details on using hashes here.

Provenance

The following attestation bundles were made for ogentic_audit-0.3.0-cp39-abi3-macosx_11_0_arm64.whl:

Publisher: wheels.yml on OgenticAI/ogentic-audit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ogentic_audit-0.3.0-cp39-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for ogentic_audit-0.3.0-cp39-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 26ce61471b2d25ee8635efd578c10dad6f14b93089fe9832140aefef527a640f
MD5 08b4948225951e6078113b481c6b38f0
BLAKE2b-256 8a47426451df9acefa221b3144e2b1a2d908bd1f33832629e6cf4df8cf0f1336

See more details on using hashes here.

Provenance

The following attestation bundles were made for ogentic_audit-0.3.0-cp39-abi3-macosx_10_12_x86_64.whl:

Publisher: wheels.yml on OgenticAI/ogentic-audit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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