Implements Spec 115 (Baseline Operability & Alert Integration). Key changes - Baseline compare: safe auto-close of stale baseline findings (gated on successful/complete compares) - Baseline alerts: `baseline_high_drift` + `baseline_compare_failed` with dedupe/cooldown semantics - Workspace settings: baseline severity mapping + minimum severity threshold + auto-close toggle - Baseline Compare UX: shared stats layer + landing/widget consistency Notes - Livewire v4 / Filament v5 compatible. - Destructive-like actions require confirmation (no new destructive actions added here). Tests - `vendor/bin/sail artisan test --compact tests/Feature/Baselines/ tests/Feature/Alerts/` Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #140
64 lines
2.8 KiB
Markdown
64 lines
2.8 KiB
Markdown
# Data Model — Baseline Operability & Alert Integration (Spec 115)
|
|
|
|
This spec extends existing models and introduces no new tables.
|
|
|
|
## Entities
|
|
|
|
### 1) Finding (existing: `App\Models\Finding`)
|
|
Baseline compare findings are a subset of drift findings.
|
|
|
|
Key fields used/extended by this feature:
|
|
- `workspace_id` (derived from tenant)
|
|
- `tenant_id`
|
|
- `finding_type` = `drift`
|
|
- `source` = `baseline.compare` (stable contract)
|
|
- `scope_key` = `baseline_profile:{baseline_profile_id}` (stable grouping)
|
|
- `fingerprint` (stable identifier; used for idempotent upsert + alert dedupe)
|
|
- `status` (lifecycle): `new`, `reopened`, other open states, and terminal states
|
|
- `reopened_at`, `resolved_at`, `resolved_reason`
|
|
- `severity` (`low|medium|high|critical`)
|
|
- `evidence_jsonb` (must include at least `change_type`)
|
|
- `current_operation_run_id` (the compare run that most recently observed the finding)
|
|
|
|
Lifecycle rules for baseline compare findings:
|
|
- New fingerprint → create finding with `status=new`.
|
|
- Existing finding in terminal state (at least `resolved`) observed again → set `status=reopened`, `reopened_at=now`, clear resolved fields.
|
|
- Existing open finding observed again → do not override workflow status.
|
|
- Stale open findings (not observed in a fully successful compare) → set `status=resolved`, `resolved_reason=no_longer_drifting`, `resolved_at=now`.
|
|
|
|
### 2) OperationRun (existing: `App\Models\OperationRun`)
|
|
Baseline compare runs are represented as:
|
|
- `type = baseline_compare`
|
|
- `tenant_id` required (tenant-scoped operation)
|
|
- `status/outcome` managed exclusively via `OperationRunService`
|
|
- `summary_counts` used for:
|
|
- completeness: `processed == total`
|
|
- safety: `failed == 0`
|
|
|
|
Baseline capture runs are represented as:
|
|
- `type = baseline_capture`
|
|
|
|
### 3) WorkspaceSetting (existing: `App\Models\WorkspaceSetting`)
|
|
New workspace keys (domain `baseline`):
|
|
- `baseline.severity_mapping` (json object)
|
|
- Keys MUST be exactly: `missing_policy`, `different_version`, `unexpected_policy`
|
|
- Values MUST be one of: `low|medium|high|critical`
|
|
- `baseline.alert_min_severity` (string)
|
|
- Allowed: `low|medium|high|critical`
|
|
- Default: `high`
|
|
- `baseline.auto_close_enabled` (bool)
|
|
- Default: `true`
|
|
|
|
Effective value rules:
|
|
- Consumers read via `SettingsResolver`, which merges system defaults with workspace overrides.
|
|
|
|
## Derived/Computed Values
|
|
- Baseline finding severity is computed at creation time from `baseline.severity_mapping[change_type]`.
|
|
- Baseline alert eligibility is computed at alert-evaluation time from:
|
|
- finding `source` + `status` + timestamps vs `windowStart`
|
|
- finding `severity` vs `baseline.alert_min_severity`
|
|
|
|
## Invariants
|
|
- `Finding.source = baseline.compare` MUST be stable and queryable.
|
|
- Auto-close MUST only execute if the compare run is complete (`processed==total`) and safe (`failed==0`) and `baseline.auto_close_enabled` is true.
|