Files
git.stella-ops.org/docs/modules/ui/components/witness-visualization.md

353 lines
9.6 KiB
Markdown

# Witness Visualization Components
> **Sprint:** SPRINT_20260118_020_FE_witness_visualization
The witness visualization component suite provides UI for displaying runtime witness data, comparing static analysis paths with runtime observations, and managing witness gate results in release promotion flows.
## Overview
Runtime witnesses confirm that static analysis reachability paths are actually exercised during application execution. These components visualize:
- **Witness Status**: Whether a path has been witnessed at runtime
- **Static vs Runtime Comparison**: Side-by-side or overlay views comparing predicted and observed paths
- **Gate Results**: Witness gate outcomes for release promotion decisions
- **Unwitnessed Advisories**: Paths requiring runtime exercise before promotion
## Components
### Core Components
| Component | Purpose | Location |
|-----------|---------|----------|
| `WitnessStatusChipComponent` | Status badge showing witness state | `shared/domain/witness-status-chip/` |
| `WitnessComparisonComponent` | Static vs runtime path comparison | `shared/components/witness-comparison/` |
| `UnwitnessedAdvisoryComponent` | Advisory panel for unwitnessed paths | `shared/components/unwitnessed-advisory/` |
| `GateSummaryPanelComponent` | Gate results with witness metrics | `shared/domain/gate-summary-panel/` |
### Witness Status Chip
Displays the witness status of a reachability path with color-coded badges.
```typescript
import { WitnessStatusChipComponent, WitnessStatus } from '@app/shared/domain/witness-status-chip';
```
#### States
| State | Color | Icon | Description |
|-------|-------|------|-------------|
| `witnessed` | Green | ✓ | Path confirmed by runtime observation |
| `unwitnessed` | Yellow | ○ | Path not yet observed at runtime |
| `stale` | Orange | ⏱ | Witness data is outdated |
| `failed` | Red | ✗ | Witness verification failed |
#### Usage
```html
<!-- Basic usage -->
<app-witness-status-chip [status]="'witnessed'" />
<!-- With details for tooltip -->
<app-witness-status-chip
[status]="'witnessed'"
[details]="{
status: 'witnessed',
lastObserved: '2026-01-15T10:30:00Z',
observationCount: 42,
rekorLogIndex: 12345
}"
[showCount]="true"
(chipClick)="onChipClick()"
/>
```
#### Input Properties
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| `status` | `WitnessStatus` | required | Witness status to display |
| `details` | `WitnessStatusDetails` | `null` | Optional metadata for tooltip |
| `showCount` | `boolean` | `true` | Whether to show observation count |
---
### Witness Comparison Component
Side-by-side or overlay view comparing static analysis paths with runtime observations. The main visualization for understanding witness coverage.
```typescript
import {
WitnessComparisonComponent,
WitnessComparisonData,
ComparisonPathStep,
ComparisonMetrics,
} from '@app/shared/components/witness-comparison';
```
#### Features
- **View Modes**: List view (vertical) or overlay view (side-by-side columns)
- **Color Coding**: Green (confirmed), yellow (static only), orange (runtime only/unexpected)
- **Filtering**: Filter by confirmation status
- **Metrics Summary**: Totals and confirmation rate display
- **Step Drill-down**: Click steps for detailed information
#### Usage
```html
<app-witness-comparison
[data]="comparisonData"
(stepClick)="onStepClick($event)"
(refresh)="onRefresh()"
/>
```
#### Input Properties
| Property | Type | Description |
|----------|------|-------------|
| `data` | `WitnessComparisonData` | Comparison data with paths and metrics |
#### Output Events
| Event | Type | Description |
|-------|------|-------------|
| `stepClick` | `ComparisonPathStep` | Emitted when user clicks a step |
| `refresh` | `void` | Emitted when user requests data refresh |
#### Data Models
```typescript
interface ComparisonPathStep {
nodeId: string;
symbol: string;
file?: string;
line?: number;
package?: string;
inStatic: boolean; // Found in static analysis
inRuntime: boolean; // Observed at runtime
runtimeInvocations?: number;
lastObserved?: string;
}
interface ComparisonMetrics {
totalSteps: number;
confirmedSteps: number; // Both static and runtime
staticOnlySteps: number; // Static only (unwitnessed)
runtimeOnlySteps: number; // Runtime only (unexpected)
confirmationRate: number; // Percentage confirmed
}
interface WitnessComparisonData {
claimId: string;
cveId?: string;
packageName: string;
packageVersion?: string;
pathSteps: ComparisonPathStep[];
metrics: ComparisonMetrics;
generatedAt: string;
}
```
---
### Unwitnessed Advisory Component
Advisory panel displayed when release promotion encounters paths without runtime witnesses. Used in the gate flow to inform operators about witness coverage gaps.
```typescript
import {
UnwitnessedAdvisoryComponent,
UnwitnessedAdvisoryData,
UnwitnessedPath,
} from '@app/shared/components/unwitnessed-advisory';
```
#### Features
- **Severity Summary**: Visual breakdown by vulnerability severity
- **Path List**: Sortable list of unwitnessed paths
- **Blocking/Advisory Mode**: Different styling based on gate configuration
- **Action Buttons**: Create test tasks for individual paths or all at once
#### Usage
```html
<app-unwitnessed-advisory
[data]="advisoryData"
(createTestTask)="onCreateTestTask($event)"
(createAllTestTasks)="onCreateAllTestTasks()"
(viewComparison)="onViewComparison()"
/>
```
#### Input Properties
| Property | Type | Description |
|----------|------|-------------|
| `data` | `UnwitnessedAdvisoryData` | Advisory data with paths and configuration |
#### Output Events
| Event | Type | Description |
|-------|------|-------------|
| `createTestTask` | `UnwitnessedPath` | Create test task for specific path |
| `createAllTestTasks` | `void` | Create test tasks for all paths |
| `viewComparison` | `void` | Open full comparison view |
#### Data Models
```typescript
interface UnwitnessedPath {
pathId: string;
cveId?: string;
vulnId: string;
packageName: string;
packageVersion?: string;
entrypoint: string;
sink: string;
severity: 'critical' | 'high' | 'medium' | 'low' | 'unknown';
confidence: number;
lastAnalyzed?: string;
}
interface UnwitnessedAdvisoryData {
totalUnwitnessed: number;
paths: UnwitnessedPath[];
targetEnvironment?: string;
isBlocking: boolean;
}
```
---
### Gate Summary Panel (Extended)
Extended to support witness gate display with metrics, expandable details, and comparison links.
```typescript
import {
GateSummaryPanelComponent,
GateResult,
WitnessGateMetrics,
WitnessPathSummary,
} from '@app/shared/domain/gate-summary-panel';
```
#### Witness Gate Support
The `GateResult` interface now supports witness-specific properties:
```typescript
interface GateResult {
id: string;
name: string;
state: 'PASS' | 'WARN' | 'BLOCK' | 'SKIP';
reason?: string;
ruleHits?: number;
gateType?: 'standard' | 'witness' | 'cve' | 'sbom';
witnessMetrics?: WitnessGateMetrics;
}
interface WitnessGateMetrics {
totalPaths: number;
witnessedPaths: number;
unwitnessedPaths: number;
stalePaths?: number;
unwitnessedPathDetails?: WitnessPathSummary[];
}
interface WitnessPathSummary {
pathId: string;
entrypoint: string;
sink: string;
severity?: 'critical' | 'high' | 'medium' | 'low' | 'unknown';
vulnId?: string;
}
```
#### Usage
```html
<app-gate-summary-panel
[gates]="gates"
[policyRef]="policyReference"
[snapshotRef]="snapshotReference"
(openExplain)="onOpenExplain($event)"
(openEvidence)="onOpenEvidence()"
(openComparison)="onOpenComparison($event)"
/>
```
#### Witness Gate Features
- **Metrics Display**: Shows X/Y witnessed paths, unwitnessed count, stale count
- **Advisory Styling**: Yellow border and background for WARN state witness gates
- **Expandable Details**: Click "Details" to see unwitnessed path list
- **Compare Button**: Opens full comparison view
---
## Color Coding Reference
### Comparison States
| State | Color | CSS Variable | Meaning |
|-------|-------|--------------|---------|
| Confirmed | Green | `--green-500` | Path in both static and runtime |
| Static Only | Yellow | `--yellow-500` | Path predicted but not observed |
| Runtime Only | Orange | `--orange-500` | Unexpected path observed |
### Severity Colors
| Severity | Color | CSS Variable |
|----------|-------|--------------|
| Critical | Red | `--red-500` |
| High | Orange | `--orange-500` |
| Medium | Yellow | `--yellow-500` |
| Low | Blue | `--blue-500` |
| Unknown | Gray | `--gray-400` |
---
## Integration with Existing Components
The witness visualization components integrate with several existing UI elements:
| Existing Component | Integration |
|--------------------|-------------|
| `WitnessDrawerComponent` | Can embed comparison view |
| `WitnessPageComponent` | Full reachability analysis page |
| `TimelineListComponent` | Display witness observation timeline |
| `GateExplainDrawerComponent` | Show witness gate explanation |
---
## Accessibility
All witness visualization components follow WCAG 2.1 AA guidelines:
- ARIA labels for all interactive elements
- Keyboard navigation support
- Focus management for expandable sections
- Color + icon combinations (not color alone)
- Screen reader announcements for status changes
---
## Testing
Unit tests are located alongside components:
- `witness-status-chip.component.spec.ts`
- `witness-comparison.component.spec.ts`
- `unwitnessed-advisory.component.spec.ts`
- `gate-summary-panel.component.spec.ts`
Run tests:
```bash
cd src/Web/StellaOps.Web
npm test -- --include="**/*witness*" --include="**/*gate-summary*"
```