save development progress
This commit is contained in:
461
docs/modules/ui/provcache-components.md
Normal file
461
docs/modules/ui/provcache-components.md
Normal file
@@ -0,0 +1,461 @@
|
||||
# Provcache UI Components
|
||||
|
||||
This document describes the Angular components for visualizing provenance cache data, trust scores, and proof trees in the StellaOps Console.
|
||||
|
||||
## Overview
|
||||
|
||||
The Provcache UI components provide visual feedback for:
|
||||
|
||||
- **Cache state awareness** — Users see whether decisions come from cache (fast) or are freshly computed
|
||||
- **Trust transparency** — Trust scores with breakdowns by evidence component
|
||||
- **Proof visualization** — Interactive proof trees showing evidence chain
|
||||
- **Input manifest** — Details of all inputs that form a cached decision
|
||||
|
||||
## Components
|
||||
|
||||
### ProvenanceBadgeComponent
|
||||
|
||||
**Selector:** `stellaops-provenance-badge`
|
||||
|
||||
Displays a compact badge indicating the provenance state of a decision.
|
||||
|
||||
#### Inputs
|
||||
|
||||
| Input | Type | Default | Description |
|
||||
|-------|------|---------|-------------|
|
||||
| `state` | `'cached' \| 'computed' \| 'stale' \| 'unknown'` | `'unknown'` | Current provenance state |
|
||||
| `cacheDetails` | `CacheDetails \| null` | `null` | Optional cache metadata |
|
||||
| `trustScore` | `number \| null` | `null` | Optional trust score (0-100) |
|
||||
| `size` | `'small' \| 'medium' \| 'large'` | `'medium'` | Badge size variant |
|
||||
|
||||
#### Outputs
|
||||
|
||||
| Output | Type | Description |
|
||||
|--------|------|-------------|
|
||||
| `viewProofTree` | `EventEmitter<void>` | Emitted when user clicks to view proof |
|
||||
|
||||
#### States & Icons
|
||||
|
||||
| State | Icon | Tooltip | CSS Class |
|
||||
|-------|------|---------|-----------|
|
||||
| `cached` | ⚡ | "Provenance-cached" | `badge--cached` |
|
||||
| `computed` | 🔄 | "Freshly computed" | `badge--computed` |
|
||||
| `stale` | ⏳ | "Stale - recomputing" | `badge--stale` |
|
||||
| `unknown` | ❓ | "Unknown provenance" | `badge--unknown` |
|
||||
|
||||
#### Usage
|
||||
|
||||
```html
|
||||
<!-- Basic usage -->
|
||||
<stellaops-provenance-badge [state]="'cached'"></stellaops-provenance-badge>
|
||||
|
||||
<!-- With cache details -->
|
||||
<stellaops-provenance-badge
|
||||
[state]="'cached'"
|
||||
[cacheDetails]="{ source: 'valkey', ageSeconds: 45, veriKey: 'sha256:abc...' }"
|
||||
[trustScore]="85"
|
||||
(viewProofTree)="openProofTree()">
|
||||
</stellaops-provenance-badge>
|
||||
```
|
||||
|
||||
#### Accessibility
|
||||
|
||||
- Uses `role="status"` for screen reader announcements
|
||||
- Tooltip content exposed via `aria-label`
|
||||
- Color is not the sole indicator — icons and text labels provided
|
||||
|
||||
---
|
||||
|
||||
### TrustScoreDisplayComponent
|
||||
|
||||
**Selector:** `stellaops-trust-score-display`
|
||||
|
||||
Visualizes a trust score (0-100) with optional breakdown by evidence component.
|
||||
|
||||
#### Inputs
|
||||
|
||||
| Input | Type | Default | Description |
|
||||
|-------|------|---------|-------------|
|
||||
| `score` | `number` | `0` | Overall trust score (0-100) |
|
||||
| `breakdown` | `TrustScoreBreakdown \| null` | `null` | Component-level scores |
|
||||
| `mode` | `'donut' \| 'badge' \| 'inline'` | `'donut'` | Display mode |
|
||||
| `showBreakdown` | `boolean` | `false` | Show breakdown tooltip |
|
||||
| `compact` | `boolean` | `false` | Use compact sizing |
|
||||
| `thresholds` | `{ high: number; medium: number }` | `{ high: 80, medium: 50 }` | Color thresholds |
|
||||
|
||||
#### TrustScoreBreakdown Interface
|
||||
|
||||
```typescript
|
||||
interface TrustScoreBreakdown {
|
||||
reachability: number; // 0.0-1.0 (25% weight)
|
||||
sbomCompleteness: number; // 0.0-1.0 (20% weight)
|
||||
vexCoverage: number; // 0.0-1.0 (20% weight)
|
||||
policyFreshness: number; // 0.0-1.0 (15% weight)
|
||||
signerTrust: number; // 0.0-1.0 (20% weight)
|
||||
}
|
||||
```
|
||||
|
||||
#### Display Modes
|
||||
|
||||
| Mode | Description |
|
||||
|------|-------------|
|
||||
| `donut` | Circular SVG chart with score in center |
|
||||
| `badge` | Compact pill-shaped badge |
|
||||
| `inline` | Text-only display for tight spaces |
|
||||
|
||||
#### Color Coding
|
||||
|
||||
| Score Range | Class | Color |
|
||||
|-------------|-------|-------|
|
||||
| ≥ high (80) | `score--high` | Green (#4caf50) |
|
||||
| ≥ medium (50) | `score--medium` | Yellow (#ff9800) |
|
||||
| < medium | `score--low` | Red (#f44336) |
|
||||
|
||||
#### Usage
|
||||
|
||||
```html
|
||||
<!-- Donut chart with breakdown -->
|
||||
<stellaops-trust-score-display
|
||||
[score]="85"
|
||||
[breakdown]="breakdown"
|
||||
[mode]="'donut'"
|
||||
[showBreakdown]="true">
|
||||
</stellaops-trust-score-display>
|
||||
|
||||
<!-- Compact badge -->
|
||||
<stellaops-trust-score-display
|
||||
[score]="72"
|
||||
[mode]="'badge'"
|
||||
[compact]="true">
|
||||
</stellaops-trust-score-display>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### ProofTreeComponent
|
||||
|
||||
**Selector:** `stellaops-proof-tree`
|
||||
|
||||
Renders a decision's proof chain as a collapsible tree with verification capabilities.
|
||||
|
||||
#### Inputs
|
||||
|
||||
| Input | Type | Default | Description |
|
||||
|-------|------|---------|-------------|
|
||||
| `digest` | `DecisionDigest \| null` | `null` | The decision digest to display |
|
||||
| `merkleTree` | `MerkleTree \| null` | `null` | Optional Merkle tree structure |
|
||||
| `verdicts` | `VerdictEntry[]` | `[]` | Vulnerability verdicts |
|
||||
| `evidenceChunks` | `EvidenceChunk[]` | `[]` | Evidence artifacts |
|
||||
| `isVerifying` | `boolean` | `false` | Show verification spinner |
|
||||
|
||||
#### Outputs
|
||||
|
||||
| Output | Type | Description |
|
||||
|--------|------|-------------|
|
||||
| `copyVeriKey` | `EventEmitter<string>` | VeriKey copied to clipboard |
|
||||
| `copyHash` | `EventEmitter<string>` | Any hash copied |
|
||||
| `verify` | `EventEmitter<void>` | Verify button clicked |
|
||||
| `downloadEvidence` | `EventEmitter<EvidenceChunk>` | Evidence download requested |
|
||||
|
||||
#### Tree Structure
|
||||
|
||||
```
|
||||
DecisionDigest
|
||||
├── VeriKey: sha256:abc123...
|
||||
├── Trust Score: 85
|
||||
│ ├── Reachability: 95%
|
||||
│ ├── SBOM Completeness: 85%
|
||||
│ ├── VEX Coverage: 90%
|
||||
│ ├── Policy Freshness: 88%
|
||||
│ └── Signer Trust: 92%
|
||||
├── Verdicts (12)
|
||||
│ ├── CVE-2025-1234 → not_affected
|
||||
│ ├── CVE-2025-5678 → fixed
|
||||
│ └── ...
|
||||
├── Merkle Tree
|
||||
│ ├── Root: sha256:root...
|
||||
│ ├── Left
|
||||
│ │ ├── sha256:sbom... (sbom-hash)
|
||||
│ │ └── sha256:vex... (vex-set-hash)
|
||||
│ └── Right
|
||||
│ ├── sha256:policy... (policy-hash)
|
||||
│ └── sha256:signers... (signers-hash)
|
||||
└── Evidence Chunks (5)
|
||||
├── [sbom] SPDX 2.3 SBOM document
|
||||
├── [vex] VEX statement bundle
|
||||
└── ...
|
||||
```
|
||||
|
||||
#### Verdict Statuses
|
||||
|
||||
| Status | Color | Meaning |
|
||||
|--------|-------|---------|
|
||||
| `not_affected` | Green | Vulnerability not applicable |
|
||||
| `fixed` | Blue | Patched/remediated |
|
||||
| `affected` | Red | Vulnerable |
|
||||
| `under_investigation` | Yellow | Pending analysis |
|
||||
| `mitigated` | Cyan | Mitigating controls in place |
|
||||
|
||||
#### Usage
|
||||
|
||||
```html
|
||||
<stellaops-proof-tree
|
||||
[digest]="decisionDigest"
|
||||
[merkleTree]="merkleTree"
|
||||
[verdicts]="verdicts"
|
||||
[evidenceChunks]="chunks"
|
||||
[isVerifying]="verifying"
|
||||
(verify)="verifyProof()"
|
||||
(copyVeriKey)="copyToClipboard($event)"
|
||||
(downloadEvidence)="downloadChunk($event)">
|
||||
</stellaops-proof-tree>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### InputManifestComponent
|
||||
|
||||
**Selector:** `stellaops-input-manifest`
|
||||
|
||||
Displays the exact inputs that formed a VeriKey and cached decision.
|
||||
|
||||
#### Inputs
|
||||
|
||||
| Input | Type | Default | Description |
|
||||
|-------|------|---------|-------------|
|
||||
| `manifest` | `InputManifest \| null` | `null` | The manifest to display |
|
||||
| `mode` | `'full' \| 'compact' \| 'summary'` | `'full'` | Display mode |
|
||||
| `displayConfig` | `InputManifestDisplayConfig` | (all true) | Section visibility |
|
||||
|
||||
#### Outputs
|
||||
|
||||
| Output | Type | Description |
|
||||
|--------|------|-------------|
|
||||
| `copyVeriKey` | `EventEmitter<string>` | VeriKey copied |
|
||||
| `refresh` | `EventEmitter<void>` | Refresh requested |
|
||||
|
||||
#### InputManifest Interface
|
||||
|
||||
```typescript
|
||||
interface InputManifest {
|
||||
veriKey: string;
|
||||
sourceArtifact: SourceArtifactInfo;
|
||||
sbom: SbomInfo;
|
||||
vex: VexInfo;
|
||||
policy: PolicyInfoManifest;
|
||||
signers: SignerInfo;
|
||||
timeWindow: TimeWindowInfo;
|
||||
generatedAt: string;
|
||||
}
|
||||
|
||||
interface SourceArtifactInfo {
|
||||
digest: string;
|
||||
artifactType: string;
|
||||
ociReference?: string;
|
||||
sizeBytes?: number;
|
||||
}
|
||||
|
||||
interface SbomInfo {
|
||||
hash: string;
|
||||
format: string; // 'spdx-2.3', 'cyclonedx-1.6'
|
||||
packageCount: number;
|
||||
completenessScore: number;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
interface VexInfo {
|
||||
hashSetHash: string;
|
||||
statementCount: number;
|
||||
sources: string[];
|
||||
latestStatementAt: string;
|
||||
}
|
||||
|
||||
interface PolicyInfoManifest {
|
||||
hash: string;
|
||||
packId: string;
|
||||
version: number;
|
||||
lastUpdatedAt: string;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
interface SignerInfo {
|
||||
setHash: string;
|
||||
signerCount: number;
|
||||
certificates?: CertificateInfo[];
|
||||
}
|
||||
|
||||
interface CertificateInfo {
|
||||
subject: string;
|
||||
issuer: string;
|
||||
fingerprint: string;
|
||||
expiresAt: string;
|
||||
trustLevel: 'fulcio' | 'enterprise-ca' | 'self-signed';
|
||||
}
|
||||
|
||||
interface TimeWindowInfo {
|
||||
bucket: string;
|
||||
startsAt: string;
|
||||
endsAt: string;
|
||||
}
|
||||
```
|
||||
|
||||
#### Display Modes
|
||||
|
||||
| Mode | Description |
|
||||
|------|-------------|
|
||||
| `full` | All sections with full details |
|
||||
| `compact` | Reduced spacing, abbreviated values |
|
||||
| `summary` | Grid layout for quick overview |
|
||||
|
||||
#### Section Visibility
|
||||
|
||||
```typescript
|
||||
interface InputManifestDisplayConfig {
|
||||
showSource: boolean;
|
||||
showSbom: boolean;
|
||||
showVex: boolean;
|
||||
showPolicy: boolean;
|
||||
showSigners: boolean;
|
||||
showTimeWindow: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
#### Usage
|
||||
|
||||
```html
|
||||
<!-- Full manifest display -->
|
||||
<stellaops-input-manifest
|
||||
[manifest]="inputManifest"
|
||||
[mode]="'full'"
|
||||
(copyVeriKey)="copyToClipboard($event)">
|
||||
</stellaops-input-manifest>
|
||||
|
||||
<!-- Security-focused view -->
|
||||
<stellaops-input-manifest
|
||||
[manifest]="inputManifest"
|
||||
[mode]="'compact'"
|
||||
[displayConfig]="{ showSource: false, showSbom: false, showVex: true, showPolicy: true, showSigners: true, showTimeWindow: false }">
|
||||
</stellaops-input-manifest>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Storybook Documentation
|
||||
|
||||
All components have Storybook stories in `src/Web/StellaOps.Web/src/stories/provcache/`:
|
||||
|
||||
| File | Description |
|
||||
|------|-------------|
|
||||
| `provenance-badge.stories.ts` | All badge states, trust scores, sizes |
|
||||
| `trust-score-display.stories.ts` | Score ranges, modes, breakdowns |
|
||||
| `input-manifest.stories.ts` | Modes, SBOM formats, certificates |
|
||||
| `proof-tree.stories.ts` | Tree depths, verdicts, verification |
|
||||
|
||||
Run Storybook to explore:
|
||||
|
||||
```bash
|
||||
cd src/Web/StellaOps.Web
|
||||
npm run storybook
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Integration Examples
|
||||
|
||||
### Finding Row Integration
|
||||
|
||||
```typescript
|
||||
// finding-row.component.ts
|
||||
@Component({
|
||||
selector: 'stellaops-finding-row',
|
||||
template: `
|
||||
<div class="finding-row">
|
||||
<stellaops-provenance-badge
|
||||
[state]="finding.provenanceState"
|
||||
[cacheDetails]="finding.cacheDetails"
|
||||
[trustScore]="finding.trustScore"
|
||||
(viewProofTree)="openProofPanel.emit(finding)">
|
||||
</stellaops-provenance-badge>
|
||||
<!-- ... rest of finding row -->
|
||||
</div>
|
||||
`
|
||||
})
|
||||
export class FindingRowComponent {
|
||||
@Input() finding!: FindingRow;
|
||||
@Output() openProofPanel = new EventEmitter<FindingRow>();
|
||||
}
|
||||
```
|
||||
|
||||
### Decision Detail Panel
|
||||
|
||||
```typescript
|
||||
// decision-detail-panel.component.ts
|
||||
@Component({
|
||||
template: `
|
||||
<div class="decision-detail-panel">
|
||||
<stellaops-trust-score-display
|
||||
[score]="digest.trustScore"
|
||||
[breakdown]="digest.trustScoreBreakdown"
|
||||
[mode]="'donut'"
|
||||
[showBreakdown]="true">
|
||||
</stellaops-trust-score-display>
|
||||
|
||||
<stellaops-proof-tree
|
||||
[digest]="digest"
|
||||
[merkleTree]="merkleTree"
|
||||
[verdicts]="verdicts"
|
||||
[evidenceChunks]="chunks"
|
||||
[isVerifying]="verifying$ | async"
|
||||
(verify)="verifyProof()"
|
||||
(downloadEvidence)="downloadChunk($event)">
|
||||
</stellaops-proof-tree>
|
||||
|
||||
<stellaops-input-manifest
|
||||
[manifest]="manifest"
|
||||
[mode]="'full'">
|
||||
</stellaops-input-manifest>
|
||||
</div>
|
||||
`
|
||||
})
|
||||
export class DecisionDetailPanelComponent {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Theming
|
||||
|
||||
Components use CSS custom properties for theming:
|
||||
|
||||
```css
|
||||
/* Dark mode overrides */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
--trust-score-high: #81c784;
|
||||
--trust-score-medium: #ffb74d;
|
||||
--trust-score-low: #e57373;
|
||||
--badge-cached-bg: #1b5e20;
|
||||
--badge-computed-bg: #0d47a1;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Accessibility
|
||||
|
||||
All components follow WCAG 2.1 AA guidelines:
|
||||
|
||||
- **Keyboard navigation** — All interactive elements focusable and operable
|
||||
- **Screen reader support** — ARIA labels, roles, and live regions
|
||||
- **Color independence** — Icons and text supplement color coding
|
||||
- **Focus indicators** — Visible focus outlines on interactive elements
|
||||
- **Motion preferences** — Reduced motion respected where applicable
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Provcache Module README](../provcache/README.md) — Core concepts and architecture
|
||||
- [Provcache Architecture](../provcache/architecture.md) — Technical deep-dive
|
||||
- [UI Architecture](./architecture.md) — Angular patterns and state management
|
||||
- [Accessibility Guide](../../accessibility.md) — WCAG compliance guidelines
|
||||
Reference in New Issue
Block a user