Skip to main content
Attesta ships with a built-in SHA-256 hash-chained JSONL audit logger, but also supports TrailProof as an alternative audit backend. TrailProof is a standalone, zero-dependency library purpose-built for tamper-evident event logging with HMAC signing, multi-tenancy, trace correlation, and cursor-based queries.

Why TrailProof?

The legacy audit backend (Attesta’s built-in logger) provides basic hash-chaining and verification. TrailProof adds:
  • HMAC signatures for cryptographic provenance
  • Multi-tenancy isolation via tenant IDs
  • Trace correlation for distributed workflows
  • Cursor-based pagination for large audit logs
  • Pluggable storage (in-memory or JSONL)
  • Production-grade features maintained as a dedicated library
Both backends are fully supported. The legacy backend remains the default and will continue to receive updates. TrailProof is optional and requires an additional package installation.

Installation

TrailProof is an optional dependency. Install it alongside Attesta:
pip install attesta[trailproof]
If you configure audit.backend: trailproof without installing the package, Attesta will raise an ImportError at initialization with clear installation instructions.

Configuration

Enable TrailProof by setting audit.backend in your attesta.yaml:
attesta.yaml
audit:
  backend: trailproof          # Switch from "legacy" (default) to "trailproof"
  path: ".attesta/audit.jsonl" # File path for the JSONL event log
  tenant_id: "my-org"          # Tenant ID for multi-tenancy isolation
  hmac_key: "your-secret-key"  # Optional HMAC signing key
FieldRequiredDefaultDescription
backendNolegacyBackend type: legacy or trailproof
pathNo.attesta/audit.jsonlFile path for the JSONL audit log
tenant_idNodefaultTenant identifier for multi-tenancy isolation
hmac_keyNoNoneHMAC signing key for cryptographic provenance
Store your HMAC key in an environment variable and reference it in your code, not directly in the YAML file. TrailProof supports reading the key at initialization.

Field Mapping

TrailProof uses a 10-field event envelope. Attesta audit fields are mapped as follows:
Attesta FieldTrailProof FieldNotes
entry_idevent_idAuto-generated by TrailProof
(derived)event_typeSet to attesta.approval.{verdict} (e.g., attesta.approval.approved)
intercepted_attimestampAuto-generated by TrailProof
agent_idactor_idDirect mapping; defaults to "unknown" if not set
(config)tenant_idSet once at backend initialization from config
session_idsession_idDirect mapping
(hints)trace_idOptional, passed through ActionContext.hints
All other fieldspayloadBundled into payload: action_name, risk_score, risk_level, challenge_type, verdict, metadata, etc.
(internal)prev_hashManaged by TrailProof
(internal)hashManaged by TrailProof
(if HMAC key set)signatureManaged by TrailProof

Event Type Convention

The event_type field follows the pattern attesta.approval.{verdict}, producing values like:
  • attesta.approval.approved
  • attesta.approval.denied
  • attesta.approval.auto_approved
  • attesta.approval.timed_out
This convention allows you to filter events by approval outcome in TrailProof queries.

Usage Examples

Python

from attesta import Attesta

# Load config with TrailProof backend
attesta = Attesta.from_config("attesta.yaml")

@attesta.gate()
def deploy_service(service: str, version: str) -> str:
    """Deploy a service to production."""
    return f"Deployed {service} v{version}"

# Approval decisions are automatically logged to TrailProof
result = deploy_service("api-gateway", "v2.1.0")

TypeScript

import { Attesta, gate } from "@kyberon/attesta";
import { TrailProofBackend } from "@kyberon/attesta";

// Create TrailProof backend
const backend = new TrailProofBackend({
  path: ".attesta/audit.jsonl",
  tenantId: "acme-corp",
  hmacKey: "your-secret-key"
});

// Create Attesta with TrailProof backend
const attesta = new Attesta({
  auditBackend: backend
});

// Use the gate decorator
const deployService = gate(async (service: string, version: string) => {
  return `Deployed ${service} v${version}`;
});

// Approval decisions are automatically logged to TrailProof
const result = await deployService("api-gateway", "v2.1.0");

Verifying Integrity

TrailProof provides the same verification guarantees as the legacy backend, but uses its own hash-chaining and signature algorithms.

What Verification Detects

Tampering TypeDetection
Modified entryHash mismatch at the modified entry
Deleted entryHash mismatch at the entry after the deleted one
Inserted entryHash mismatch at the inserted entry
Reordered entriesHash mismatch at every reordered position
Signature forgeryHMAC signature verification fails (if signing is enabled)
from attesta.core.audit_backend import TrailProofBackend

backend = TrailProofBackend(
    path=".attesta/audit.jsonl",
    hmac_key="your-secret-key"
)

intact, total, broken_indices = backend.verify()

if not intact:
    print(f"ALERT: Audit trail has been tampered with!")
    print(f"Broken entries at indices: {broken_indices}")
    # Investigate immediately
Chain verification is a forward-only operation. It can detect tampering but cannot recover the original data. For production use, consider replicating the audit log to an immutable store (S3 with Object Lock, append-only databases, etc.).

Querying Events

TrailProof provides a query API that supports filtering by actor, tenant, event type, and more. The Attesta backend adapter exposes a simplified query interface:
from attesta.core.audit_backend import TrailProofBackend

