- Implemented EmailChannelTestProvider to generate email preview payloads. - Implemented SlackChannelTestProvider to create Slack message previews. - Implemented TeamsChannelTestProvider for generating Teams Adaptive Card previews. - Implemented WebhookChannelTestProvider to create webhook payloads. - Added INotifyChannelTestProvider interface for channel-specific preview generation. - Created ChannelTestPreviewContracts for request and response models. - Developed NotifyChannelTestService to handle test send requests and generate previews. - Added rate limit policies for test sends and delivery history. - Implemented unit tests for service registration and binding. - Updated project files to include necessary dependencies and configurations.
16 KiB
component_architecture_web_ui.md — Stella Ops Web UI (2025Q4)
Scope. Implementation‑ready architecture for the Angular SPA that operators and developers use to drive Stella Ops. This document defines UX surfaces, module boundaries, data flows, auth, RBAC, real‑time updates, performance targets, i18n/a11y, security headers, testing and deployment. The UI is a consumer of backend APIs (Scanner, Policy, Excititor, Concelier, Attestor, Authority) and never performs scanning, merging, or signing on its own.
0) Mission & non‑goals
Mission. Provide a fast, explainable console for:
- Scans (status, SBOMs, diffs, EntryTrace, attestation).
- Policy management (rules, exemptions, VEX consumption view).
- Vulnerability intel (Concelier status), VEX consensus exploration (Excititor).
- Runtime posture (Zastava observer + admission).
- Admin operations (tenants, tokens, quotas, licensing posture).
Non‑goals. No client‑side crypto signing; no Docker/CRI access; no direct registry access beyond fetching static assets or OCI referrer summaries exposed by backend.
1) Technology baseline
- Framework: Angular 17+ (Stand‑alone APIs / Signals), TypeScript 5.
- Styling: Tailwind CSS + headless component patterns; CSS variables for theming.
- Charts: Lightweight SVG (uPlot or Apache ECharts via on‑demand import).
- State: Angular Signals +
@ngrx/signalsstore for cross‑page slices. - Transport:
fetch+ RxJS interop; SSE (EventSource) for progress streams. - Build: Angular CLI + Vite builder.
- Testing: Jest + Testing Library, Playwright for e2e.
- Packaging: Containerized NGINX (immutable assets, ETag + content hashing).
2) High‑level module map
/app
├─ core/ # bootstrap, config, auth, http, error boundary, i18n
├─ shared/ # UI kit (tables, code-viewers, badges), pipes
├─ dashboard/ # live tiles, fleet KPIs, feed/vex age, queue depth
├─ scans/ # scan list, detail, SBOM viewer, diff-by-layer, EntryTrace
├─ runtime/ # Zastava posture, drift events, admission decisions
├─ policy/ # rules editor (YAML/Rego), exemptions, previews
├─ vex/ # VEX explorer (claims, consensus, conflicts)
├─ concelier/ # source health, export cursors, rebuild/export triggers
├─ attest/ # attestation proofs, verification bundles, Rekor links
├─ admin/ # tenants, roles, clients, quotas, licensing posture
└─ plugins/ # route plug-ins (lazy remote modules, governed)
Each feature folder builds as a standalone route (lazy loaded). All HTTP shapes live in core/api/ clients with shared DTOs.
3) Navigation & key views
3.1 Dashboard
- Tiles: “New criticals (24h)”, “VEX suppressions applied”, “Attested SBOMs (7d)”, “Feed age per provider”, “Scanner queue depth”, “Admission events”.
- Trends: sparkline for vulns/day, pass/fail rates, attestation throughput.
3.2 Scans
-
Scan list with status, image digest, repo, time, artifacts, attestation badge.
-
Scan detail:
- SBOM viewer: Inventory/Usage toggle; component table (virtualized), filters by package type, severity, source.
- Diff by layer: A→B change grid (added/removed/upgraded), grouped by introducing/removing layer; tooltips show provenance and links to layer SBOM fragment.
- EntryTrace: shell chain with file:line breadcrumbs; jump‑to source viewer (read‑only, hexdump fallback).
- Attestation: Rekor UUID, index, inclusion proof; Verify button calls Attestor
/verify. - Export: download buttons (CycloneDX JSON, Protobuf, SPDX JSON); size shown; SHA‑256 inline.
3.3 Runtime (Zastava)
- Observer timeline: container start/stop, drift, policy violations; faceted by namespace/owner.
- Live process view: top N processes, loaded libs summary vs Usage SBOM.
- Admission decisions: per‑namespace rules, allow/deny events, cache TTL, reasons.
3.4 Policy
-
Policy bundles: active vs staged; diff viewer with change summary.
-
Editors:
- YAML rules (ignore lists, thresholds, vendor precedence overrides).
- Rego blocks (advanced gates) with WASM preview evaluator (client‑side sandbox) for “preview” against sample SBOMs.
-
VEX inclusion controls: weight sliders (visualization only), provider allow/deny toggles.
-
Preview: select SBOM (or image digest) → show verdict under staged policy.
3.5 Excititor
- Claims explorer: search by vulnId/productKey/provider; show raw claim (status, justification, evidence).
- Consensus view: rollup per (vuln, product) with accepted/rejected sources, weights, timestamps.
- Conflicts: grid of top conflicts; filters for justification gates failed.
3.6 Concelier
- Sources table: staleness, last run, errors.
- Advisory search: by CVE/alias; show normalized affected ranges.
- Exports: trigger full/delta JSON/Trivy DB; show manifest digests and Rekor link if attested.
3.7 Attest
- Proofs list: last 7 days Rekor entries; filter by kind (sbom/report/vex).
- Verification: paste UUID or upload bundle → verify; result with explanations (chain, Merkle path).
3.8 Admin
- Tenants/Installations: view/edit, isolation hints.
- Clients & roles: Authority clients, role→scope mapping, rotation hints.
- Quotas: per license plan, counters, throttle events.
- Licensing posture: last PoE introspection snapshot (redacted), release window.
4) Auth, sessions & RBAC
4.1 OIDC flow
- Authorization Code + PKCE to Authority.
- ID Token for UX identity; Access Token (OpTok) for APIs (2–5 min TTL).
- DPoP (browser): generate ephemeral WebCrypto keypair; store public JWK in memory, private key in IndexedDB (non‑exportable if platform allows). Access token includes
cnf.jkt; each API call addsDPoPproof; handle nonce challenges automatically. - Refresh: optional DPoP‑bound refresh tokens with rotation; otherwise silent renew.
4.2 RBAC
- Roles (
ui.read,ui.admin, plus service roles) are embedded in ID token or fetched via/meendpoint. - Route guards enforce access; feature flags hide admin pages for non‑admins.
4.3 Session storage
- Access tokens & refresh metadata in memory; persist only minimal session (subject, expiries) in
sessionStorage. Never persist raw JWTs tolocalStorage. Use SameSite=Lax cookies for anti‑CSRF if cookies are required (prefer pure bearer headers + DPoP).
5) HTTP layer & API clients
-
core/http/api-client.tscentralizes:- Base URLs (Scanner, Excititor, Concelier, Attestor).
- Retry policies on idempotent GETs (backoff + jitter).
- Problem+JSON parser → uniform error toasts with correlation ID.
- SSE helper (EventSource) with auto‑reconnect & backpressure.
- DPoP injector & nonce handling.
-
Typed API clients (DTOs in
core/api/models.ts):ScannerApi,PolicyApi,ExcititorApi,ConcelierApi,AttestorApi,AuthorityApi.
DTO examples (abbrev):
export type ImageDigest = `sha256:${string}`;
export interface ScanSummary {
imageDigest: ImageDigest; createdAt: string;
artifacts: { view: 'inventory'|'usage'; format: 'cdx-json'|'cdx-pb'|'spdx-json'; sha256: string; size: number }[];
status: 'queued'|'running'|'completed'|'error';
rekor?: { uuid: string; index?: number; url?: string };
}
export interface DiffEntry {
key: string; change: 'added'|'removed'|'upgraded'|'downgraded';
fromVersion?: string; toVersion?: string; layer: string; usedByEntrypoint?: boolean;
}
export interface VexConsensus {
vulnId: string; productKey: string; rollupStatus: 'affected'|'not_affected'|'fixed'|'under_investigation';
sources: { providerId: string; status: string; weight: number; accepted: boolean; reason: string }[];
}
Upcoming: NotifyApi consumes delivery history using the new paginated envelope returned by /api/v1/notify/deliveries.
export interface NotifyDeliveryListResponse {
items: NotifyDelivery[];
count: number;
continuationToken?: string;
}
export interface NotifyDelivery {
deliveryId: string;
ruleId: string;
actionId: string;
status: 'pending'|'sent'|'failed'|'throttled'|'digested'|'dropped';
rendered: NotifyDeliveryRendered;
metadata: Record<string, string>; // includes channelType, target, previewProvider, traceId, and provider-specific entries
createdAt: string;
sentAt?: string;
completedAt?: string;
}
6) State, caching & real‑time
-
Per‑page stores (Signals) for list filters, pagination, and selected entities.
-
Normalized caches keyed by
(imageDigest, view, format); artifacts are downloaded via pre‑signed URLs from Scanner and streamed; SHA‑256 verified client‑side before exposing “verified” badge. -
SSE channels:
/scans/{id}/events→ progress log./runtime/events/stream(optional) → live drift/admission feed (rate‑limited).
-
Cache invalidation on job completion or explicit “refresh”.
7) SBOM viewing & diff UX
- Huge tables rendered with virtual scrolling (CDK Virtual Scroll); sort/filter performed client‑side for ≤ 20k rows; beyond that, server‑side queries via BOM‑Index endpoints.
- Component row shows purl, version, origin (OS pkg / metadata / linker / attested), licenses, and used badge (Usage view).
- Diff: compact heatmap per layer; clicking opens a right‑pane with evidence: introducing paths, file hashes, VEX notes (from Excititor consensus) and links to advisories (Concelier).
8) Policy editor & VEX integration
- YAML editor: Monaco‑based with schema hints; previews show which rules matched.
- Rego editor: Monaco with WASM‑OPA sandbox for read‑only evaluation on sample SBOMs.
- VEX toggles: per‑provider enable/disable; “explain” drawer shows why a claim was accepted/rejected (justification gate, signature state, weight).
- Staged → Active promotion is a two‑step flow with confirmation and automatic policy digest computation.
9) Accessibility, i18n & theming
- A11y: WCAG 2.2 AA; keyboard navigation, focus management, ARIA roles; color‑contrast tokens verified by unit tests.
- I18n: Angular i18n + runtime translation loader (
/locales/{lang}.json); dates/numbers localized viaIntl. - Languages: English default; Bulgarian, German, Japanese as initial additions.
- Theming: dark/light via CSS variables; persisted in
prefers-color-schemeaware store.
10) Performance budgets
- TTI ≤ 1.5 s on 4G/slow CPU (first visit), ≤ 0.6 s repeat (HTTP/2, cached).
- JS initial < 300 KB gz (lazy routes).
- SBOM list: render 10k rows in < 70 ms with virtualization; filter in < 150 ms.
- Diff view: compute client‑side grouping for 5k changes in < 120 ms.
Techniques: route‑level code splitting; ChangeDetectionStrategy.OnPush; Signals; server compression (zstd/gzip), immutable assets with long max‑age (cache busting via hashes).
11) Security headers & CSP
- CSP:
default-src 'self'; connect-src 'self' https://*.internal; img-src 'self' data:; script-src 'self'; style-src 'self' 'unsafe-inline'; frame-ancestors 'none'; - HSTS enabled at gateway.
- Referrer Policy:
no-referrer. - X‑Frame‑Options:
DENY. - COOP/COEP to enable faster cross‑origin isolation (for WASM OPA).
- Subresource Integrity (SRI) for third‑party fonts (minimize third‑party).
12) Error handling & UX hygiene
- Global error boundary surfaces Problem+JSON
title/detail/instancewith correlation ID. - Retry toast for 429 (quota throttles) with backoff timer.
- Auth expiry: pre‑emptive refresh; unobtrusive banner when < 60 s TTL; re‑login modal if refresh fails.
- Network down: offline banner with queued actions (idempotent resubmits).
- File verify: show SHA‑256 mismatch warnings if artifact altered in transit.
13) Observability
- Front‑end telemetry (OpenTelemetry Web): route timings, API latency by service, error counts; sampled to 1–5% and shipped to backend OTLP endpoint.
- User actions logged anonymously (no PII): “policy promote”, “scan export”, “attest verify”.
- Metrics dash in admin shows SLOs and recent front‑end errors.
14) Testing strategy
- Unit: pure component logic via Jest + Testing Library (no TestBed when possible).
- Component harness for table, code viewer, diff heatmap.
- Contract tests: OpenAPI schemas pulled at build time; DTOs validated; breaking changes fail CI.
- e2e: Playwright scenarios (login, scan detail, diff, policy edit, admit deny).
- A11y: axe-core CI checks; color‑contrast lints.
- i18n: key coverage tests (no missing translations in supported locales).
15) Deployment & ops
- Container:
stellaops/web-ui:<ver>-<rev>; NGINX withgzip_static+ brotli; immutable assets under/static/<hash>/…. - Config:
/config.jsonserved by gateway (injected at runtime): API base URLs, authority issuer, telemetry sampling. - Version banner: footer shows UI & backend versions; warns on major mismatches.
- CDN (optional): cache static bundle; APIs stay behind internal gateway.
- Feature flags: environment gates (staged policies, eBPF runtime) readable from config.
16) Plugin system (route plug‑ins)
- Manifest: Backend provides a signed plug‑in manifest with remote module URLs and cosign signature per JS bundle.
- Loader: dynamic import with SRI and signature verification (WebCrypto).
- Sandbox: plug‑ins are routed modules receiving a limited UI SDK (navigation, theme, API gateway). No direct token access; API calls proxied through the UI SDK which enforces RBAC.
- Examples: custom reports, vendor dashboards, regulated TLS config UIs.
17) Wire sequences (representative)
A) View scan progress
sequenceDiagram
autonumber
participant UI
participant Auth as Authority
participant SW as Scanner.WebService
UI->>Auth: /authorize (PKCE)
Auth-->>UI: code → token (DPoP-bound)
UI->>SW: GET /scans/{id} (Authorization+DPoP)
SW-->>UI: { status: running }
UI->>SW: (SSE) GET /scans/{id}/events
SW-->>UI: progress events …
SW-->>UI: terminal event { status: completed, artifacts[] }
B) Verify attestation
sequenceDiagram
autonumber
participant UI
participant AT as Attestor
UI->>AT: POST /rekor/verify { uuid }
AT-->>UI: { ok:true, index, logURL }
C) Promote policy & preview
sequenceDiagram
autonumber
participant UI
participant BE as Scanner.WebService (Policy endpoint)
UI->>BE: POST /policy/stage { yaml, rego }
BE-->>UI: { policyRevision, diagnostics }
UI->>BE: POST /policy/preview { imageDigest, policyRevision }
BE-->>UI: { verdict: pass|fail, reasons[] }
UI->>BE: POST /policy/promote { policyRevision }
BE-->>UI: { ok:true }
18) Security hard lines
- Never store JWTs in
localStorage. - Enforce DPoP for API calls; if DPoP unsupported for a service, require SameSite=Lax cookies with CSRF token header.
- Block mixed‑content; only HTTPS origins allowed.
- Validate and render only escaped user content; code viewer uses safe highlighter.
- Downloaded artifacts are treated as opaque binaries; no HTML rendering.
19) Roadmap
- PWA offline shell (read‑only) for dashboards and cached scan details.
- SBOM graph visualization (force‑directed) for small components sets.
- Runtime session replay (privacy‑safe) to debug operator workflows (opt‑in).
- Assistive wizards for policy creation with guided templates.