# Audit Verify

> Verify the integrity of ActiveCAMT's append-only audit-log hash chain (tamper evidence) by running AuditService.verifyChainIntegrity — via the existing GET /api/admin/audit-verify route or a local script. Use before a deploy/migration that touches audit_logs or users, periodically, or on any suspicion of tampering. Read-only; a broken chain is a security incident, never "repaired".

- Skill: `daydeda/audit-verify` (Agent Skill)
- Install (CLI): `npx skillmds@latest add daydeda/audit-verify`
- Raw SKILL.md: https://api.skillmd.com/api/skills/daydeda/audit-verify/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: daydeda (https://skillmd.com/u/daydeda)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/daydeda/audit-verify

---


# Audit Verify (ActiveCAMT)

`audit_logs` is an **append-only SHA256 hash chain**: each row's `rowHash` folds in the
previous row's hash (`prevHash`), serialized by an advisory lock so concurrent appends
can't fork it. Any insert, delete, modification, or reorder of a historical row breaks
the chain and is detectable. `AuditService.verifyChainIntegrity()`
(`src/modules/audit/audit.service.ts`) walks the chain and reports the first break.
Today it's only run by hand — this skill operationalizes it.

## How to run
- **Preferred:** there's already an endpoint — `GET /api/admin/audit-verify` (`src/app/api/admin/audit-verify/route.ts`). Hit it authenticated as `super_admin`/`admin` and read the `ChainVerifyResult` (ok, and if not, the first offending row).
- **Local / CI:** run `verifyChainIntegrity()` against the target DB via a small `tsx` script. Rehearse against the **local** DB (`.env.local`, see `/db-local`); only point at prod read-only and deliberately.

## When to run
- Before/after a migration or deploy that touches `audit_logs` or `users` (user deletion interacts with the dropped audit FKs — migration step 27).
- Periodically as a tamper check, and immediately on any suspicion of tampering.
- Note: it can't be a `/schedule` cron easily if it requires an authenticated session — drive it via the route in an interactive/CI context.

## Hard rules
- **Read-only.** This only verifies; it never writes.
- **Never "fix" a broken chain.** Rewriting or back-filling `audit_logs` to make it validate defeats the entire tamper-evidence guarantee. A break = treat as a **security incident**: capture the first offending row id, stop, and surface it to the user. Do not mutate audit rows.
- Do not export or include audit-log contents in any data export (see `/pdpa-export`).

## Output
`ok: true`, or `ok: false` with the first broken row id and the surrounding context, plus an explicit "treat as a security incident — not auto-repairing" note when broken.