backend = TrailProofBackend(path=".attesta/audit.jsonl")

# Query by agent ID (maps to actor_id in TrailProof)
events = backend.query(agent_id="deploy-bot", limit=10)

for event in events:
    print(f"Event: {event.event_type} at {event.timestamp}")
For advanced queries (filtering by tenant, trace, cursor-based pagination), use the TrailProof library directly. The Attesta backend adapter provides a simplified interface for common use cases.

Multi-Tenancy

TrailProof supports multi-tenancy isolation via tenant IDs. All events logged by a TrailProof backend are tagged with the tenant_id configured at initialization.
attesta.yaml
audit:
  backend: trailproof
  tenant_id: "acme-corp"  # All events tagged with this tenant ID
  path: ".attesta/audit.jsonl"
This allows you to:
  • Store audit logs for multiple tenants in the same file
  • Filter events by tenant in queries
  • Maintain separate integrity chains per tenant
If you’re deploying Attesta in a multi-tenant SaaS application, set the tenant_id dynamically based on the current request context. The TrailProof backend can be initialized per-tenant or reconfigured at runtime.

HMAC Signing

TrailProof supports HMAC signatures for cryptographic provenance. When you provide an hmac_key, every event is signed with HMAC-SHA256, and verification checks both hash integrity and signature validity.
attesta.yaml
audit:
  backend: trailproof
  hmac_key: "your-secret-key"  # Enable HMAC signing
Never commit your HMAC key to version control. Store it in an environment variable and read it at initialization:
import os
from attesta.core.audit_backend import TrailProofBackend

backend = TrailProofBackend(
    path=".attesta/audit.jsonl",
    hmac_key=os.environ.get("ATTESTA_HMAC_KEY")
)

Migration from Legacy Backend

Audit trails are stored as independent JSONL files. When you switch from legacy to trailproof, Attesta will start writing to a new TrailProof-formatted log. Your existing legacy audit log remains intact and can still be verified using the LegacyBackend.

Migration Strategy

  1. Keep both logs during transition:
    audit:
      backend: trailproof
      path: ".attesta/audit-trailproof.jsonl"  # New TrailProof log
    
    Your old .attesta/audit.jsonl remains unchanged.
  2. Verify the legacy log one last time:
    from attesta.core.audit_backend import LegacyBackend
    
    legacy = LegacyBackend(path=".attesta/audit.jsonl")
    intact, total, broken = legacy.verify()
    print(f"Legacy log: {total} entries, intact={intact}")
    
  3. Archive the legacy log to immutable storage.
  4. Switch to TrailProof for all new events.
There is no automatic migration tool to convert legacy JSONL entries into TrailProof format. The two backends use different field structures and hash algorithms. If you need to analyze both logs together, export them to a common format (CSV, JSON) using Attesta’s exporter utilities.

Comparison: Legacy vs TrailProof

FeatureLegacy BackendTrailProof Backend
Hash-chainingSHA-256SHA-256
HMAC signaturesNoYes (optional)
Multi-tenancyNoYes
Trace correlationNoYes
Cursor-based paginationNoYes
Storage formatJSONLJSONL
Verification APIverify_chain()verify()
Query APIBasic filteringAdvanced filtering + cursors
DependenciesZeroTrailProof package
Maintained byAttesta coreKyberon AI (sibling project)

Example Audit Entry

Here’s what a TrailProof-backed audit entry looks like in the JSONL file:
{
  "event_id": "evt_a3f7b9c2",
  "event_type": "attesta.approval.approved",
  "timestamp": "2025-01-15T14:30:47.300Z",
  "actor_id": "admin-bot",
  "tenant_id": "acme-corp",
  "session_id": "sess_abc123",
  "trace_id": null,
  "payload": {
    "action_name": "delete_user",
    "action_description": "Permanently delete user account usr_12345",
    "risk_score": 0.82,
    "risk_level": "critical",
    "challenge_type": "multi_party",
    "challenge_passed": true,
    "approver_ids": ["alice@company.com", "bob@company.com"],
    "verdict": "approved",
    "review_duration_seconds": 47.3,
    "min_review_met": true,
    "intercepted_at": "2025-01-15T14:30:00.000Z",
    "decided_at": "2025-01-15T14:30:47.300Z",
    "executed_at": "2025-01-15T14:30:47.450Z",
    "environment": "production",
    "metadata": {
      "user_id": "usr_12345",
      "reason": "GDPR right-to-erasure request"
    }
  },
  "prev_hash": "b4c7e9f1a3b5c7d9e1f3a5b7c9d1e3f5a7b9c1d3e5f7a9b1c3d5e7f9a1b3c5",
  "hash": "e8f2a4b6c8d0e2f4a6b8c0d2e4f6a8b0c2d4e6f8a0b2c4d6e8f0a2b4c6d8e0",
  "signature": "a9f3e7b2c4d6f8a1b3c5d7e9f1a3b5c7d9e1f3a5b7c9d1e3f5a7b9c1d3e5f7"
}

Audit Trail Concepts

Understand audit trail fundamentals and hash-chaining

Production Deployment

Best practices for deploying Attesta in production