diff --git a/docs/implplan/SPRINT_20260307_024_FE_identity_watchlist_shell.md b/docs-archived/implplan/SPRINT_20260307_024_FE_identity_watchlist_shell.md similarity index 69% rename from docs/implplan/SPRINT_20260307_024_FE_identity_watchlist_shell.md rename to docs-archived/implplan/SPRINT_20260307_024_FE_identity_watchlist_shell.md index c85168b18..4bf593ee5 100644 --- a/docs/implplan/SPRINT_20260307_024_FE_identity_watchlist_shell.md +++ b/docs-archived/implplan/SPRINT_20260307_024_FE_identity_watchlist_shell.md @@ -30,7 +30,7 @@ ## Delivery Tracker ### FE-WL-001 - Wire the canonical watchlist shell into Setup -Status: TODO +Status: DONE Dependency: none Owners: Product Manager, FE Architect Task description: @@ -38,12 +38,12 @@ Task description: - Make the shell routable and usable with working tab navigation and scope-aware header behavior. Completion criteria: -- [ ] Watchlist is reachable from the active shell navigation. -- [ ] Canonical routes and tab behavior are wired in code. -- [ ] Scope-aware header behavior works from the mounted shell. +- [x] Watchlist is reachable from the active shell navigation. +- [x] Canonical routes and tab behavior are wired in code. +- [x] Scope-aware header behavior works from the mounted shell. ### FE-WL-002 - Ship the Entries workflow -Status: TODO +Status: DONE Dependency: FE-WL-001 Owners: Developer, FE Architect Task description: @@ -51,12 +51,12 @@ Task description: - Ensure operators can create, edit, duplicate, enable/disable, delete, and test matching rules from the mounted shell. Completion criteria: -- [ ] Entry CRUD flows work from the mounted shell. -- [ ] Edit/create uses a contextual panel or drawer instead of a detached page. -- [ ] Pattern test is wired and usable within the entry-editing flow. +- [x] Entry CRUD flows work from the mounted shell. +- [x] Edit/create uses a contextual panel or drawer instead of a detached page. +- [x] Pattern test is wired and usable within the entry-editing flow. ### FE-WL-003 - Ship the Alerts workflow -Status: TODO +Status: DONE Dependency: FE-WL-001 Owners: Developer, Product Manager Task description: @@ -64,12 +64,12 @@ Task description: - Make alert-detail deep links work from Mission Control and back into the owning watchlist rule. Completion criteria: -- [ ] Alert listing and filtering work in the mounted shell. -- [ ] Alert-detail drawer shows the required context and actions. -- [ ] Operators can jump between alert detail and the owning watchlist entry. +- [x] Alert listing and filtering work in the mounted shell. +- [x] Alert-detail drawer shows the required context and actions. +- [x] Operators can jump between alert detail and the owning watchlist entry. ### FE-WL-004 - Ship tuning and diagnostics -Status: TODO +Status: DONE Dependency: FE-WL-001 Owners: Developer, Documentation author Task description: @@ -77,12 +77,12 @@ Task description: - Align the shipped tab with the operational runbook so the page is usable for real operator tuning. Completion criteria: -- [ ] Dedup and channel controls are wired into the page. -- [ ] Operational KPI cards render in the mounted shell. -- [ ] Tuning guidance matches the operational runbook terminology. +- [x] Dedup and channel controls are wired into the page. +- [x] Operational KPI cards render in the mounted shell. +- [x] Tuning guidance matches the operational runbook terminology. ### FE-WL-005 - Wire Mission Control and Notifications entry points -Status: TODO +Status: DONE Dependency: FE-WL-003 Owners: FE Architect, Developer Task description: @@ -90,12 +90,12 @@ Task description: - Ensure those surfaces expose outcomes only and send operators into the canonical watchlist shell for action. Completion criteria: -- [ ] Mission Control links open the working watchlist alerts flow. -- [ ] Notifications links open tuning or alert views in the canonical shell. -- [ ] `returnTo` behavior preserves operator context across shells. +- [x] Mission Control links open the working watchlist alerts flow. +- [x] Notifications links open tuning or alert views in the canonical shell. +- [x] `returnTo` behavior preserves operator context across shells. ### FE-WL-006 - Verify, document, and cut over the feature -Status: TODO +Status: DONE Dependency: FE-WL-002 Owners: QA, Documentation author Task description: @@ -103,24 +103,33 @@ Task description: - Update docs and cutover notes so Watchlist is treated as a shipped feature, not an orphan page. Completion criteria: -- [ ] Playwright scenarios cover entries, alerts, and tuning. -- [ ] Scope-sensitive behaviors are explicitly verified. -- [ ] Docs and rollout notes reflect the mounted and usable feature. +- [x] Playwright scenarios cover entries, alerts, and tuning. +- [x] Scope-sensitive behaviors are explicitly verified. +- [x] Docs and rollout notes reflect the mounted and usable feature. ## Execution Log | Date (UTC) | Update | Owner | | --- | --- | --- | | 2026-03-07 | Sprint created to ship Watchlist as a Trust & Signing-owned shell with working entries, alerts, tuning, and secondary surfacing in Mission Control and Notifications. | Project Manager | +| 2026-03-07 | Implementation started. Freezing Watchlist under the Trust Admin shell with route-backed tabs, query-param deep links, split detail panels, and cross-shell entry points from Mission Control and Notifications. | Developer | +| 2026-03-07 | Implemented the canonical Watchlist shell under `Setup > Trust & Signing`, wired Mission Control and Notifications deep links, and updated the shipped UX docs. | Developer | +| 2026-03-07 | Verified the feature with targeted Angular tests (`npx ng test --watch=false --include src/tests/watchlist/identity-watchlist-management-ui.component.spec.ts --include src/tests/trust_admin/trust-scoring-dashboard-ui.behavior.spec.ts --include src/tests/notify/notify-watchlist-handoff.spec.ts`) and Playwright browser scenarios (`npx playwright test tests/e2e/watchlist-shell.spec.ts --workers=1`). | QA | ## Decisions & Risks - Decision: Watchlist belongs under `Setup > Trust & Signing`, with alert visibility surfaced elsewhere. - Decision: configuration and alert history remain in one shell; they should not be split into separate products. +- Decision: the canonical mounted routes are `/setup/trust-signing/watchlist/{entries|alerts|tuning}` and all secondary entry points now deep-link into that route family. - Risk: Mission Control may try to absorb watchlist because it already owns alerts. - Mitigation: freeze the ownership boundary and only allow alert-source chips and deep links from Mission Control. - Risk: scope handling across tenant, global, and system rules can create hidden permissions complexity. - Mitigation: require scope-aware header behavior and QA coverage before rollout. - Delivery rule: this sprint is only complete when Watchlist is visible in navigation, usable end to end, and its key alert and tuning workflows are verified. - Reference design note: `docs/modules/ui/watchlist-operations/README.md`. +- Docs synced: + - `docs/modules/ui/watchlist-operations/README.md` + - `docs/features/checked/web/identity-watchlist-management-ui.md` + - `docs/modules/ui/TASKS.md` + - `docs/modules/ui/implementation_plan.md` ## Next Checkpoints - 2026-03-08: confirm owner shell, tab set, and deep-link behavior. diff --git a/docs/features/checked/web/identity-watchlist-management-ui.md b/docs/features/checked/web/identity-watchlist-management-ui.md index 699b20479..08779bad4 100644 --- a/docs/features/checked/web/identity-watchlist-management-ui.md +++ b/docs/features/checked/web/identity-watchlist-management-ui.md @@ -7,32 +7,42 @@ Web VERIFIED ## Description -Full CRUD UI for managing identity watchlist entries (issuer, SAN, keyId) with match modes (Exact, Prefix, Glob, Regex), severity levels, scope (Tenant/Global/System), alert viewing, pattern testing, and duplicate suppression configuration. Users can create, edit, delete, enable/disable watchlist entries and view resulting alerts. +Mounted Trust & Signing shell for managing identity watchlist entries (issuer, SAN, keyId) with match modes (Exact, Prefix, Glob, Regex), severity levels, scope (Tenant/Global/System), alert viewing, pattern testing, duplicate suppression configuration, and deep-link handoff from Mission Control and Notifications. ## Implementation Details - **Feature directory**: `src/Web/StellaOps.Web/src/app/features/watchlist/` - **Components**: - `watchlist-page` (`src/Web/StellaOps.Web/src/app/features/watchlist/watchlist-page.component.ts`) -- **Source**: Feature matrix scan +- **Canonical routes**: + - `/setup/trust-signing/watchlist/entries` + - `/setup/trust-signing/watchlist/alerts` + - `/setup/trust-signing/watchlist/tuning` +- **Secondary entry points**: + - `Mission Control > Alerts` + - `Ops > Notifications` +- **Source**: shipped Trust & Signing watchlist shell ## E2E Test Plan - **Setup**: - [ ] Log in with a user that has appropriate permissions - - [ ] Navigate to `/security` - - [ ] Ensure test data exists (scanned artifacts, SBOM data, or seed data as needed) + - [ ] Navigate to `/setup/trust-signing/watchlist/entries` + - [ ] Ensure identity watchlist seed data exists for entries and recent alerts - **Core verification**: - - [ ] Verify the list/table loads with paginated data - - [ ] Verify sorting and filtering controls work correctly - - [ ] Verify clicking a row navigates to the detail view + - [ ] Verify `Entries`, `Alerts`, and `Tuning` load inside one mounted shell + - [ ] Verify entry CRUD, pattern testing, and scope switching work + - [ ] Verify alert drill-in, jump-to-rule, and notifications handoff work - **Edge cases**: - [ ] Verify graceful handling when backend API is unavailable (error state) + - [ ] Verify `returnTo` preserves operator context from Mission Control and Notifications - [ ] Verify responsive layout at different viewport sizes - [ ] Verify accessibility (keyboard navigation, screen reader labels, ARIA attributes) ## Verification -- Run: `docs/qa/feature-checks/runs/web/identity-watchlist-management-ui/run-001/` +- Run: + - `npx ng test --watch=false --include src/tests/watchlist/identity-watchlist-management-ui.component.spec.ts --include src/tests/trust_admin/trust-scoring-dashboard-ui.behavior.spec.ts --include src/tests/notify/notify-watchlist-handoff.spec.ts` + - `npx playwright test tests/e2e/watchlist-shell.spec.ts --workers=1` - Tier 0 (source): pass (`tier0-source-check.json`) - Tier 1 (build/tests): pass (`tier1-build-check.json`) - Tier 2 (behavior): pass (`tier2-e2e-check.json`) -- Verified on (UTC): 2026-02-11T07:02:25Z +- Verified on (UTC): 2026-03-07T16:43:00Z diff --git a/docs/modules/ui/TASKS.md b/docs/modules/ui/TASKS.md index 8561fa03b..0133812dc 100644 --- a/docs/modules/ui/TASKS.md +++ b/docs/modules/ui/TASKS.md @@ -9,7 +9,6 @@ - `docs/implplan/SPRINT_20260307_009_DOCS_ui_component_preservation_map.md` - `docs/implplan/SPRINT_20260307_022_FE_policy_vex_release_decisioning_studio.md` - `docs/implplan/SPRINT_20260307_023_DOCS_ui_restoration_topic_shapes.md` -- `docs/implplan/SPRINT_20260307_024_FE_identity_watchlist_shell.md` - `docs/implplan/SPRINT_20260307_025_FE_reachability_witnessing_merge.md` - `docs/implplan/SPRINT_20260307_026_FE_platform_ops_consolidation.md` - `docs/implplan/SPRINT_20260307_027_FE_triage_explainability_workspace.md` @@ -72,12 +71,12 @@ - [TODO] FE-PD-005 FE implementation slices for Decisioning Studio shell and cutover - [TODO] FE-PD-006 QA and rollout contract for Decisioning Studio - [TODO] FE-PD-007 Docs and deprecation plan for legacy policy / VEX product labels -- [TODO] FE-WL-001 Freeze Watchlist shell ownership and route contract -- [TODO] FE-WL-002 Entries tab list-detail implementation slice -- [TODO] FE-WL-003 Alerts tab and alert-detail drill-in -- [TODO] FE-WL-004 Tuning tab and operational diagnostics -- [TODO] FE-WL-005 Cross-product surfacing and deep links for Watchlist -- [TODO] FE-WL-006 QA, rollout, and docs sync for Watchlist +- [DONE] FE-WL-001 Freeze Watchlist shell ownership and route contract +- [DONE] FE-WL-002 Entries tab list-detail implementation slice +- [DONE] FE-WL-003 Alerts tab and alert-detail drill-in +- [DONE] FE-WL-004 Tuning tab and operational diagnostics +- [DONE] FE-WL-005 Cross-product surfacing and deep links for Watchlist +- [DONE] FE-WL-006 QA, rollout, and docs sync for Watchlist - [TODO] FE-RW-001 Freeze reachability shell tabs and route contract - [TODO] FE-RW-002 Witnesses tab and witness-detail page slice - [TODO] FE-RW-003 PoE drawer and permalink route contract diff --git a/docs/modules/ui/component-preservation-map/RESTORATION_PRIORITIES.md b/docs/modules/ui/component-preservation-map/RESTORATION_PRIORITIES.md index feb5718be..5e9a4c277 100644 --- a/docs/modules/ui/component-preservation-map/RESTORATION_PRIORITIES.md +++ b/docs/modules/ui/component-preservation-map/RESTORATION_PRIORITIES.md @@ -41,7 +41,7 @@ The order is by confidence that the capability should exist in the final Stella - `Setup > Trust & Signing > Identity Watchlist` - Notes: - Detailed UX dossier: `docs/modules/ui/watchlist-operations/README.md` - - Implementation sprint: `docs/implplan/SPRINT_20260307_024_FE_identity_watchlist_shell.md` + - Implementation sprint: `docs-archived/implplan/SPRINT_20260307_024_FE_identity_watchlist_shell.md` ### 3. Reachability Witnessing - Type: `merge` diff --git a/docs/modules/ui/implementation_plan.md b/docs/modules/ui/implementation_plan.md index f9d635bb9..06bd91108 100644 --- a/docs/modules/ui/implementation_plan.md +++ b/docs/modules/ui/implementation_plan.md @@ -13,7 +13,6 @@ Provide a living plan for UI deliverables, dependencies, and evidence. - `SPRINT_20260307_009_DOCS_ui_component_preservation_map.md` - per-component preservation dossiers for unused and weakly surfaced console UI components. - `SPRINT_20260307_022_FE_policy_vex_release_decisioning_studio.md` - canonical Decisioning Studio shell to unify policy, simulation, VEX decisioning, and release-context gate explanation. - `SPRINT_20260307_023_DOCS_ui_restoration_topic_shapes.md` - documentation prerequisite for shell/menu/tab placements; not a product-delivery sprint by itself. -- `SPRINT_20260307_024_FE_identity_watchlist_shell.md` - ship the Trust & Signing-owned identity watchlist shell with usable entries, alerts, tuning, and alert deep-link behavior. - `SPRINT_20260307_025_FE_reachability_witnessing_merge.md` - ship witness and proof-of-exposure UX inside Security > Reachability with working cross-shell deep links. - `SPRINT_20260307_026_FE_platform_ops_consolidation.md` - ship one Operations shell with grouped overview cards, legacy widget absorption, and legacy redirects. - `SPRINT_20260307_027_FE_triage_explainability_workspace.md` - ship the artifact workspace lane model, explainability panels, and audit-bundle flows. @@ -27,6 +26,7 @@ Provide a living plan for UI deliverables, dependencies, and evidence. - `docs/modules/ui/policy-decisioning-studio/README.md` - proposed Decisioning Studio product shape, tab model, route contract, and Release Orchestrator integration boundary. - `docs/modules/ui/restoration-topics/README.md` - detailed placement notes for the next restoration topics after Decisioning Studio. - `docs/modules/ui/watchlist-operations/README.md` - detailed watchlist UX dossier and owner-shell contract. +- `docs/features/checked/web/identity-watchlist-management-ui.md` - shipped verification note for the Trust & Signing watchlist shell and its Mission Control / Notifications handoffs. - `docs/modules/ui/reachability-witnessing/README.md` - detailed witness and proof UX dossier plus cross-shell deep-link contract. - `docs/modules/ui/platform-ops-consolidation/README.md` - detailed Operations overview taxonomy and legacy absorption plan. - `docs/modules/ui/triage-explainability-workspace/README.md` - detailed artifact workspace and audit-bundle UX dossier. diff --git a/docs/modules/ui/restoration-topics/README.md b/docs/modules/ui/restoration-topics/README.md index 6e965b3ff..bf7b56240 100644 --- a/docs/modules/ui/restoration-topics/README.md +++ b/docs/modules/ui/restoration-topics/README.md @@ -27,7 +27,7 @@ It answers four questions for each topic: ## Implementation Sprint Set -- `docs/implplan/SPRINT_20260307_024_FE_identity_watchlist_shell.md` +- `docs-archived/implplan/SPRINT_20260307_024_FE_identity_watchlist_shell.md` - shipped watchlist restoration - `docs/implplan/SPRINT_20260307_025_FE_reachability_witnessing_merge.md` - `docs/implplan/SPRINT_20260307_026_FE_platform_ops_consolidation.md` - `docs/implplan/SPRINT_20260307_027_FE_triage_explainability_workspace.md` diff --git a/docs/modules/ui/restoration-topics/watchlist.md b/docs/modules/ui/restoration-topics/watchlist.md index 9da385aef..4a3492c10 100644 --- a/docs/modules/ui/restoration-topics/watchlist.md +++ b/docs/modules/ui/restoration-topics/watchlist.md @@ -84,7 +84,7 @@ Merge these current behaviors into the new shell: ## Detailed UX And Sprint - Detailed UX dossier: `../watchlist-operations/README.md` -- Implementation sprint: `../../../implplan/SPRINT_20260307_024_FE_identity_watchlist_shell.md` +- Implementation sprint: `../../../docs-archived/implplan/SPRINT_20260307_024_FE_identity_watchlist_shell.md` ## Corroborating Inputs diff --git a/docs/modules/ui/watchlist-operations/README.md b/docs/modules/ui/watchlist-operations/README.md index cae404773..e4eace32f 100644 --- a/docs/modules/ui/watchlist-operations/README.md +++ b/docs/modules/ui/watchlist-operations/README.md @@ -1,5 +1,17 @@ # Identity Watchlist +## Implementation Status + +- Status: `shipped` +- Owner shell: `Setup > Trust & Signing` +- Canonical routes: + - `/setup/trust-signing/watchlist/entries` + - `/setup/trust-signing/watchlist/alerts` + - `/setup/trust-signing/watchlist/tuning` +- Secondary entry points: + - `Mission Control > Alerts` deep-links into `Alerts` + - `Ops > Notifications` deep-links into `Tuning` and `Alerts` + ## Recommendation Restore Watchlist as a narrow operational shell owned by `Setup > Trust & Signing`, not as a standalone top-level product. diff --git a/src/Web/StellaOps.Web/src/app/features/mission-control/mission-alerts-page.component.ts b/src/Web/StellaOps.Web/src/app/features/mission-control/mission-alerts-page.component.ts index f8602d3d0..f53940d7e 100644 --- a/src/Web/StellaOps.Web/src/app/features/mission-control/mission-alerts-page.component.ts +++ b/src/Web/StellaOps.Web/src/app/features/mission-control/mission-alerts-page.component.ts @@ -15,6 +15,14 @@ import { RouterLink } from '@angular/router'; diff --git a/src/Web/StellaOps.Web/src/app/features/notify/notify-panel.component.html b/src/Web/StellaOps.Web/src/app/features/notify/notify-panel.component.html index 6d4943d21..83192980b 100644 --- a/src/Web/StellaOps.Web/src/app/features/notify/notify-panel.component.html +++ b/src/Web/StellaOps.Web/src/app/features/notify/notify-panel.component.html @@ -15,6 +15,31 @@ +
+
+
+

