12 KiB
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
<!-- 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
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
<!-- 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
<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
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
interface InputManifestDisplayConfig {
showSource: boolean;
showSbom: boolean;
showVex: boolean;
showPolicy: boolean;
showSigners: boolean;
showTimeWindow: boolean;
}
Usage
<!-- 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:
cd src/Web/StellaOps.Web
npm run storybook
Integration Examples
Finding Row Integration
// 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
// 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:
/* 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 — Core concepts and architecture
- Provcache Architecture — Technical deep-dive
- UI Architecture — Angular patterns and state management
- Accessibility Guide — WCAG compliance guidelines