Files
boc/memory/audit-s1-s3.md
T
Bernt bae705aa97 ARCHITECTURE: NFC roadmap, edge AI, audit logging
- Add NFC ePassport roadmap (ICAO 9303, eIDAS)
- Add TensorFlow.js edge face detection (BlazeFace)
- Add structured audit logger (GDPR-compliant)
- Risk scoring support

Part of KYC Apple Native UX v1.1.0
2026-06-29 16:24:48 +00:00

207 lines
9.3 KiB
Markdown

# EXTREME CERTIFICATION AUDIT — SECTIONS 1-3
**Date:** 2026-06-05T15:47 UTC
**Auditor:** TÜV Lead Auditor / Chaos Engineer (subagent)
**Baseline:** GECL chain v0.3.0 (localhost:3263), Audit Engine (localhost:3251), Ledger (localhost:3250)
---
## SECTION 1: EVENT COMPLETENESS PROOF
### [S1.1] GECL Schema Discovery
**STATUS: PROVEN**
**EVIDENCE:**
```
GECL service: amos-gecl-chain v0.3.0 (PID 2609293)
DATABASE: wavult_identity (NOT amos)
Actual routes: /health, /append, /chain, /status, /verify, /block/:hash, /certify,
/streams/:id, /audit/events, /audit/events/batch, /audit/trail/:entity_id,
/audit/trace/:trace_id, /audit/summary
Tables (wavult_identity): audit_events (id, tenant_id, trace_id, correlation_id, user_id,
service, entity_type, entity_id, action, decision_source, before_state, after_state,
metadata, ip_address, session_id, ts)
Initial state: total_blocks=0, chain_hash=000...000 (pristine)
```
**FINDING:** GECL has two distinct subsystems: (1) in-memory hash chain (/append, /chain, /status) and (2) SQL audit event store (/audit/events → wavult_identity.audit_events). These are DECOUPLED — audit events written via /audit/events do NOT auto-create chain blocks.
---
### [S1.2] CRUD Operations Audit Trail — CREATE + POST
**STATUS: PARTIAL**
#### Test Entry
```
entry_id: 712f74f4-1a0c-4391-9f21-635fc7bacbbb
trace_id: 9416a41a-fe32-4491-a855-858b431f3f9a
status: draft → posted
period: 2026-07 (opened manually for test; all prod periods closed)
```
#### Audit Trail Link-by-Link
| Layer | Status | Evidence |
|-------|--------|----------|
| **DB (amos.ledger_journal_entries)** | ✅ PROVEN | Row exists: `status=posted, created_at=15:44:00, posted_at=15:44:05` |
| **DB (amos.ledger_audit_log)** | ✅ PROVEN | 2 rows: `[created] trace=9416a41a ts=15:44:00` + `[posted] trace=8dbef483 ts=15:44:05` |
| **Hermes JSONL (/opt/amos/data/hermes/events.jsonl)** | ✅ PROVEN | `finance.journal.created` (trace=9416a41a, ts=15:44:00.360) + `finance.journal.posted` (trace=8dbef483, ts=15:44:05.146) |
| **NATS publish** | ❌ FAILED | Redis DOWN → Hermes falls back to JSONL only. No NATS/JetStream publish. AAMOS_AUDIT stream: 0 msgs |
| **GECL audit_events (wavult_identity)** | ❌ FAILED | `audit/trail/712f74f4?tenant_id=wavult-group` → count=0. Ledger publishes to hermes JSONL but NOT to GECL audit API |
| **GECL chain blocks** | ❌ FAILED | total_blocks=0. No auto-integration between ledger ops and GECL chain append |
| **Audit Engine 3251 trail** | ❌ FAILED | Same wavult_identity.audit_events — also returns count=0 for entity_id |
**FINDING:**
- Ledger creates complete audit trail in its own DB (amos.ledger_audit_log) ✅
- Hermes event fabric fires events to JSONL fallback (Redis DOWN) ✅
- Cross-system propagation to GECL is BROKEN: no consumer bridges hermes JSONL/Redis → GECL audit_events
- GECL chain (in-memory hash blocks) has 0 blocks — never fed by ledger operations
- **Critical Gap:** Two separate audit stores (amos.ledger_audit_log vs wavult_identity.audit_events) with no bridge
**NOTE on trace_id mismatch:** `ledger_audit_log` shows different trace_ids for `created` vs `posted` operations on the same entry (9416... vs 8dbef4...). Correlation_id is also different. This means created and posted events are NOT linked by a shared trace chain.
---
### [S1.3] Rollback Test
**STATUS: FAILED**
**EVIDENCE:**
```
POST /api/ledger/journal/:id/rollback → 404 Cannot POST
POST /api/ledger/journal/:id/void → 404 Cannot POST
```
**FINDING:** No rollback or void endpoint exists in the ledger API (aamos-ledger). Only `/api/ledger/journal/:id/post` is implemented. Rollback/void operations are architecturally missing — there is no reversal mechanism, and therefore no audit trail for reversals.
---
## SECTION 2: EVENT STORM TEST (10,000 events)
### [S2.1] Storm Execution
**STATUS: PROVEN**
**EVIDENCE:**
```
Tag: STORM-1780674412596
Target: GECL /audit/events (direct)
Batch size: 100 concurrent
Total sent: 10,000
Success: 10,000 (100%)
Failures: 0
Total time: 22,426ms
Throughput: 446 events/sec
```
### [S2.2] Ordering Verification
**STATUS: PROVEN**
**EVIDENCE:**
```sql
SELECT ts FROM audit_events WHERE service='storm-test' AND metadata->>'tag'=$1 ORDER BY ts ASC
10,000 rows returned
Monotone increasing: TRUE (0 out-of-order pairs detected)
```
### [S2.3] Idempotency / Duplicate Detection
**STATUS: PROVEN**
**EVIDENCE:**
```sql
SELECT entity_id, COUNT(*) FROM audit_events WHERE service='storm-test'
GROUP BY entity_id HAVING COUNT(*)>1
Duplicate entity_ids: 0
```
### [S2.4] GECL Chain Integrity After Storm
**STATUS: FAILED**
**EVIDENCE:**
```
POST /audit/events → writes to audit_events table (SQL) only
GECL chain blocks after storm: total_blocks=0 (chain NOT fed by audit/events)
/verify → ok=true, valid=true, errors=[] (trivially valid — empty chain)
```
**FINDING:** The GECL cryptographic hash chain remains empty (0 blocks) despite 10,000 audit events being written. The SQL audit store and the in-memory chain are not connected. Chain integrity is vacuously valid (empty). The `total_blocks=0` is a structural concern — the chain provides no tamper-evidence for any audit events.
**Rate limiting:** GECL audit engine (3251) implements per-tenant rate limiting. For storm at 10k events, batch API (`/audit/events/batch`) was used successfully without rate-limit rejection.
---
## SECTION 3: LINEAGE INTEGRITY TEST
### [S3.1] Event Population
**STATUS: PARTIAL**
**EVIDENCE:**
```
audit_events (wavult_identity, non-storm): 4 events
ledger_audit_log (amos): 46 events
hermes JSONL: multiple event types, ~25+ records
```
**FINDING:** Only 4 non-storm events in GECL audit_events table (used for lineage tracking). Ledger's audit log has 46. The two stores are isolated.
### [S3.2] Lineage Field Completeness (100 random events)
**STATUS: PROVEN (within each store)**
**EVIDENCE:**
```
GECL audit_events (4 non-storm events):
Complete (trace_id + correlation_id + entity_id + decision_source): 4/4 (100%)
Broken: 0
ledger_audit_log (46 events):
Complete: 46/46 (100%)
Broken: 0
Schema includes: id, tenant_id, trace_id, correlation_id, user_id, service, entity_type,
entity_id, action, decision_source, before_state, after_state, metadata, ip_address, session_id, ts
```
### [S3.3] Cross-System Lineage Chain (event→parent→originator→decision→action)
**STATUS: FAILED**
**EVIDENCE:**
```
Entry 712f74f4:
amos.ledger_journal_entries → has trace_id ✅
amos.ledger_audit_log → 2 entries (created, posted) ✅ but different trace_ids ⚠️
hermes events.jsonl → 2 events matching same entity_id ✅ but trace_ids differ from audit_log posted event
wavult_identity.audit_events → 0 entries ❌
GECL chain blocks → 0 ❌
Multi-event trace groups (same trace_id across multiple events): 0 (no cross-event traces)
```
**FINDING:** Full lineage chain (event→parent→originator→decision→action) is BROKEN across system boundaries:
1. `created` and `posted` actions on the same entry have DIFFERENT trace_ids (no shared trace)
2. Hermes JSONL events are not forwarded to GECL
3. GECL audit_events has 0 entries for any ledger operation
4. No parent_id field exists — there is no explicit parent-child relationship
5. Cross-system replay via GECL `/audit/trace/:trace_id` or `/audit/trail/:entity_id` returns empty results for all ledger entities
---
## SECTION 1-3 SUMMARY SCORECARD
| Check | Status | Score |
|-------|--------|-------|
| S1.1 GECL schema discovery | PROVEN | ✅ |
| S1.2a DB write (ledger_journal_entries) | PROVEN | ✅ |
| S1.2b DB audit log (ledger_audit_log) | PROVEN | ✅ |
| S1.2c Hermes event emission | PROVEN | ✅ (JSONL fallback) |
| S1.2d NATS publish | FAILED | ❌ (Redis DOWN, no NATS publish) |
| S1.2e GECL audit trail cross-DB | FAILED | ❌ (no bridge amos→wavult_identity) |
| S1.2f GECL chain blocks | FAILED | ❌ (0 blocks, not auto-fed) |
| S1.2g Audit engine 3251 visibility | FAILED | ❌ (same gap) |
| S1.3 Rollback endpoint | FAILED | ❌ (does not exist) |
| S2.1 Storm 10k throughput | PROVEN | ✅ (10000/10000, 446 ev/s) |
| S2.2 Monotone ordering | PROVEN | ✅ |
| S2.3 Zero duplicates | PROVEN | ✅ |
| S2.4 Chain integrity | FAILED | ❌ (vacuously valid, 0 blocks) |
| S3.1 Event population | PARTIAL | ⚠️ (isolated stores) |
| S3.2 Field completeness (per-store) | PROVEN | ✅ (100% within stores) |
| S3.3 Cross-system lineage chain | FAILED | ❌ (broken at every boundary) |
### Section Scores
| Section | Score | Verdict |
|---------|-------|---------|
| **Section 1: Event Completeness** | 3/8 checks PROVEN | **PARTIAL** |
| **Section 2: Event Storm** | 3/4 checks PROVEN | **PARTIAL** |
| **Section 3: Lineage Integrity** | 1/3 checks PROVEN | **PARTIAL** |
### Critical Findings
1. **GECL chain is empty (0 blocks)** — no tamper-evident ledger chain despite service running
2. **No cross-DB bridge** — ledger audit (amos) never reaches GECL audit store (wavult_identity)
3. **Redis DOWN** — Hermes event bus degraded to JSONL-only; no real-time NATS propagation
4. **Trace fragmentation** — created/posted on same entity have different trace_ids, preventing full trace reconstruction
5. **No rollback/void** — no API surface for reversals; irreversible financial records
6. **GECL chain decoupled from audit_events** — the SQL audit store and hash chain are architecturally disconnected