theam / theam/facility

Audit verify reports legacy writer serialization mismatches as tamper-like chain breaks

Open
#202 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
TypeScript
Stars
71
Forks
64
Avg merge
15h 38m
Merged PRs (30d)
66

Description

Problem

GET /v1/audit/verify can report ok: false for rows created before 3a23cadf33ef (fix(audit): hash persisted JSON representation), even when no stored audit row was modified.

The old writer hashed the in-memory object and then persisted it as JSONB. Values such as an optional undefined object property were present in the old hash input but removed by JSON serialization. The current verifier only has the persisted JSON and therefore computes a different content hash.

This is a real content-hash mismatch, but it is writer-generated legacy drift rather than evidence of tampering. List pagination and display order are unrelated: verification scans the full organization chain in ascending seq order.

Minimal reproduction

  1. With the pre-3a23cadf33ef algorithm, build a successful run.finished audit event whose payload is:
    { status: "succeeded", error: undefined, receipt_sha256: "..." }
    
  2. Hash that in-memory object and persist the row as JSONB. PostgreSQL retains no error property.
  3. Run the current verifyAuditChain against the stored row.
  4. Observe ok: false at that sequence, even though prev_hash still equals the previous row's stored hash and the following row points to this row's stored hash.

3a23cadf33ef prevents new occurrences by canonicalizing through JSON before hashing, but it does not provide a compatibility or migration path for rows already written with v1.

Expected

Upgrades should not make historical, writer-generated serialization drift indistinguishable from post-write mutation. Verification should state whether the failure is:

  • a prev_hash link mismatch;
  • a current-algorithm content-hash mismatch;
  • or a known/unverifiable legacy serialization mismatch.

Suggested direction

  • Version the hash algorithm or introduce chain epochs/checkpoints.
  • Add an explicit, auditable legacy-repair path. Do not silently rewrite audit rows: lock writes per organization, preserve an immutable before-image and checksum, and either rehash canonical persisted JSON with recorded provenance or begin a v2 epoch anchored to that snapshot.
  • Return structured diagnostics such as failureKind, hashVersion or epoch, and checkedThrough from /v1/audit/verify.
  • Label the UI action verify full org chain because filters and the current 100-row page do not scope verification, and link firstBreakSeq to the containing page/event.

Acceptance criteria

  • An upgrade fixture containing a v1 run.finished event with error: undefined is classified deterministically and is not presented as unexplained tampering.
  • New-version events verify from their persisted canonical JSON.
  • Link mismatches and current-version content mismatches remain hard failures.
  • Any repair or epoch transition preserves a checksummed before-image and durable provenance.
  • UI copy makes full-organization scope explicit and can navigate to the reported sequence.

Relevant code:

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with packages/db/src/audit.ts and packages/core/src/audit.ts, then trace the run.finished writer in services/api/src/sandbox/orchestrator.ts and the UI in apps/web/components/audit/audit-explorer.tsx. Reproduce the described v1 fixture and inspect the existing verification flow. Done means legacy drift is classified deterministically, hard failures remain distinct, and any repair or epoch transition records the required before-image and provenance.

Written by the indexing model from the issue text.

Assessment

Tech stack
postgresql, typescript
Domain
backend-api-design, databases, frontend, security
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.