bae705aa97
- 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
207 lines
9.3 KiB
Markdown
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
|
|
|