# Audit Logging

> Every mutation in @azmr/db and every AI fix attempt is written to a tamper-evident audit log.

Source: https://platform.azmara.io/docs/security/audit-logging

## How the hash chain works

```
Entry 1: { action: "createTable", prevHash: "", hash: "a3f..." }
Entry 2: { action: "insert",      prevHash: "a3f...", hash: "9b2..." }
Entry 3: { action: "insert",      prevHash: "9b2...", hash: "c41..." }
```

Modifying entry 2's content changes its hash. Entry 3's `prevHash` then no longer matches entry 2's `hash` — the tamper is immediately detectable by replaying the chain.

## Usage

```typescript
import { createAuditLogger } from "@azmr/security";

const audit = createAuditLogger("payments");

audit.log("payment:processed", { orderId: "abc123", amount: 99.99 });
audit.log("payment:refunded",  { orderId: "abc123" });
```

## Log format

Each line is a JSON object:

```json
{
  "timestamp": "2026-04-08T00:00:00.000Z",
  "context": "payments",
  "action": "payment:processed",
  "meta": { "orderId": "abc123", "amount": 99.99 },
  "prevHash": "a3f2c1...",
  "hash": "9b2d44..."
}
```

## Concurrency and restarts

Every `createAuditLogger()` call targeting the same resolved log path — including one from a different package, or one created after a process restart — shares one hash chain. On creation, the logger seeds itself from the last valid entry already on disk, rather than starting a fresh chain at `prevHash: ""`. This means two loggers (e.g. `@azmr/db` and `@azmr/ai`, both writing to the default `.azmara/audit.log`) interleave into a single valid chain instead of each producing false "chain broken" reports.

> **Single writer process per log file**
>
> This module assumes one writer **process** per log file — there is no file locking. Two separate OS processes appending to the same path concurrently can still interleave writes and desync their chains. If multiple processes must write to the same audit log, route them through one process rather than writing directly from each.

`log()` appends synchronously (`fs.appendFileSync`), so each call blocks the event loop until the write completes — a deliberate trade of throughput for simple, easy-to-reason-about ordering.

## Log location

Default: `.azmara/audit.log`

Override:

```bash
AZMARA_AUDIT_LOG=/var/log/azmara/audit.log
```

## What NOT to log

> **Never log these**
>
> - Passwords or password hashes
> - API keys or tokens
> - Full PII (name + email + address combined)
> - Session tokens or JWTs

These never belong in `meta` — log identifiers (user ID, order ID) instead.
