---
title: Audit and export
description: Verify the chain on a schedule, produce a verifiable evidence pack, and treat retention changes as the destructive operation they are.
---

## Verify on a schedule

```bash
veefore audit verify
```

Exits non-zero if the chain is broken, and names the **first position** where
the recomputed hash diverges. Over the API:
`POST /v1/audit-events/verify-integrity`, requiring
`audit:verify_integrity`.

:::warning Verify on a schedule, not after an incident
A check you only run when you suspect something tells you nothing about *when*
the problem started. Run it daily, from CI or a cron job, with the result going
somewhere a person reads.

Then a failure has a date attached, and the date narrows the investigation to a
window instead of to all of history.
:::

```yaml
name: Veefore audit integrity
on:
  schedule: [{ cron: '0 6 * * *' }]
jobs:
  verify:
    runs-on: ubuntu-latest
    env:
      VEEFORE_CONTROL_PLANE_URL: ${{ vars.VEEFORE_CONTROL_PLANE_URL }} # self-hosted only
      VEEFORE_EMAIL: ${{ secrets.VEEFORE_AUDIT_EMAIL }}
      VEEFORE_PASSWORD: ${{ secrets.VEEFORE_AUDIT_PASSWORD }}
    steps:
      - uses: actions/setup-node@v4
        with: { node-version: '20' }
      - run: npm install -g veefore
      - run: veefore audit verify
```

An `AUDITOR` role is enough — it holds `audit:read`, `audit:export` and
`audit:verify_integrity` and nothing that can change anything.

## Produce an evidence pack

```bash
veefore audit export \
  --format csv \
  --from 2026-07-01T00:00:00Z \
  --to 2026-10-01T00:00:00Z \
  --reason "Quarterly SOC 2 evidence" \
  --out audit-2026-q3.csv
```

Three things happen:

1. **The reason is required and recorded.**
2. **The export is itself an audit event.** Removing evidence from the system is worth knowing happened.
3. **The file is watermarked and you get a content hash.** An auditor recomputes the hash to prove the file they received is the file that was produced.

Written at mode `0600`.

:::security Give the auditor the hash separately
The hash proves the file is unaltered only if it reaches them through a
different path than the file. Emailing both in one message proves nothing —
whoever could alter one could alter the other.

Send the file however is convenient; send the hash over a channel that is
independently authenticated.
:::

Over the API: `POST /v1/audit-events/export`, requiring `audit:export`.

## Search

```bash
veefore audit list --severity CRITICAL --from 2026-10-01T00:00:00Z
veefore audit list --type agent.revoked
veefore audit show evt_01ABC
```

Cursor-paginated over the API:

```http
GET /v1/audit-events?severity=CRITICAL&cursor=…&limit=50
GET /v1/audit-events/{eventId}
```

The detail view includes the event's position in the hash chain.

## Severity, and what belongs in CRITICAL

| | |
| --- | --- |
| `INFO` | Routine state changes |
| `NOTICE` | Worth seeing in a review |
| `WARNING` | Something is off |
| `CRITICAL` | A security team must see this |

`CRITICAL` is reserved for: agent revocation, emergency controls, break-glass
access, **reducing enforcement**, and changing audit retention.

:::note If CRITICAL is noisy, something is miscategorised
The point of the severity is that a `CRITICAL` event is always worth a human
look. A `CRITICAL` stream that gets skimmed is a `CRITICAL` stream that will be
skimmed on the day it matters.
:::

## Ship it somewhere else

Audit events exist to survive. The chain detects tampering within the stored
sequence; it does not protect against an attacker with database write access
*and* the chain secret, who could rewrite the whole chain consistently.

The mitigation is boring and effective:

- Keep `VEEFORE_AUDIT_CHAIN_SECRET` out of the database and out of the application's own config store.
- Restrict database write access to the application role.
- Ship events to an append-only sink you control separately — object storage with versioning and object lock, or your SIEM.

Subscribe a webhook to the event types you care about, or export on a schedule.
Either way the second copy is what turns "we think nothing was altered" into
"two independent records agree".

See [Audit integrity](/secure/audit-integrity).

## Retention

Configurable, requiring `audit:configure_retention` — step-up gated, writing a
`CRITICAL` audit event.

:::danger Shortening retention destroys evidence
That is why it is a high-impact, step-up-gated, `CRITICAL`-audited operation. A
request to "clean up old audit data" leaves a mark explaining who asked and why.

Export and archive before you shorten:

```bash
veefore audit export --format json \
  --reason "Pre-retention-change archive" --out archive.json
```

The archive is watermarked and hashed, so it remains verifiable afterwards.
:::

## Correlation

Every API response carries `x-request-id` and `x-trace-id`. Both appear on the
action record, on the audit event, and in the structured logs.

Given a `request_id` from a user complaint:

```bash
veefore logs --limit 100              # the decision
curl -s $CP/v1/actions/act_01ABC …        # the full lineage
curl -s $CP/v1/audit-events/evt_01ABC …   # the audit event
# plus every log line, if you index on requestId
```

That is the intended path, and it is why the ids are on the response rather than
only in the logs.

## What an export contains

For a protected action: the actor and its type, the resolved authority and
delegation chain, every policy consulted with versions, every rule that matched,
every risk signal with its weight and explanation, the approval and who decided
it, the credential lease **by reference**, the downstream status, the outcome,
and the correlation ids.

Never the credential material. Never a private key. Masked parameter paths are
masked in audit too, because a `MASK` decision redacts the value in the trail as
well as in the forwarded request.

## Related

:::cards

:::card Audit | /concepts/audit
The chain and what it proves.
:::

:::card Audit integrity | /secure/audit-integrity
The threat model.
:::

:::card Compliance | /secure/compliance
Control mapping with live evidence.
:::

:::card Audit API | /reference/api/audit
Search, export, verify.
:::

:::
