## Summary - add the Evidence Snapshot domain with immutable tenant-scoped snapshots, per-dimension items, queued generation, audit actions, badge mappings, and Filament list/detail surfaces - add the workspace evidence overview, capability and policy wiring, Livewire update-path hardening, and review-pack integration through explicit evidence snapshot resolution - add spec 153 artifacts, migrations, factories, and focused Pest coverage for evidence, review-pack reuse, authorization, action-surface regressions, and audit behavior ## Testing - `vendor/bin/sail artisan test --compact --stop-on-failure` - `CI=1 vendor/bin/sail artisan test --compact` - `vendor/bin/sail bin pint --dirty --format agent` ## Notes - branch: `153-evidence-domain-foundation` - commit: `b7dfa279` - spec: `specs/153-evidence-domain-foundation/` Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #183
114 lines
3.7 KiB
Markdown
114 lines
3.7 KiB
Markdown
# Data Model: Evidence Domain Foundation
|
|
|
|
## 1. EvidenceSnapshot
|
|
|
|
- **Purpose**: Immutable, tenant-scoped evidence package captured at a specific point in time and reused by downstream consumers.
|
|
- **Ownership**: Tenant-owned (`workspace_id` + `tenant_id` NOT NULL)
|
|
- **Fields**:
|
|
- `id`
|
|
- `workspace_id`
|
|
- `tenant_id`
|
|
- `operation_run_id` nullable
|
|
- `initiated_by_user_id` nullable
|
|
- `fingerprint` nullable, 64-char SHA-256
|
|
- `previous_fingerprint` nullable
|
|
- `status` enum: `queued`, `generating`, `active`, `superseded`, `expired`, `failed`
|
|
- `completeness_state` enum: `complete`, `partial`, `missing`, `stale`
|
|
- `summary` JSONB
|
|
- `generated_at` timestampTz nullable
|
|
- `expires_at` timestampTz nullable
|
|
- `created_at`, `updated_at`
|
|
- **Relationships**:
|
|
- belongs to `Workspace`
|
|
- belongs to `Tenant`
|
|
- belongs to `OperationRun`
|
|
- belongs to initiator `User`
|
|
- has many `EvidenceSnapshotItem`
|
|
- **Validation / invariants**:
|
|
- `workspace_id` and `tenant_id` required on every row
|
|
- successful snapshots are immutable in content after `status` becomes `active`
|
|
- one active snapshot per tenant evidence scope in v1
|
|
- identical fingerprint for the same tenant scope reuses the existing non-expired snapshot
|
|
|
|
## 2. EvidenceSnapshotItem
|
|
|
|
- **Purpose**: One curated evidence dimension inside an evidence snapshot.
|
|
- **Ownership**: Tenant-owned (`workspace_id` + `tenant_id` NOT NULL)
|
|
- **Fields**:
|
|
- `id`
|
|
- `evidence_snapshot_id`
|
|
- `workspace_id`
|
|
- `tenant_id`
|
|
- `dimension_key` string
|
|
- `state` enum: `complete`, `partial`, `missing`, `stale`
|
|
- `required` boolean
|
|
- `source_kind` string
|
|
- `source_record_type` nullable string
|
|
- `source_record_id` nullable string
|
|
- `source_fingerprint` nullable string
|
|
- `measured_at` timestampTz nullable
|
|
- `freshness_at` timestampTz nullable
|
|
- `summary_payload` JSONB
|
|
- `sort_order` integer default 0
|
|
- `created_at`, `updated_at`
|
|
- **Relationships**:
|
|
- belongs to `EvidenceSnapshot`
|
|
- **Validation / invariants**:
|
|
- unique per snapshot: `(evidence_snapshot_id, dimension_key)`
|
|
- `workspace_id`/`tenant_id` must match the parent snapshot
|
|
- `summary_payload` stores curated summary/reference data only; no secrets, tokens, or raw Graph dumps
|
|
|
|
## 3. Evidence dimensions in first rollout
|
|
|
|
- `findings_summary`
|
|
- `permission_posture`
|
|
- `entra_admin_roles`
|
|
- `baseline_drift_posture`
|
|
- `operations_summary`
|
|
|
|
Each dimension stores:
|
|
- inclusion state (`complete|partial|missing|stale`)
|
|
- source provenance (record type, identifier, fingerprint)
|
|
- freshness timestamp
|
|
- dimension-specific summary payload
|
|
|
|
## 4. Derived completeness rules
|
|
|
|
- **Snapshot overall completeness precedence**:
|
|
- `missing` if any required dimension is missing
|
|
- `stale` if no required dimensions are missing and at least one required dimension is stale
|
|
- `partial` if no required dimensions are missing or stale and at least one required dimension is partial
|
|
- `complete` only when all required dimensions are complete
|
|
|
|
## 5. Lifecycle transitions
|
|
|
|
### EvidenceSnapshot status
|
|
|
|
- `queued -> generating`
|
|
- `generating -> active`
|
|
- `generating -> failed`
|
|
- `active -> superseded`
|
|
- `active -> expired`
|
|
- `superseded -> expired`
|
|
|
|
No transition may mutate snapshot items after `active` is reached.
|
|
|
|
## 6. Downstream resolution contract
|
|
|
|
### EvidenceResolutionRequest
|
|
|
|
- **Purpose**: Explicit request from a downstream consumer for a tenant evidence package.
|
|
- **Fields**:
|
|
- `workspace_id`
|
|
- `tenant_id`
|
|
- `snapshot_id` nullable explicit selection
|
|
- `required_dimensions` array
|
|
- `allow_stale` boolean default `false`
|
|
|
|
### EvidenceResolutionResult
|
|
|
|
- **Outcomes**:
|
|
- `resolved` with snapshot id and eligible dimensions
|
|
- `missing_snapshot`
|
|
- `snapshot_ineligible` with missing/stale dimension reasons
|