Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
- Created CycloneDX and SPDX SBOM files for both reachable and unreachable images. - Added symbols.json detailing function entry and sink points in the WordPress code. - Included runtime traces for function calls in both reachable and unreachable scenarios. - Developed OpenVEX files indicating vulnerability status and justification for both cases. - Updated README for evaluator harness to guide integration with scanner output.
31 lines
3.1 KiB
Markdown
31 lines
3.1 KiB
Markdown
# Findings Ledger — Workflow Inference Notes
|
||
|
||
> **Audience:** Findings Ledger Guild, Vuln Explorer API, Console Guild
|
||
> **Scope:** How workflow mutations (assign/comment/accept-risk/etc.) derive canonical ledger inputs when the caller omits low-level fields.
|
||
|
||
## 1. Chain + sequencing
|
||
- **Chain derivation.** When a request does not provide `chainId`, we deterministically derive it from `tenantId :: policyVersion` (`Guid` from SHA-256 first 16 bytes). This keeps per-policy ordering stable and avoids callers leaking raw GUID logic.
|
||
- **Sequence number.** We fetch the current chain head and expect `head.sequence + 1`. If the chain has no entries, the expected sequence is `1`. The append path still enforces optimistic concurrency and rejects mismatches.
|
||
- **Previous hash.** We reuse the head’s `event_hash` (defaulting to the all-zero hash for genesis events) so writers don’t need to manage hash pointers.
|
||
|
||
## 2. Event identifiers + timestamps
|
||
- **Event IDs.** If the caller omits `eventId`, we mint a V7 GUID to keep chronological ordering while remaining globally unique.
|
||
- **Occurred / recorded timestamps.** `occurredAt` defaults to “now” in UTC (based on `TimeProvider`). `recordedAt` always comes from the service’s `TimeProvider` to avoid caller-provided drift.
|
||
|
||
## 3. Status & severity fallbacks
|
||
- The reducer already maps event types to canonical statuses. Workflow service only writes `status` when the mutation explicitly changes it (e.g., `accept-risk` → `accepted_risk`, `target-fix` → `in_progress`, `verify-fix` → `verified`, `reopen` → `affected`). Otherwise we leave status null and let the reducer infer it.
|
||
- Severity is never inferred inside workflow handlers—they rely on policy evaluation or reducer logic.
|
||
|
||
## 4. Attachments metadata
|
||
- Attachments now include security context: every entry captures an AES-256-GCM envelope (`algorithm`, `ciphertext`, `nonce`, `tag`, `expiresAt`) derived from `attachments.encryptionKey`.
|
||
- Signed URLs are generated with HMAC-SHA256 using `attachments.signedUrlSecret` and inherit `attachments.signedUrlLifetime` (default 15 minutes). URLs plus envelopes share the same expiry window.
|
||
- Metadata is normalized (trimmed keys, deterministic ordering) before encryption so ledger hashes remain stable; duplicate IDs are deduplicated.
|
||
- Actual binary blobs stay in Evidence Locker/S3; the envelope is what downstream services use to decrypt the blob once downloaded.
|
||
|
||
## 5. Validation surface
|
||
- All handlers enforce tenant/policy/finding/artifact/vuln IDs, actor identity, and supported actor types.
|
||
- Mutation-specific requirements (e.g., assignment requires assignee, accept-risk needs justification) are validated before any ledger append occurs.
|
||
- Attachments are validated for ID/file name/MIME type/positive size and 64-char SHA-256 digests before encryption, preventing malformed payloads from burning hashes or emitting invalid URLs.
|
||
|
||
These rules let upstream APIs/clients send high-level workflow intents without micromanaging ledger sequencing or hashing, while preserving deterministic ledger entries. LEDGER-29-005 implements the service described here; LEDGER-29-006 builds on it for secure attachment handling.
|