> ## Documentation Index
> Fetch the complete documentation index at: https://attesta.kyberon.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# TrailProof Integration

> Switch from the legacy audit backend to TrailProof for enhanced tamper-evident logging with HMAC signing and multi-tenancy

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

<Note>
  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.
</Note>

***

## Installation

TrailProof is an optional dependency. Install it alongside Attesta:

<CodeGroup>
  ```bash Python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  pip install attesta[trailproof]
  ```

  ```bash TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  npm install @kyberon/attesta @kyberonai/trailproof
  ```
</CodeGroup>

<Warning>
  If you configure `audit.backend: trailproof` without installing the package, Attesta will raise an `ImportError` at initialization with clear installation instructions.
</Warning>

***

## Configuration

Enable TrailProof by setting `audit.backend` in your `attesta.yaml`:

```yaml attesta.yaml theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
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
```

| Field       | Required | Default                | Description                                   |
| ----------- | -------- | ---------------------- | --------------------------------------------- |
| `backend`   | No       | `legacy`               | Backend type: `legacy` or `trailproof`        |
| `path`      | No       | `.attesta/audit.jsonl` | File path for the JSONL audit log             |
| `tenant_id` | No       | `default`              | Tenant identifier for multi-tenancy isolation |
| `hmac_key`  | No       | None                   | HMAC signing key for cryptographic provenance |

<Tip>
  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.
</Tip>

***

## Field Mapping

TrailProof uses a 10-field event envelope. Attesta audit fields are mapped as follows:

| Attesta Field     | TrailProof Field | Notes                                                                                                          |
| ----------------- | ---------------- | -------------------------------------------------------------------------------------------------------------- |
| `entry_id`        | `event_id`       | Auto-generated by TrailProof                                                                                   |
| (derived)         | `event_type`     | Set to `attesta.approval.{verdict}` (e.g., `attesta.approval.approved`)                                        |
| `intercepted_at`  | `timestamp`      | Auto-generated by TrailProof                                                                                   |
| `agent_id`        | `actor_id`       | Direct mapping; defaults to `"unknown"` if not set                                                             |
| (config)          | `tenant_id`      | Set once at backend initialization from config                                                                 |
| `session_id`      | `session_id`     | Direct mapping                                                                                                 |
| (hints)           | `trace_id`       | Optional, passed through `ActionContext.hints`                                                                 |
| All other fields  | `payload`        | Bundled into payload: `action_name`, `risk_score`, `risk_level`, `challenge_type`, `verdict`, `metadata`, etc. |
| (internal)        | `prev_hash`      | Managed by TrailProof                                                                                          |
| (internal)        | `hash`           | Managed by TrailProof                                                                                          |
| (if HMAC key set) | `signature`      | Managed 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

<CodeGroup>
  ```python Basic Setup theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  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")
  ```

  ```python Programmatic Configuration theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  from attesta import Attesta
  from attesta.core.audit_backend import TrailProofBackend

  # Create TrailProof backend directly
  backend = TrailProofBackend(
      path=".attesta/audit.jsonl",
      tenant_id="acme-corp",
      hmac_key="your-secret-key"
  )

  # Pass to Attesta
  attesta = Attesta(audit_backend=backend)

  @attesta.gate()
  def delete_user(user_id: str) -> None:
      """Permanently delete a user account."""
      # Implementation here
      pass
  ```

  ```python Verification theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  from attesta.core.audit_backend import TrailProofBackend

  # Verify the audit trail integrity
  backend = TrailProofBackend(path=".attesta/audit.jsonl")
  intact, total, broken = backend.verify()

  if intact:
      print(f"✓ Chain integrity verified ({total} entries)")
  else:
      print(f"✗ Chain integrity compromised ({len(broken)} broken entries)")
  ```
</CodeGroup>

### TypeScript

<CodeGroup>
  ```typescript Basic Setup theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  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");
  ```

  ```typescript Verification theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import { TrailProofBackend } from "@kyberon/attesta";

  // Verify the audit trail integrity
  const backend = new TrailProofBackend({
    path: ".attesta/audit.jsonl"
  });

  const verification = backend.verify();

  if (verification.intact) {
    console.log(`✓ Chain integrity verified (${verification.total} entries)`);
  } else {
    console.log(`✗ Chain integrity compromised (${verification.broken.length} broken entries)`);
  }
  ```
</CodeGroup>

***

## 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 Type    | Detection                                                 |
| ----------------- | --------------------------------------------------------- |
| Modified entry    | Hash mismatch at the modified entry                       |
| Deleted entry     | Hash mismatch at the entry after the deleted one          |
| Inserted entry    | Hash mismatch at the inserted entry                       |
| Reordered entries | Hash mismatch at every reordered position                 |
| Signature forgery | HMAC signature verification fails (if signing is enabled) |

<CodeGroup>
  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  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
  ```

  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import { TrailProofBackend } from "@kyberon/attesta";

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

  const verification = backend.verify();

  if (!verification.intact) {
    console.log("ALERT: Audit trail has been tampered with!");
    console.log(`Broken entries at indices: ${verification.broken}`);
    // Investigate immediately
  }
  ```
</CodeGroup>

<Warning>
  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.).
</Warning>

***

## 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:

<CodeGroup>
  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  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}")
  ```

  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import { TrailProofBackend } from "@kyberon/attesta";

  const backend = new TrailProofBackend({
    path: ".attesta/audit.jsonl"
  });

  // Query by agent ID (maps to actorId in TrailProof)
  const events = backend.query({ agentId: "deploy-bot", limit: 10 });

  for (const event of events) {
    console.log(`Event: ${event.eventType} at ${event.timestamp}`);
  }
  ```
</CodeGroup>

<Note>
  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.
</Note>

***

## 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.

```yaml attesta.yaml theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
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

<Tip>
  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.
</Tip>

***

## 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.

```yaml attesta.yaml theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
audit:
  backend: trailproof
  hmac_key: "your-secret-key"  # Enable HMAC signing
```

<Warning>
  Never commit your HMAC key to version control. Store it in an environment variable and read it at initialization:

  ```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import os
  from attesta.core.audit_backend import TrailProofBackend

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

***

## 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:**
   ```yaml theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
   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:**
   ```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
   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.

<Note>
  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.
</Note>

***

## Comparison: Legacy vs TrailProof

| Feature                 | Legacy Backend   | TrailProof Backend           |
| ----------------------- | ---------------- | ---------------------------- |
| Hash-chaining           | SHA-256          | SHA-256                      |
| HMAC signatures         | No               | Yes (optional)               |
| Multi-tenancy           | No               | Yes                          |
| Trace correlation       | No               | Yes                          |
| Cursor-based pagination | No               | Yes                          |
| Storage format          | JSONL            | JSONL                        |
| Verification API        | `verify_chain()` | `verify()`                   |
| Query API               | Basic filtering  | Advanced filtering + cursors |
| Dependencies            | Zero             | TrailProof package           |
| Maintained by           | Attesta core     | Kyberon AI (sibling project) |

***

## Example Audit Entry

Here's what a TrailProof-backed audit entry looks like in the JSONL file:

```json theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
{
  "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"
}
```

<CardGroup cols={2}>
  <Card title="Audit Trail Concepts" icon="file-shield" color="#16A34A" href="/concepts/audit-trail">
    Understand audit trail fundamentals and hash-chaining
  </Card>

  <Card title="Production Deployment" icon="rocket" color="#15803D" href="/guides/production-deployment">
    Best practices for deploying Attesta in production
  </Card>
</CardGroup>