Watchlist handoff

+

Identity watchlist configuration stays under Trust & Signing. Use notifications only for delivery health and escalation outcomes.

+
+
+
+ + Open watchlist tuning + + + Review watchlist alerts + +
+
+
diff --git a/src/Web/StellaOps.Web/src/app/features/notify/notify-panel.component.spec.ts b/src/Web/StellaOps.Web/src/app/features/notify/notify-panel.component.spec.ts index 9e5eb0f7b..e577c281e 100644 --- a/src/Web/StellaOps.Web/src/app/features/notify/notify-panel.component.spec.ts +++ b/src/Web/StellaOps.Web/src/app/features/notify/notify-panel.component.spec.ts @@ -63,4 +63,19 @@ describe('NotifyPanelComponent', () => { const preview = fixture.nativeElement.querySelector('[data-testid="test-preview"]'); expect(preview).toBeTruthy(); }); + + it('surfaces watchlist handoff links for tuning and alerts', () => { + const text = fixture.nativeElement.textContent as string; + const links = Array.from( + fixture.nativeElement.querySelectorAll('a') + ) as HTMLAnchorElement[]; + + expect(text).toContain('Watchlist handoff'); + expect( + links.some((link) => link.getAttribute('href')?.includes('/setup/trust-signing/watchlist/tuning')) + ).toBeTrue(); + expect( + links.some((link) => link.getAttribute('href')?.includes('/setup/trust-signing/watchlist/alerts')) + ).toBeTrue(); + }); }); diff --git a/src/Web/StellaOps.Web/src/app/features/notify/notify-panel.component.ts b/src/Web/StellaOps.Web/src/app/features/notify/notify-panel.component.ts index 810d91165..f009e2838 100644 --- a/src/Web/StellaOps.Web/src/app/features/notify/notify-panel.component.ts +++ b/src/Web/StellaOps.Web/src/app/features/notify/notify-panel.component.ts @@ -12,6 +12,7 @@ import { ReactiveFormsModule, Validators, } from '@angular/forms'; +import { RouterLink } from '@angular/router'; import { firstValueFrom } from 'rxjs'; import { @@ -40,7 +41,7 @@ type DeliveryFilter = @Component({ selector: 'app-notify-panel', - imports: [CommonModule, ReactiveFormsModule], + imports: [CommonModule, ReactiveFormsModule, RouterLink], templateUrl: './notify-panel.component.html', styleUrls: ['./notify-panel.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush diff --git a/src/Web/StellaOps.Web/src/app/features/trust-admin/trust-admin.component.spec.ts b/src/Web/StellaOps.Web/src/app/features/trust-admin/trust-admin.component.spec.ts index 860395851..963d1ca2b 100644 --- a/src/Web/StellaOps.Web/src/app/features/trust-admin/trust-admin.component.spec.ts +++ b/src/Web/StellaOps.Web/src/app/features/trust-admin/trust-admin.component.spec.ts @@ -1,85 +1,100 @@ -/** - * @file trust-admin.component.spec.ts - * @sprint SPRINT_20251229_018c_FE - * @description Unit tests for TrustAdminComponent - */ - -import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing'; -import { provideRouter } from '@angular/router'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { provideRouter, Router } from '@angular/router'; import { of } from 'rxjs'; + +import { TRUST_API, type TrustApi } from '../../core/api/trust.client'; +import type { TrustDashboardSummary } from '../../core/api/trust.models'; import { TrustAdminComponent } from './trust-admin.component'; -import { TRUST_API, TrustApi } from '../../core/api/trust.client'; -import { TrustDashboardStats } from '../../core/api/trust.models'; describe('TrustAdminComponent', () => { let component: TrustAdminComponent; let fixture: ComponentFixture; - let mockTrustApi: jasmine.SpyObj; + let router: Router; + let trustApi: jasmine.SpyObj; - const mockStats: TrustDashboardStats = { - totalKeys: 10, - activeKeys: 8, - expiringKeys: 2, - revokedKeys: 0, - totalIssuers: 25, - trustedIssuers: 20, - blockedIssuers: 5, - totalCertificates: 15, - validCertificates: 12, - expiringCertificates: 3, - recentAuditEvents: 50, - criticalEvents: 2, + const dashboardSummaryFixture: TrustDashboardSummary = { + keys: { + total: 12, + active: 9, + expiringSoon: 2, + expired: 1, + revoked: 0, + pendingRotation: 1, + }, + issuers: { + total: 8, + fullTrust: 3, + partialTrust: 3, + minimalTrust: 1, + untrusted: 1, + blocked: 0, + averageTrustScore: 86.4, + }, + certificates: { + total: 5, + valid: 4, + expiringSoon: 1, + expired: 0, + revoked: 0, + invalidChains: 0, + }, + recentEvents: [], + expiryAlerts: [ + { + keyId: 'key-001', + keyName: 'Attestation Key', + expiresAt: '2026-03-01T00:00:00Z', + daysUntilExpiry: 19, + severity: 'warning', + purpose: 'attestation', + suggestedAction: 'Rotate key', + }, + ], }; beforeEach(async () => { - mockTrustApi = jasmine.createSpyObj('TrustApi', [ - 'getDashboardStats', + trustApi = jasmine.createSpyObj('TrustApi', [ + 'getDashboardSummary', ]); - - mockTrustApi.getDashboardStats.and.returnValue(of(mockStats)); + trustApi.getDashboardSummary.and.returnValue(of(dashboardSummaryFixture)); await TestBed.configureTestingModule({ imports: [TrustAdminComponent], providers: [ provideRouter([]), - { provide: TRUST_API, useValue: mockTrustApi }, + { provide: TRUST_API, useValue: trustApi }, ], }).compileComponents(); + router = TestBed.inject(Router); fixture = TestBed.createComponent(TrustAdminComponent); component = fixture.componentInstance; }); - it('should create', () => { - expect(component).toBeTruthy(); + it('loads the trust dashboard summary on init', () => { + fixture.detectChanges(); + + expect(trustApi.getDashboardSummary).toHaveBeenCalledTimes(1); + expect(component.summary()).toEqual(dashboardSummaryFixture); + expect(component.alertCount()).toBe(1); }); - it('should load dashboard stats on init', fakeAsync(() => { + it('renders the watchlist tab in the trust shell', () => { fixture.detectChanges(); - tick(); + const text = fixture.nativeElement.textContent as string; - expect(mockTrustApi.getDashboardStats).toHaveBeenCalled(); - expect(component.stats()).toEqual(mockStats); - })); - - it('should display navigation tabs', () => { - fixture.detectChanges(); - const tabs = fixture.nativeElement.querySelectorAll('.trust-admin__tabs a, .trust-admin__tabs button'); - expect(tabs.length).toBeGreaterThan(0); + expect(text).toContain('Watchlist'); + expect(text).toContain('Trust Management'); }); - it('should display summary cards', fakeAsync(() => { - fixture.detectChanges(); - tick(); + it('derives the watchlist tab from nested watchlist routes', () => { + Object.defineProperty(router, 'url', { + configurable: true, + get: () => '/setup/trust-signing/watchlist/alerts?scope=tenant', + }); - const cards = fixture.nativeElement.querySelectorAll('.summary-card, .stat-card, .dashboard-card'); - // Should have summary cards for keys, issuers, certificates - expect(cards.length).toBeGreaterThan(0); - })); - - it('should handle loading state', () => { - expect(component.loading()).toBeTrue(); fixture.detectChanges(); - expect(component.loading()).toBeFalse(); + + expect(component.activeTab()).toBe('watchlist'); }); }); diff --git a/src/Web/StellaOps.Web/src/app/features/trust-admin/trust-admin.component.ts b/src/Web/StellaOps.Web/src/app/features/trust-admin/trust-admin.component.ts index 90f53e433..d483091b9 100644 --- a/src/Web/StellaOps.Web/src/app/features/trust-admin/trust-admin.component.ts +++ b/src/Web/StellaOps.Web/src/app/features/trust-admin/trust-admin.component.ts @@ -13,8 +13,25 @@ import { filter } from 'rxjs'; import { TRUST_API, TrustApi } from '../../core/api/trust.client'; import { TrustDashboardSummary } from '../../core/api/trust.models'; -export type TrustAdminTab = 'keys' | 'issuers' | 'certificates' | 'audit' | 'airgap' | 'incidents' | 'analytics'; -const TRUST_ADMIN_TABS: readonly TrustAdminTab[] = ['keys', 'issuers', 'certificates', 'audit', 'airgap', 'incidents', 'analytics']; +export type TrustAdminTab = + | 'keys' + | 'issuers' + | 'certificates' + | 'watchlist' + | 'audit' + | 'airgap' + | 'incidents' + | 'analytics'; +const TRUST_ADMIN_TABS: readonly TrustAdminTab[] = [ + 'keys', + 'issuers', + 'certificates', + 'watchlist', + 'audit', + 'airgap', + 'incidents', + 'analytics', +]; @Component({ selector: 'app-trust-admin', @@ -28,7 +45,7 @@ const TRUST_ADMIN_TABS: readonly TrustAdminTab[] = ['keys', 'issuers', 'certific

{{ workspaceLabel() }}

Trust Management

- Manage signing keys, trusted issuers, mTLS certificates, and view audit logs. + Manage signing keys, trusted issuers, mTLS certificates, identity watchlists, and audit logs.

@@ -135,6 +152,15 @@ const TRUST_ADMIN_TABS: readonly TrustAdminTab[] = ['keys', 'issuers', 'certific {{ summary()?.certificates?.expiringSoon }} } + + Watchlist + + import('../watchlist/watchlist-page.component').then( + (m) => m.WatchlistPageComponent + ), + data: { requiredScopes: [StellaOpsScopes.SIGNER_READ] }, + }, + { + path: 'watchlist/entries', + loadComponent: () => + import('../watchlist/watchlist-page.component').then( + (m) => m.WatchlistPageComponent + ), + data: { requiredScopes: [StellaOpsScopes.SIGNER_READ] }, + }, + { + path: 'watchlist/alerts', + loadComponent: () => + import('../watchlist/watchlist-page.component').then( + (m) => m.WatchlistPageComponent + ), + data: { requiredScopes: [StellaOpsScopes.SIGNER_READ] }, + }, + { + path: 'watchlist/tuning', + loadComponent: () => + import('../watchlist/watchlist-page.component').then( + (m) => m.WatchlistPageComponent + ), + data: { requiredScopes: [StellaOpsScopes.SIGNER_READ] }, + }, { path: 'audit', loadComponent: () => diff --git a/src/Web/StellaOps.Web/src/app/features/watchlist/watchlist-page.component.html b/src/Web/StellaOps.Web/src/app/features/watchlist/watchlist-page.component.html index 4c67870f7..9ad3953fe 100644 --- a/src/Web/StellaOps.Web/src/app/features/watchlist/watchlist-page.component.html +++ b/src/Web/StellaOps.Web/src/app/features/watchlist/watchlist-page.component.html @@ -1,333 +1,689 @@
- @if (message()) { -
- {{ message() }} - +
+ {{ message() }} +
} - -