Archive completed Sprint 008 (mirror client setup wizard)
All 6 tasks DONE: consumer API endpoints, 4-step setup wizard UI, dashboard and catalog integration, air-gap import API, E2E tests, and documentation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,232 +0,0 @@
|
||||
# Sprint 20260315_008 - Mirror Client Setup Wizard
|
||||
|
||||
## Topic & Scope
|
||||
- Give operators a self-serve UI to configure Stella Ops as a **mirror consumer** — pulling advisory/VEX data from an upstream mirror instead of (or alongside) direct sources.
|
||||
- Currently, switching to Mirror or Hybrid mode requires env vars (`CONCELIER__SOURCES__STELLAOPSMIRROR__*`). The backend connector (`StellaOpsMirrorConnector`) and API (`PUT /api/v1/mirror/config`, `POST /api/v1/mirror/test`) already exist, but there is no guided setup flow.
|
||||
- Also wire the air-gap bundle import path into the UI (currently CLI-only via `MirrorBundleImportService`).
|
||||
- Working directory: `src/Web/StellaOps.Web`, `src/Concelier/`
|
||||
- Cross-module edits: `src/Cli/`, `docs/modules/concelier/`
|
||||
- Expected evidence: wizard component, API extensions, Playwright tests, updated docs.
|
||||
|
||||
## Dependencies & Concurrency
|
||||
- Depends on Sprint 007 (mirror domain API, dashboard, catalog header — all DONE except TASK-011 docs).
|
||||
- The `StellaOpsMirrorConnector` plugin at `src/Concelier/__Libraries/StellaOps.Concelier.Connector.StellaOpsMirror/` is the backend consumer. The wizard configures it.
|
||||
- Safe parallelism: frontend tasks don't conflict with Sprint 006 (different components). Backend tasks modify Concelier endpoints (coordinate with TASK-011 if running).
|
||||
|
||||
## Documentation Prerequisites
|
||||
- `docs/modules/concelier/operations/mirror.md`
|
||||
- `src/Concelier/__Libraries/StellaOps.Concelier.Connector.StellaOpsMirror/Settings/StellaOpsMirrorConnectorOptions.cs`
|
||||
- `src/Concelier/StellaOps.Concelier.WebService/Extensions/MirrorDomainManagementEndpointExtensions.cs`
|
||||
- `src/Web/StellaOps.Web/src/app/features/integrations/advisory-vex-sources/mirror-dashboard.component.ts`
|
||||
|
||||
---
|
||||
|
||||
## Delivery Tracker
|
||||
|
||||
### MCS-001 - Extend mirror config API for consumer setup
|
||||
Status: DONE
|
||||
Dependency: none
|
||||
Owners: Developer (Backend)
|
||||
Task description:
|
||||
- The existing `PUT /api/v1/mirror/config` accepts mode and consumerBaseAddress but doesn't persist or apply the `StellaOpsMirrorConnectorOptions` (connector base address, domain ID, signature settings, timeout). Add endpoints to configure the consumer connector at runtime.
|
||||
|
||||
**Endpoints to add** (under `/api/v1/mirror`):
|
||||
|
||||
| Method | Path | Purpose |
|
||||
|--------|------|---------|
|
||||
| GET | `/consumer` | Get current consumer connector configuration |
|
||||
| PUT | `/consumer` | Update consumer connector config (base address, domain, signature, timeout) |
|
||||
| POST | `/consumer/discover` | Fetch mirror index from base address, return available domains with metadata |
|
||||
| POST | `/consumer/verify-signature` | Fetch a bundle header from mirror, return signature details (alg, kid) |
|
||||
|
||||
**Request/Response DTOs**:
|
||||
```
|
||||
ConsumerConfigRequest { baseAddress, domainId, indexPath?, httpTimeoutSeconds?, signature: { enabled, algorithm, keyId, publicKeyPem? } }
|
||||
ConsumerConfigResponse { baseAddress, domainId, indexPath, httpTimeoutSeconds, signature, connected, lastSync }
|
||||
MirrorDiscoveryResponse { domains: [ { domainId, displayName, lastGenerated, advisoryCount, bundleSize, exportFormats[], signed } ] }
|
||||
SignatureDiscoveryResponse { detected, algorithm, keyId, provider }
|
||||
```
|
||||
|
||||
**Files to modify**:
|
||||
- `src/Concelier/StellaOps.Concelier.WebService/Extensions/MirrorDomainManagementEndpointExtensions.cs` — add 4 new endpoints
|
||||
- `src/Concelier/StellaOps.Concelier.WebService/Services/InMemoryMirrorDomainStore.cs` — add `IMirrorConsumerConfigStore` with get/set for consumer config
|
||||
|
||||
Completion criteria:
|
||||
- [x] 4 new consumer endpoints created and wired
|
||||
- [x] Consumer config persisted in-memory (later DB)
|
||||
- [x] Discovery endpoint fetches real mirror index and parses domain metadata
|
||||
- [x] Signature discovery fetches JWS header from bundle
|
||||
|
||||
### MCS-002 - Mirror client setup wizard UI
|
||||
Status: DONE
|
||||
Dependency: MCS-001
|
||||
Owners: Developer (FE)
|
||||
Task description:
|
||||
- Create a guided wizard for configuring Stella Ops as a mirror consumer. The wizard should feel like a natural extension of the existing mirror dashboard.
|
||||
|
||||
**File to create**: `src/Web/StellaOps.Web/src/app/features/integrations/advisory-vex-sources/mirror-client-setup.component.ts`
|
||||
|
||||
**Wizard steps (4 steps)**:
|
||||
|
||||
**Step 1: Connect to Mirror**
|
||||
- Mirror base address input (URL, validated, placeholder: `https://mirror.stella-ops.org`)
|
||||
- "Test Connection" button → calls `POST /api/v1/mirror/test`
|
||||
- Connection result: green checkmark + latency OR red X + error message + remediation hint
|
||||
- On success: auto-fetch domain index via `POST /api/v1/mirror/consumer/discover`
|
||||
- Domain selector dropdown (populated from discovery, shows domain name + advisory count + staleness)
|
||||
- Index path override (advanced toggle, default `/concelier/exports/index.json`)
|
||||
- HTTP timeout slider (5-300 seconds, default 30)
|
||||
|
||||
**Step 2: Signature Verification**
|
||||
- Auto-detect: fetch JWS header from selected domain's bundle via `POST /api/v1/mirror/consumer/verify-signature`
|
||||
- Show detected algorithm + key ID (pre-populated if found)
|
||||
- Signature verification toggle (on/off)
|
||||
- If enabled: algorithm dropdown (ES256/ES384/ES512/RS256/RS384), key ID input, public key PEM textarea or file upload
|
||||
- "Verify Sample" button → download a small bundle chunk and verify signature
|
||||
- Status: "Signature valid" / "Signature invalid" / "No signature detected"
|
||||
|
||||
**Step 3: Sync Schedule & Caching**
|
||||
- Operating mode selector: Mirror (consumer only) / Hybrid (consumer + direct sources)
|
||||
- Sync schedule presets: Manual, Hourly, Every 4 hours, Daily, Weekly
|
||||
- Bundle caching toggle + cache TTL (hours, default 168)
|
||||
- Air-gap import section (collapsible):
|
||||
- "Import Bundle" button → file picker for bundle directory
|
||||
- Trust roots file upload
|
||||
- Checksum + DSSE verification toggles
|
||||
|
||||
**Step 4: Review & Activate**
|
||||
- Summary card: mirror URL, domain, mode, signature status, sync schedule
|
||||
- Pre-flight checks (auto-run):
|
||||
- Mirror reachable
|
||||
- Domain exists in index
|
||||
- Signature valid (if enabled)
|
||||
- Current sources that will be superseded listed
|
||||
- "Activate Mirror Consumer" button → `PUT /api/v1/mirror/consumer` + `PUT /api/v1/mirror/config` (set mode)
|
||||
- Success state: "Mirror consumer activated. First sync in X seconds." + link to dashboard
|
||||
|
||||
**Route**: `advisory-vex-sources/mirror/client-setup` (lazy-loaded)
|
||||
|
||||
Completion criteria:
|
||||
- [ ] 4-step wizard component created (standalone, OnPush, signals)
|
||||
- [ ] Connection testing with real-time feedback
|
||||
- [ ] Domain discovery and selection from mirror index
|
||||
- [ ] Signature auto-detection and manual configuration
|
||||
- [ ] Mode selection and sync schedule
|
||||
- [ ] Air-gap bundle import section
|
||||
- [ ] Pre-flight validation before activation
|
||||
- [ ] Route wired in integration-hub.routes.ts
|
||||
|
||||
### MCS-003 - Wire mirror client setup into dashboard and catalog
|
||||
Status: DONE
|
||||
Dependency: MCS-002
|
||||
Owners: Developer (FE)
|
||||
Task description:
|
||||
- Update the mirror dashboard and catalog to link to the client setup wizard.
|
||||
|
||||
**Files to modify**:
|
||||
- `mirror-dashboard.component.ts`:
|
||||
- In the consumer panel: add "Configure" button → navigates to wizard
|
||||
- When mode is Direct: show "Switch to Mirror" CTA → navigates to wizard
|
||||
- When no consumer URL configured: show setup prompt instead of empty status
|
||||
- `advisory-source-catalog.component.ts`:
|
||||
- In mirror header: add "Connect to Mirror" button alongside "Configure Mirror"
|
||||
- When mode is Mirror/Hybrid: show consumer URL + sync status in header stats
|
||||
|
||||
Completion criteria:
|
||||
- [x] Dashboard consumer panel has "Configure" button
|
||||
- [x] Direct mode shows "Switch to Mirror" CTA
|
||||
- [x] Catalog header shows "Connect to Mirror" option
|
||||
- [x] Consumer status visible in catalog stats when in Mirror/Hybrid mode
|
||||
|
||||
### MCS-004 - Air-gap bundle import API endpoint
|
||||
Status: DONE
|
||||
Dependency: none (parallel)
|
||||
Owners: Developer (Backend)
|
||||
Task description:
|
||||
- Expose `MirrorBundleImportService` functionality via HTTP API so the wizard can trigger imports from the UI, not just CLI.
|
||||
|
||||
**Endpoint**:
|
||||
| Method | Path | Purpose |
|
||||
|--------|------|---------|
|
||||
| POST | `/api/v1/mirror/import` | Import a mirror bundle from a specified local path |
|
||||
| GET | `/api/v1/mirror/import/status` | Get status of last import (progress, result) |
|
||||
|
||||
**Request**: `{ bundlePath, verifyChecksums: true, verifyDsse: true, trustRootsPath? }`
|
||||
**Response**: `{ success, exportsImported, totalSize, errors[], warnings[] }`
|
||||
|
||||
Read `src/Cli/StellaOps.Cli/Services/MirrorBundleImportService.cs` to understand the import logic, then expose it as an API.
|
||||
|
||||
Completion criteria:
|
||||
- [x] Import endpoint accepts local path and triggers import
|
||||
- [x] Status endpoint reports progress/result
|
||||
- [x] Checksum and DSSE verification configurable per request
|
||||
- [x] Error details returned for failed imports
|
||||
|
||||
### MCS-005 - Playwright E2E tests for mirror client setup
|
||||
Status: DONE
|
||||
Dependency: MCS-002, MCS-003
|
||||
Owners: QA, Test Automation
|
||||
Task description:
|
||||
- Create E2E tests for the mirror client setup wizard with mocked API responses.
|
||||
|
||||
**File to create**: `src/Web/StellaOps.Web/e2e/mirror-client-setup.e2e.spec.ts`
|
||||
|
||||
**Test scenarios**:
|
||||
1. Wizard renders with 4 steps and step navigation works
|
||||
2. Connection test shows success/failure feedback with mocked mirror/test response
|
||||
3. Domain discovery populates dropdown from mocked index
|
||||
4. Signature auto-detection pre-fills algorithm and key ID
|
||||
5. Mode selection switches between Mirror and Hybrid
|
||||
6. Pre-flight checks all pass before activation
|
||||
7. Dashboard shows "Configure" button in consumer panel
|
||||
8. Catalog header shows "Connect to Mirror" when in Direct mode
|
||||
9. Air-gap import section triggers import endpoint
|
||||
|
||||
Completion criteria:
|
||||
- [x] 9 test scenarios with mocked API
|
||||
- [x] Tests cover happy path and error states
|
||||
- [x] Tests verify navigation between wizard and dashboard
|
||||
|
||||
### MCS-006 - Documentation update
|
||||
Status: DONE
|
||||
Dependency: MCS-001 through MCS-005
|
||||
Owners: Documentation author
|
||||
Task description:
|
||||
- Update mirror operations docs with the new UI-based client setup flow.
|
||||
|
||||
**Files to update**:
|
||||
- `docs/modules/concelier/operations/mirror.md` — add "Setting up as Mirror Consumer (UI)" section
|
||||
- `docs/modules/concelier/architecture.md` — mention consumer API endpoints
|
||||
- Add consumer setup screenshots or step descriptions
|
||||
|
||||
Completion criteria:
|
||||
- [x] Mirror docs include UI-based consumer setup instructions
|
||||
- [x] Env var and UI configuration paths both documented
|
||||
- [x] Air-gap import documented for both CLI and UI
|
||||
|
||||
---
|
||||
|
||||
## Execution Log
|
||||
| Date (UTC) | Update | Owner |
|
||||
| --- | --- | --- |
|
||||
| 2026-03-15 | Sprint created after investigation revealed mirror client/consumer backend exists but has no UI setup wizard. | Planning |
|
||||
| 2026-03-15 | MCS-002 DONE: Created mirror-client-setup.component.ts (4-step wizard), extended mirror-management.api.ts with consumer DTOs + 5 new API methods, wired route at advisory-vex-sources/mirror/client-setup. | Developer (FE) |
|
||||
| 2026-03-15 | MCS-005 DONE: Created `src/Web/StellaOps.Web/e2e/mirror-client-setup.e2e.spec.ts` with 9 test scenarios covering wizard rendering, connection test success/failure, domain discovery, signature auto-detection, mode selection, pre-flight checks, dashboard Configure button, and catalog Connect to Mirror button. All tests use mocked API responses following existing E2E patterns (auth fixture, navigateAndWait helper, page.route mocking). | QA |
|
||||
| 2026-03-15 | MCS-001 DONE: Added 4 consumer endpoints (GET/PUT /consumer, POST /consumer/discover, POST /consumer/verify-signature), IMirrorConsumerConfigStore interface, in-memory implementation, DI wiring, MirrorConsumer HttpClient. | Developer (Backend) |
|
||||
| 2026-03-15 | MCS-003 DONE: mirror-dashboard.component.ts — added Configure button in consumer panel header, setup prompt when no consumer URL, Switch to Mirror CTA card for Direct mode with showDirectModeCta computed signal. advisory-source-catalog.component.ts — added Connect to Mirror link in mirror context header, consumer URL + last sync stats for Mirror/Hybrid mode via isConsumerMode computed signal. | Developer (FE) |
|
||||
| 2026-03-15 | MCS-004 DONE: Added POST /api/v1/mirror/import and GET /api/v1/mirror/import/status endpoints to MirrorDomainManagementEndpointExtensions.cs. Import runs async with manifest parsing, SHA256 checksum verification, DSSE detection, artifact copy to local data store. Added IMirrorBundleImportStore interface, implemented in InMemoryMirrorDomainStore, wired DI in Program.cs. Extended mirror-management.api.ts with importBundle() and getImportStatus() methods + DTOs. | Developer (Backend + FE) |
|
||||
| 2026-03-15 | MCS-006 DONE: Updated `docs/modules/concelier/operations/mirror.md` with new section 8 "Setting up as Mirror Consumer (UI)" covering 4-step wizard flow, wizard-vs-env-var comparison table, air-gap bundle import for both CLI and UI. Updated `docs/modules/concelier/architecture.md` REST API section with 6 new endpoints (GET/PUT /consumer, POST /consumer/discover, POST /consumer/verify-signature, POST /import, GET /import/status). Added cross-reference in `docs/operations/airgap-operations-runbook.md` section 2.4 pointing to the UI import alternative. | Documentation author |
|
||||
|
||||
## Decisions & Risks
|
||||
- The `StellaOpsMirrorConnector` plugin already handles fetch/parse/map jobs. The wizard configures it, not replaces it.
|
||||
- Consumer config is initially in-memory (like mirror domain config). DB persistence can follow when the config store gets a database backend.
|
||||
- Air-gap import via HTTP is a convenience — the CLI path remains the primary offline method. The API endpoint operates on local filesystem paths, not file uploads.
|
||||
- Signature verification is optional but strongly recommended. The wizard should default to "enabled" when a signed bundle is detected.
|
||||
- Mode switching from Direct → Mirror disables direct source fetching. The wizard must warn about this. Hybrid mode keeps both active.
|
||||
|
||||
## Next Checkpoints
|
||||
- **Checkpoint 1**: MCS-001 — Consumer API endpoints operational
|
||||
- **Checkpoint 2**: MCS-002 — Wizard functional end-to-end
|
||||
- **Checkpoint 3**: MCS-003 — Dashboard and catalog integration
|
||||
- **Checkpoint 4**: MCS-005 — E2E tests passing
|
||||
- **Checkpoint 5**: MCS-006 — Docs updated
|
||||
Reference in New Issue
Block a user