chore(docs+devops): cross-module doc sync + sprint archival moves + compose updates

Bundled pre-session doc + ops work:
- docs/modules/**: sync across advisory-ai, airgap, cli, excititor,
  export-center, findings-ledger, notifier, notify, platform, router,
  sbom-service, ui, web (architectural + operational updates)
- docs/features/**: updates to checked excititor vex pipeline,
  developer workspace, quick verify drawer
- docs top-level: README, quickstart, API_CLI_REFERENCE, UI_GUIDE,
  code-of-conduct/TESTING_PRACTICES updates
- docs/qa/feature-checks/: FLOW.md + excititor state update
- docs/implplan/: remaining sprint updates + new Concelier source
  credentials sprint (SPRINT_20260422_003)
- docs-archived/implplan/: 30 sprint archival moves (ElkSharp series,
  misc completed sprints)
- devops/compose: .env + services compose + env example + router gateway
  config updates

File-level granularity preserved.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
master
2026-04-22 16:06:39 +03:00
parent ad77711ac2
commit 7943cfb3af
121 changed files with 10483 additions and 387 deletions

View File

@@ -0,0 +1,117 @@
# Console UI QA Strategy
## Goal
- Produce QA work that proves Stella Ops can be operated to release with confidence.
- Focus downstream agents on route truth, tab truth, evidence linkage, and corrective-action handoffs instead of generic visual review.
- Turn runtime findings into concrete test and fix work under `src/Web/StellaOps.Web/`.
## Required Reading
- `docs/product/release-with-confidence-product-card.md`
- `docs/qa/console-ui-traversal-map.md`
- `docs/qa/feature-checks/FLOW.md`
- `docs/UI_GUIDE.md`
- `src/Web/AGENTS.md`
## Preconditions
1. Start the Web app and required local services before any UI verification.
2. Use authenticated QA sessions. For local-source passes, seed the persisted auth keys used by `AuthSessionStore`:
- `stellaops.auth.session.full`
- `stellaops.auth.session.info`
- `stellaops:wasEverAuth`
3. Do not rely on `window.__stellaopsTestSession` as the only bootstrap path. The current live guard contract is storage-based.
4. If running against the live frontdoor instead of the local source server, export `STELLAOPS_FRONTDOOR_PASSWORD` or `STELLAOPS_ADMIN_PASS` before starting the run.
5. Do not write transient Playwright output into a watched Angular source path during a live `ng serve` pass unless rebuild churn is acceptable. Prefer a temp directory or write once after the traversal completes.
## What Counts As A Pass
- The route lands on the correct canonical page or canonical child route.
- The page clearly states what surface the operator is on.
- The page preserves release, evidence, policy, or admin context instead of silently collapsing into another workspace.
- Every visible tab lands on a truthful state with distinct route or content identity.
- Empty states tell the operator what is missing and what action to take next.
- Primary CTAs lead to the owning corrective workflow.
## What Counts As A Failure
- Redirects that lose authority, tenant, or base-url context.
- Evidence routes that silently become unrelated Ops pages without preserving evidence identity.
- Pages with no stable page identity in the main surface.
- Tabs that render but do not change route or state in a way the operator can understand.
- Placeholder or empty content presented without an explanation of what data or action is missing.
- Broken admin or setup handoffs that prevent the operator from reaching the owning page.
## Execution Order
1. Resolve active route and redirect defects first.
2. Verify Release Control and Release Policies next.
3. Verify Security next.
4. Verify Evidence and Ops next.
5. Verify Setup and Admin last.
This order is intentional. A polished admin page does not compensate for ambiguous release, policy, or evidence truth.
## Route-Family Checks
### Release Control
| Entry route | Seek for | Required interactions | Failure signals |
| --- | --- | --- | --- |
| `/environments/overview` | clear environment readiness ownership | load page, verify the main panel is not just nav chrome, check whether topology or readiness content exists | missing top-level page identity or only shell text |
| `/releases` | release list anchored to versions or bundles | verify sort and filter chips, empty-state truth, drill into release identity when possible | page title only, no release context in main panel |
| `/releases/deployments` | deployment state and approval queue visibility | switch visible state filters, confirm counts and state labels remain coherent | filters that do not change visible state or route |
| `/releases/bundles` | digest-first bundle identity and validation context | verify bundle states, digest-oriented copy, and bundle creation handoff if present | tag-first copy or missing digest and evidence context |
| `/releases/promotions` | promotion queue and readiness | verify page state and empty-state guidance | generic list shell without promotion meaning |
| `/releases/approvals` | approvals segmented by decision state | click all tabs: Pending, Approved, Rejected, Expiring, My Team | tabs render but do not change state or route |
### Release Policies
| Entry route | Seek for | Required interactions | Failure signals |
| --- | --- | --- | --- |
| `/ops/policy/packs` | release policy entry surface | confirm the page has main-panel identity and is not only nav chrome | title exists but no main-panel page identity |
| `/ops/policy/governance` | governance ownership | click Governance, VEX & Exceptions, Simulation, Audit; confirm route changes and headings follow | cross-links present but content stays ambiguous |
| `/ops/policy/vex` | VEX conflict and exception truth | click local VEX tabs such as Search, Stats, Consensus, Explorer, Conflicts, Exceptions | VEX surface lacks distinct page state or operator action |
| `/ops/policy/simulation` | what-if and promotion-gate simulation | click Shadow Mode, Promotion Gate, Test & Validate, Pre-Promotion Review, Effective Policies, Exceptions | simulation tabs do not expose a reviewable scenario or result state |
### Security
| Entry route | Seek for | Required interactions | Failure signals |
| --- | --- | --- | --- |
| `/security/images` | security posture attached to a release or image selection | click Summary, Findings, SBOM, Reachability, VEX, Evidence | tabs break context or the empty state hides what must be selected |
| `/security/risk` | risk budget and verdict truth | verify Current Verdict, Side-by-Side Risk Diff, Exception Workflow | metrics or exceptions render as placeholders without explanation |
| `/security/advisory-sources` | source freshness and feed ownership | confirm the page has page-level identity and feed-specific actions or state | route title only, no main-panel identity |
| `/triage/artifacts` | vulnerability triage work surface | confirm page identity, queue or state controls, and drill-in affordances | route resolves but only shell text is present |
### Evidence
| Entry route | Seek for | Required interactions | Failure signals |
| --- | --- | --- | --- |
| `/evidence/overview` | evidence-specific landing page | confirm whether aliasing to Ops > Audit is intentional and understandable to an operator | silent collapse into Audit with no Evidence identity |
| `/evidence/audit-log` | audit-event search and log review | exercise search and pagination controls if available | search and log surface lacks audit identity |
| `/evidence/verify-replay` | replay request, replay queue, quick verify | click visible replay controls, confirm mismatch and empty-state copy is truthful | replay surface exists but offers no actionable next step |
| `/evidence/exports` | export ownership and workflow | verify page identity and export actions | route title only, no export-specific surface |
| `/evidence/capsules` | proof-bundle and capsule ownership | confirm whether this intentionally maps to Audit > Bundles or incorrectly loses capsule identity | route lands in Audit with no capsule language |
### Ops
| Entry route | Seek for | Required interactions | Failure signals |
| --- | --- | --- | --- |
| `/ops/operations/jobengine` | execution control plane | click Runs, Schedules, Workers and verify state changes | tabs render but do not alter the visible slice |
| `/ops/operations/feeds-airgap` | feed and offline readiness | verify the page is not mislabeled as generic dashboard content | "About this page" points to the wrong workspace or no feed identity exists |
| `/ops/operations/doctor` | diagnostics ownership | confirm service-health and drift checks appear in the main panel | title exists but no diagnostic identity or actions |
| `/ops/operations/audit` | audit workspace | click All Events, Timeline, Correlations, Exports, Bundles | tabs do not preserve audit context |
| `/ops/scripts` | operator scripts and filtering | exercise visible language and visibility filters | filters do not affect state or are mislabeled |
### Setup And Admin
| Entry route | Seek for | Required interactions | Failure signals |
| --- | --- | --- | --- |
| `/setup` | setup workspace overview | verify each tile links to the owning setup route | setup overview lists areas but handoffs are broken |
| `/setup/integrations` | integration ownership | confirm page identity and integration-specific actions | route title only, no integration surface |
| `/setup/trust-signing` | trust and signing canonical child route | click Signing Keys, Trusted Issuers, Certificates, Audit | keys child route is fine, but parent trust identity must remain obvious |
| `/setup/identity-providers` | identity-provider CRUD surface | verify list and create affordances | page lands but cannot express current state or next step |
| `/setup/tenant-branding` | tenant and branding ownership | confirm page identity and editable controls | route title only, no branding-specific surface |
| `/console-admin/*` | admin deep links | verify redirects keep the correct origin and page ownership | redirects drop the port or base URL or land on the wrong setup page |
## Retained Automation Requirements
- Any manual route or tab discovered during QA must become retained Playwright coverage before the feature area is considered stable.
- New or corrected tests must follow the current route contract, not the retired standalone Evidence sidebar expectation.
- Admin-route coverage must explicitly assert the final URL origin so port-dropping redirects are caught.
- Evidence-route coverage must assert whether a route is intentionally aliased or whether it must preserve standalone Evidence identity.
## Downstream Sprint Split
- `SPRINT_20260421_005_FE_console_route_identity_and_redirect_truth.md`
- `SPRINT_20260421_006_FE_release_and_security_console_behavioral_qa.md`
- `SPRINT_20260421_007_FE_evidence_ops_setup_admin_console_behavioral_qa.md`
These sprints are intentionally small enough that another agent can verify and fix within `src/Web/StellaOps.Web/` without re-deriving the product model.

View File

@@ -0,0 +1,87 @@
# Console UI Traversal Map
## Purpose
- Translate the approved "release with confidence" product framing into the current Stella Ops Console surface.
- Give QA and implementers a route-by-route map of what must be traversed, what is only an alias, and what already looks weak or broken.
- Keep the next pass grounded in runtime truth, not in older navigation specs or planned-only screen inventories.
## Evidence Base
- Product framing: `docs/product/release-with-confidence-product-card.md`
- Route ownership: `src/Web/StellaOps.Web/src/app/app.routes.ts`
- Sidebar ownership model: `src/Web/StellaOps.Web/src/app/core/navigation/navigation.config.ts`
- Runtime evidence: authenticated local-source sweep captured on 2026-04-21 in `src/Web/StellaOps.Web/output/playwright/console-surface-scan.json`
## Product Standard
- Stella is not a generic dashboard collection. The Console exists to answer: what is being released, why it is safe enough, what evidence backs that decision, and what action an operator should take next.
- A Console page is only acceptable when it preserves release/evidence context, makes ownership clear, and exposes truthful next actions.
- Hidden uncertainty, ambiguous aliases, and page shells with weak identity are product defects because they increase operator error under release pressure.
## Canonical Surface
| Family | Canonical entry routes | Tabs or route variants observed | What the page family must prove |
| --- | --- | --- | --- |
| Home | `/` | none captured in the sweep | Daily operating state and the first truthful next action. |
| Release Control | `/environments/overview`, `/releases`, `/releases/deployments`, `/releases/bundles`, `/releases/promotions`, `/releases/approvals` | `/releases/approvals` tabs: Pending, Approved, Rejected, Expiring, My Team | Release identity, promotion state, approval state, and bundle truth. |
| Release Policies | `/ops/policy/packs`, `/ops/policy/governance`, `/ops/policy/vex`, `/ops/policy/simulation` | Shared policy tabs: Release Policies, Governance, VEX & Exceptions, Simulation, Audit. Additional VEX and Simulation local tabs are visible. | Policy gates, VEX conflict handling, simulation, and auditability of release decisions. |
| Security | `/security/images`, `/security/risk`, `/security/advisory-sources`, `/triage/artifacts` | `/security/images/*` tabs: Summary, Findings, SBOM, Reachability, VEX, Evidence | Security posture must stay attached to release truth and evidence, not float as disconnected findings. |
| Evidence | `/evidence/overview`, `/evidence/audit-log`, `/evidence/verify-replay`, `/evidence/exports`, `/evidence/capsules` | Audit-style tabs observed on `/evidence/overview` and `/evidence/capsules`: All Events, Timeline, Correlations, Exports, Bundles. Replay tabs observed on `/evidence/verify-replay`. | Evidence lookup, replay, export, and proof packaging for audit and re-verification. |
| Ops | `/ops/operations/jobengine`, `/ops/operations/feeds-airgap`, `/ops/operations/doctor`, `/ops/scripts`, `/ops/operations/audit` | JobEngine tabs: Runs, Schedules, Workers. Audit tabs: All Events, Timeline, Correlations, Exports, Bundles | Operator workflows, execution health, feed freshness, and background control-plane truth. |
| Setup and Admin | `/setup`, `/setup/integrations`, `/setup/trust-signing`, `/setup/identity-providers`, `/setup/tenant-branding`, `/console-admin/*` | Trust Signing tabs: Signing Keys, Trusted Issuers, Certificates, Audit | Identity, trust, integrations, branding, and admin controls that let the Console be safely operated. |
## Current Route And Handoff Findings
### Stable, route-backed surfaces from the 2026-04-21 pass
- `/releases`, `/releases/deployments`, `/releases/bundles`, `/releases/promotions`, and `/releases/approvals` all rendered with stable titles and page-specific headings.
- `/ops/policy/governance`, `/ops/policy/vex`, and `/ops/policy/simulation` rendered as a coherent tab family and visibly cross-linked to sibling routes.
- `/security/images/summary` rendered with the expected security tabs and explicit empty-state guidance telling the operator to select a release.
- `/evidence/verify-replay` rendered a distinct replay surface with headings for replay request and determinism verification.
- `/ops/operations/jobengine`, `/ops/operations/audit`, `/ops/scripts`, `/setup`, `/setup/trust-signing`, and `/setup/identity-providers` rendered distinct route-backed surfaces with recognizable titles.
### Alias and ownership behavior that QA must treat carefully
- `/security/images` canonicalizes to `/security/images/summary`. That is acceptable if the page identity remains "Image Security" and the tabs preserve the security evidence context.
- `/setup/trust-signing` canonicalizes to `/setup/trust-signing/keys`. That is acceptable if the page identity remains trust and signing, not just "keys".
- `/evidence/overview` currently lands on `/ops/operations/audit`.
- `/evidence/capsules` currently lands on `/ops/operations/audit?tab=all-events`.
- Those Evidence-to-Audit collapses may be intentional consolidation, but today they weaken the standalone Evidence surface and must be reviewed against product intent.
### Weak identity surfaces from the current runtime pass
- `/`
- `/environments/overview`
- `/ops/policy/packs`
- `/security/advisory-sources`
- `/triage/artifacts`
- `/evidence/exports`
- `/ops/operations/feeds-airgap`
- `/ops/operations/doctor`
- `/setup/integrations`
- `/setup/tenant-branding`
These routes resolved and often had route titles, but the automated pass extracted little or no page-level heading/CTA identity from the main surface. In the next QA pass, treat them as "weak identity" pages and verify whether the problem is:
- truly missing page identity,
- card-based content without a stable top-level heading,
- lazy-loading or state timing,
- or a page shell that is present but not communicating ownership clearly enough.
### Confirmed route defect
- `curl -k -I https://127.0.0.1:4400/console-admin/tenants` returned `302 Found` with `location: https://127.0.0.1/console-admin/tenants`.
- The redirect drops the dev-server port. Browser navigation then fails with `net::ERR_CONNECTION_REFUSED`.
- Treat `/console-admin/*` and `/console/admin/*` as an active route defect in local-source verification until the redirect/base-url behavior is fixed.
### Harness caveat that affects future QA
- The comment in `src/Web/StellaOps.Web/e2e/fixtures/auth.fixture.ts` says the app reads `window.__stellaopsTestSession` during bootstrap.
- In the current app, the auth guard trusts `AuthSessionStore`, which restores from the persisted session keys `stellaops.auth.session.full`, `stellaops.auth.session.info`, and the `stellaops:wasEverAuth` latch.
- Local-source QA should seed the real persisted session keys. Do not rely on the outdated fixture comment as the source of truth.
### Stale spec caveat
- Older E2E navigation expectations still assume a standalone Evidence sidebar group.
- The current navigation config intentionally routes Evidence contextually and consolidates audit entry under Ops.
- Any future UI regression claims must be judged against the current navigation contract, not against the retired sidebar grouping.
## Next-Pass Traversal Order
1. Release Control and Release Policies
2. Security
3. Evidence
4. Ops
5. Setup and Admin
This order matches product risk. Release truth and policy truth come first, because those surfaces determine whether Stella can release with confidence at all.

View File

@@ -178,7 +178,8 @@ the described behavior.
2. Run `dotnet build <project>.csproj` and capture output
3. Run the targeted tests and confirm the filter actually executes the intended subset.
- For VSTest-style projects where filtering works normally, use `dotnet test <test-project>.csproj --filter <relevant-filter>`.
- For xUnit v3 projects running under Microsoft Testing Platform, do **not** rely on `dotnet test --filter`; use `scripts/test-targeted-xunit.ps1` or direct `dotnet exec <test-dll> -method/-class/...` instead.
- For xUnit v3 projects running under Microsoft Testing Platform, do **not** rely on `dotnet test --filter`; use `scripts/test-targeted-xunit.ps1` instead. Invoke the helper with `pwsh` on PowerShell 7 hosts or `powershell -ExecutionPolicy Bypass -File` on Windows PowerShell hosts.
- The helper auto-selects `dotnet exec <test-dll>` for standard library-style assemblies and `dotnet run --project <test-project> -- ...` for ASP.NET host tests that reference `Microsoft.AspNetCore.Mvc.Testing`. If you bypass the helper, preserve that same distinction.
4. For Angular/frontend features: run `npx ng build` and `npx ng test` for the relevant library/app
5. **Code review** (CRITICAL): Read the key source files and verify:
- The classes/methods described in the feature file actually contain the logic claimed
@@ -368,14 +369,14 @@ integration tests** or **behavioral unit tests** that prove the feature logic:
1. Identify tests that specifically exercise the feature's behavior
2. Run those tests using a targeting path that actually filters the assembly:
- VSTest-compatible path: `dotnet test <test-project>.csproj --filter "FullyQualifiedName~FeatureClassName"`
- xUnit v3 / Microsoft Testing Platform path: `pwsh ./scripts/test-targeted-xunit.ps1 -Project <test-project>.csproj -Class "<fully.qualified.class>"`
- xUnit v3 / Microsoft Testing Platform path: `pwsh ./scripts/test-targeted-xunit.ps1 -Project <test-project>.csproj -Class "<fully.qualified.class>"` or `powershell -ExecutionPolicy Bypass -File .\scripts\test-targeted-xunit.ps1 -Project <test-project>.csproj -Class "<fully.qualified.class>"`
3. Read the test code to confirm it asserts meaningful behavior (not just "compiles")
4. If no behavioral tests exist, write a focused test and run it
**Example for `evidence-weighted-score-model`**:
```bash
pwsh ./scripts/test-targeted-xunit.ps1 \
-Project src/Policy/__Tests/StellaOps.Policy.Engine.Tests/StellaOps.Policy.Engine.Tests.csproj \
```powershell
powershell -ExecutionPolicy Bypass -File .\scripts\test-targeted-xunit.ps1 `
-Project src/Policy/__Tests/StellaOps.Policy.Engine.Tests/StellaOps.Policy.Engine.Tests.csproj `
-Class "StellaOps.Policy.Engine.Tests.Scoring.EwsCalculatorTests"
# Verify: normalizers produce expected dimension scores
# Verify: guardrails cap/floor scores correctly

View File

@@ -0,0 +1,47 @@
{
"type": "source",
"capturedAtUtc": "2026-04-22T07:40:37.2236785Z",
"featureFile": "docs/features/checked/excititor/vex-source-registration-and-verification-pipeline.md",
"filesChecked": [
"src/Concelier/StellaOps.Excititor.Worker/Scheduling/VexWorkerHostedService.cs",
"src/Concelier/StellaOps.Excititor.Worker/Scheduling/DefaultVexProviderRunner.cs",
"src/Concelier/StellaOps.Excititor.Worker/Orchestration/OrchestratorVexProviderRunner.cs",
"src/Concelier/StellaOps.Excititor.Worker/Orchestration/VexWorkerOrchestratorClient.cs",
"src/Concelier/StellaOps.Excititor.Worker/Orchestration/VexWorkerHeartbeatService.cs",
"src/Concelier/StellaOps.Excititor.Worker/Plugins/VexWorkerPluginCatalogLoader.cs",
"src/Concelier/StellaOps.Excititor.Worker/Signature/WorkerSignatureVerifier.cs",
"src/Concelier/StellaOps.Excititor.Worker/Scheduling/VexWorkerSchedule.cs",
"src/Concelier/StellaOps.Excititor.WebService/Endpoints/MirrorRegistrationEndpoints.cs",
"src/Concelier/__Libraries/StellaOps.Excititor.Connectors.Abstractions/VexConnectorBase.cs",
"src/Concelier/__Libraries/StellaOps.Excititor.Connectors.Abstractions/VexConnectorDescriptor.cs",
"src/Concelier/__Libraries/StellaOps.Excititor.Connectors.Cisco.CSAF/CiscoCsafConnector.cs",
"src/Concelier/__Tests/StellaOps.Excititor.Worker.Tests/Orchestration/VexWorkerOrchestratorClientTests.cs",
"src/Concelier/__Tests/StellaOps.Excititor.Connectors.Cisco.CSAF.Tests/Connectors/CiscoCsafConnectorTests.cs"
],
"found": [
"src/Concelier/StellaOps.Excititor.Worker/Scheduling/VexWorkerHostedService.cs",
"src/Concelier/StellaOps.Excititor.Worker/Scheduling/DefaultVexProviderRunner.cs",
"src/Concelier/StellaOps.Excititor.Worker/Orchestration/OrchestratorVexProviderRunner.cs",
"src/Concelier/StellaOps.Excititor.Worker/Orchestration/VexWorkerOrchestratorClient.cs",
"src/Concelier/StellaOps.Excititor.Worker/Orchestration/VexWorkerHeartbeatService.cs",
"src/Concelier/StellaOps.Excititor.Worker/Plugins/VexWorkerPluginCatalogLoader.cs",
"src/Concelier/StellaOps.Excititor.Worker/Signature/WorkerSignatureVerifier.cs",
"src/Concelier/StellaOps.Excititor.Worker/Scheduling/VexWorkerSchedule.cs",
"src/Concelier/StellaOps.Excititor.WebService/Endpoints/MirrorRegistrationEndpoints.cs",
"src/Concelier/__Libraries/StellaOps.Excititor.Connectors.Abstractions/VexConnectorBase.cs",
"src/Concelier/__Libraries/StellaOps.Excititor.Connectors.Abstractions/VexConnectorDescriptor.cs",
"src/Concelier/__Libraries/StellaOps.Excititor.Connectors.Cisco.CSAF/CiscoCsafConnector.cs",
"src/Concelier/__Tests/StellaOps.Excititor.Worker.Tests/Orchestration/VexWorkerOrchestratorClientTests.cs",
"src/Concelier/__Tests/StellaOps.Excititor.Connectors.Cisco.CSAF.Tests/Connectors/CiscoCsafConnectorTests.cs"
],
"missing": [],
"legacyReferencedPathsMissing": [
"src/Excititor/StellaOps.Excititor.Worker/Scheduling/VexWorkerHostedService.cs",
"src/Excititor/__Libraries/StellaOps.Excititor.Connectors.Abstractions/VexConnectorBase.cs"
],
"verdict": "pass",
"notes": [
"Current source of truth for the VEX worker and connector runtime is under src/Concelier/...",
"The checked feature file still carried legacy src/Excititor/... paths from run-001 and was normalized as part of run-002."
]
}

View File

@@ -0,0 +1,56 @@
{
"type": "build-and-targeted-tests",
"capturedAtUtc": "2026-04-22T07:41:30Z",
"project": "src/Concelier/StellaOps.Excititor.Worker/StellaOps.Excititor.Worker.csproj",
"build": {
"command": "dotnet build \"src/Concelier/StellaOps.Excititor.Worker/StellaOps.Excititor.Worker.csproj\" --nologo -v minimal",
"result": "pass",
"warnings": 0,
"errors": 0,
"outputSnippet": [
"Build succeeded.",
"0 Warning(s)",
"0 Error(s)",
"Time Elapsed 00:00:14.24"
]
},
"targetedRuns": [
{
"runner": "scripts/test-targeted-xunit.ps1",
"project": "src/Concelier/__Tests/StellaOps.Excititor.Connectors.Cisco.CSAF.Tests/StellaOps.Excititor.Connectors.Cisco.CSAF.Tests.csproj",
"class": "StellaOps.Excititor.Connectors.Cisco.CSAF.Tests.Connectors.CiscoCsafConnectorTests",
"command": "powershell -ExecutionPolicy Bypass -File .\\scripts\\test-targeted-xunit.ps1 -Project \"src/Concelier/__Tests/StellaOps.Excititor.Connectors.Cisco.CSAF.Tests/StellaOps.Excititor.Connectors.Cisco.CSAF.Tests.csproj\" -Class \"StellaOps.Excititor.Connectors.Cisco.CSAF.Tests.Connectors.CiscoCsafConnectorTests\"",
"testsRun": 8,
"testsPassed": 8,
"testsFailed": 0,
"outputSnippet": [
"Build succeeded.",
"Total: 8, Errors: 0, Failed: 0, Skipped: 0, Not Run: 0, Time: 6.570s",
"FetchAsync_IncrementalChangesBackfill_CheckpointsForbiddenTimestampedDocumentsAndContinues",
"FetchAsync_IndexFallback_BootstrapSkipsForbiddenDocumentsAndContinues",
"FetchAsync_InitialChangesBackfill_UsesPathCheckpointAcrossBoundedRuns"
]
},
{
"runner": "scripts/test-targeted-xunit.ps1",
"project": "src/Concelier/__Tests/StellaOps.Excititor.Worker.Tests/StellaOps.Excititor.Worker.Tests.csproj",
"class": "StellaOps.Excititor.Worker.Tests.Orchestration.VexWorkerOrchestratorClientTests",
"command": "powershell -ExecutionPolicy Bypass -File .\\scripts\\test-targeted-xunit.ps1 -Project \"src/Concelier/__Tests/StellaOps.Excititor.Worker.Tests/StellaOps.Excititor.Worker.Tests.csproj\" -Class \"StellaOps.Excititor.Worker.Tests.Orchestration.VexWorkerOrchestratorClientTests\"",
"testsRun": 10,
"testsPassed": 10,
"testsFailed": 0,
"outputSnippet": [
"Build succeeded.",
"Total: 10, Errors: 0, Failed: 0, Skipped: 0, Not Run: 0, Time: 0.294s",
"CompleteJobAsync_PreservesConnectorManagedLastUpdated",
"CompleteJobAsync_UpdatesStateWithResults",
"SendHeartbeatAsync_UpdatesConnectorState"
]
}
],
"verdict": "pass",
"notes": [
"Targeted xUnit helper runs were used instead of solution filters so the requested classes were actually filtered and counted.",
"The Cisco class covers the anonymous 403 checkpoint regression path, and the worker class covers cursor preservation on successful job completion."
]
}

View File

@@ -0,0 +1,89 @@
{
"type": "integration",
"capturedAtUtc": "2026-04-22T07:42:44Z",
"providerId": "excititor:cisco",
"environment": {
"longLivedWorker": "stellaops-excititor-worker",
"disposableWorker": "stellaops-excititor-worker-cisco-qa-check",
"workerImage": "stellaops/excititor-worker:dev",
"databaseContainer": "stellaops-postgres"
},
"steps": [
{
"name": "long-lived-worker-health",
"command": "docker ps --filter name=stellaops-excititor-worker --format \"table {{.Names}}\\t{{.Status}}\\t{{.Image}}\"",
"result": "pass",
"evidence": [
"stellaops-excititor-worker Up 9 minutes (healthy) stellaops/excititor-worker:dev"
]
},
{
"name": "pre-run-state",
"command": "docker exec -i stellaops-postgres psql -U stellaops -d stellaops_platform -v ON_ERROR_STOP=1 -c \"SELECT connector_id, last_updated, array_length(document_digests,1) AS digests, COALESCE((SELECT COUNT(*) FROM jsonb_each(resume_tokens)),0) AS resume_tokens, next_eligible_run, failure_count FROM vex.connector_states WHERE connector_id = 'excititor:cisco';\"",
"result": "pass",
"state": {
"lastUpdated": "2026-04-22 07:25:53.884862+00",
"documentDigests": 4,
"resumeTokens": 1,
"nextEligibleRun": null,
"failureCount": 0
}
},
{
"name": "disposable-cisco-only-run",
"command": "docker compose -f devops/compose/docker-compose.stella-services.yml run --rm --no-deps -d --name stellaops-excititor-worker-cisco-qa-check -e Excititor__Worker__Providers__0__ProviderId=excititor:cisco -e Excititor__Worker__Providers__0__InitialDelay=00:00:00 -e Excititor__Worker__Providers__0__Interval=24:00:00 -e Excititor__Worker__Providers__0__Settings__MaxDocumentsPerFetch=2 -e Excititor__Worker__Providers__0__Settings__RequestDelay=00:00:00 excititor-worker",
"result": "pass",
"containerId": "86b49750fece2cce53fb3b053b83a6f5050d2c2c1c4d1c8fcd8922f2f6451878"
},
{
"name": "runtime-logs",
"command": "docker logs -f stellaops-excititor-worker-cisco-qa-check",
"result": "pass",
"runId": "eddb0e0b-26b1-4b9c-b08d-679413905795",
"evidence": [
"Provider excititor:cisco run started at 04/22/2026 07:42:38 +00:00",
"GET https://www.cisco.com/.well-known/csaf/provider-metadata.json -> 200",
"GET https://www.cisco.com/.well-known/csaf/index.json -> 404",
"GET https://www.cisco.com/.well-known/csaf/changes.csv -> 200",
"Cisco advisory change index https://www.cisco.com/.well-known/csaf/changes.csv yielded 2747 candidate advisory document(s).",
"Connector excititor:cisco persisted 0 raw document(s) this run.",
"Orchestrator job completed: runId=eddb0e0b-26b1-4b9c-b08d-679413905795 connector=excititor:cisco documents=0 claims=0 duration=00:00:01.6892442",
"Provider excititor:cisco run completed at 04/22/2026 07:42:41 +00:00"
]
},
{
"name": "post-run-state",
"command": "docker exec -i stellaops-postgres psql -U stellaops -d stellaops_platform -v ON_ERROR_STOP=1 -c \"SELECT connector_id, last_updated, array_length(document_digests,1) AS digests, COALESCE((SELECT COUNT(*) FROM jsonb_each(resume_tokens)),0) AS resume_tokens, next_eligible_run, failure_count FROM vex.connector_states WHERE connector_id = 'excititor:cisco'; SELECT provider_id, COUNT(*) AS docs FROM vex.vex_raw_documents WHERE provider_id = 'excititor:cisco' GROUP BY provider_id;\"",
"result": "pass",
"state": {
"lastUpdated": "2026-04-22 07:25:53.884862+00",
"documentDigests": 4,
"resumeTokens": 1,
"nextEligibleRun": null,
"failureCount": 0,
"rawDocuments": 4
},
"assertions": [
"last_updated remained unchanged across successful completion",
"failure_count stayed at 0",
"next_eligible_run remained null",
"raw document count stayed stable at 4"
]
},
{
"name": "cleanup",
"command": "docker stop stellaops-excititor-worker-cisco-qa-check",
"result": "pass",
"evidence": [
"stellaops-excititor-worker-cisco-qa-check"
]
}
],
"behaviorVerified": [
"Cisco worker fallback from index.json to changes.csv is healthy in the live environment.",
"Successful worker completion does not overwrite connector-managed LastUpdated.",
"Cisco connector remained out of backoff with next_eligible_run unset and failure_count equal to 0.",
"Anonymous 403 checkpoint handling was covered in the fresh targeted Cisco connector class run from the same QA cycle even though this live run did not encounter a new 403."
],
"verdict": "pass"
}

View File

@@ -0,0 +1,27 @@
{
"type": "source",
"capturedAtUtc": "2026-04-22T08:08:08.8206436Z",
"featureFile": "docs/features/checked/excititor/vex-source-registration-and-verification-pipeline.md",
"filesChecked": [
"src/Concelier/__Libraries/StellaOps.Excititor.Connectors.Oracle.CSAF/OracleCsafConnector.cs",
"src/Concelier/__Libraries/StellaOps.Excititor.Connectors.Oracle.CSAF/Configuration/OracleConnectorOptions.cs",
"src/Concelier/__Libraries/StellaOps.Excititor.Connectors.Oracle.CSAF/Metadata/OracleCatalogLoader.cs",
"src/Concelier/__Tests/StellaOps.Excititor.Connectors.Oracle.CSAF.Tests/Metadata/OracleCatalogLoaderTests.cs",
"src/Concelier/__Tests/StellaOps.Excititor.Connectors.Oracle.CSAF.Tests/Connectors/OracleCsafConnectorTests.cs",
"src/Concelier/StellaOps.Excititor.Worker/Options/BuiltInVexProviderDefaults.cs"
],
"found": [
"src/Concelier/__Libraries/StellaOps.Excititor.Connectors.Oracle.CSAF/OracleCsafConnector.cs",
"src/Concelier/__Libraries/StellaOps.Excititor.Connectors.Oracle.CSAF/Configuration/OracleConnectorOptions.cs",
"src/Concelier/__Libraries/StellaOps.Excititor.Connectors.Oracle.CSAF/Metadata/OracleCatalogLoader.cs",
"src/Concelier/__Tests/StellaOps.Excititor.Connectors.Oracle.CSAF.Tests/Metadata/OracleCatalogLoaderTests.cs",
"src/Concelier/__Tests/StellaOps.Excititor.Connectors.Oracle.CSAF.Tests/Connectors/OracleCsafConnectorTests.cs",
"src/Concelier/StellaOps.Excititor.Worker/Options/BuiltInVexProviderDefaults.cs"
],
"missing": [],
"verdict": "pass",
"notes": [
"The Oracle CSAF connector, its catalog loader, and the targeted Oracle test classes are present in the current src/Concelier layout.",
"BuiltInVexProviderDefaults still seeds excititor:oracle as one of the default public providers."
]
}

View File

@@ -0,0 +1,53 @@
{
"type": "build-and-targeted-tests",
"capturedAtUtc": "2026-04-22T08:07:05Z",
"project": "src/Concelier/__Tests/StellaOps.Excititor.Connectors.Oracle.CSAF.Tests/StellaOps.Excititor.Connectors.Oracle.CSAF.Tests.csproj",
"targetedRuns": [
{
"runner": "scripts/test-targeted-xunit.ps1",
"class": "StellaOps.Excititor.Connectors.Oracle.CSAF.Tests.Metadata.OracleCatalogLoaderTests",
"command": "powershell -ExecutionPolicy Bypass -File .\\scripts\\test-targeted-xunit.ps1 -Project \"src/Concelier/__Tests/StellaOps.Excititor.Connectors.Oracle.CSAF.Tests/StellaOps.Excititor.Connectors.Oracle.CSAF.Tests.csproj\" -Class \"StellaOps.Excititor.Connectors.Oracle.CSAF.Tests.Metadata.OracleCatalogLoaderTests\"",
"buildResult": "pass",
"warnings": 0,
"errors": 0,
"testsRun": 3,
"testsPassed": 3,
"testsFailed": 0,
"outputSnippet": [
"Build succeeded.",
"0 Warning(s)",
"0 Error(s)",
"Total: 3, Errors: 0, Failed: 0, Skipped: 0, Not Run: 0, Time: 0.400s",
"LoadAsync_FetchesAndCachesCatalog",
"LoadAsync_UsesOfflineSnapshotWhenNetworkFails",
"LoadAsync_ThrowsWhenOfflinePreferredButMissing"
]
},
{
"runner": "scripts/test-targeted-xunit.ps1",
"class": "StellaOps.Excititor.Connectors.Oracle.CSAF.Tests.Connectors.OracleCsafConnectorTests",
"command": "powershell -ExecutionPolicy Bypass -File .\\scripts\\test-targeted-xunit.ps1 -Project \"src/Concelier/__Tests/StellaOps.Excititor.Connectors.Oracle.CSAF.Tests/StellaOps.Excititor.Connectors.Oracle.CSAF.Tests.csproj\" -Class \"StellaOps.Excititor.Connectors.Oracle.CSAF.Tests.Connectors.OracleCsafConnectorTests\"",
"buildResult": "pass",
"warnings": 0,
"errors": 0,
"testsRun": 4,
"testsPassed": 4,
"testsFailed": 0,
"outputSnippet": [
"Build succeeded.",
"0 Warning(s)",
"0 Error(s)",
"Total: 4, Errors: 0, Failed: 0, Skipped: 0, Not Run: 0, Time: 1.235s",
"FetchAsync_NewEntry_PersistsDocumentAndUpdatesState",
"FetchAsync_ChecksumMismatch_SkipsDocument",
"FetchAsync_MissingHistoricalDocument_SkipsAndContinues",
"FetchAsync_EmptyDigestCheckpoint_DoesNotSuppressInitialBackfill"
]
}
],
"verdict": "pass",
"notes": [
"The Oracle targeted test pass covers both live-catalog metadata behavior and connector fetch safety paths.",
"The missing historical document case directly backs the live Oracle run behavior where several old Oracle CSAF URLs returned 404 but the provider still completed."
]
}

View File

@@ -0,0 +1,94 @@
{
"type": "integration",
"capturedAtUtc": "2026-04-22T08:07:25Z",
"providerId": "excititor:oracle",
"environment": {
"longLivedWorker": "stellaops-excititor-worker",
"disposableWorker": "stellaops-excititor-worker-oracle-qa-check",
"workerImage": "stellaops/excititor-worker:dev",
"databaseContainer": "stellaops-postgres"
},
"steps": [
{
"name": "long-lived-worker-health",
"command": "docker ps --filter name=stellaops-excititor-worker --format \"table {{.Names}}\\t{{.Status}}\\t{{.Image}}\"",
"result": "pass",
"evidence": [
"stellaops-excititor-worker Up 33 minutes (healthy) stellaops/excititor-worker:dev"
]
},
{
"name": "pre-run-state",
"command": "docker exec -i stellaops-postgres psql -U stellaops -d stellaops_platform -v ON_ERROR_STOP=1 -c \"SELECT connector_id, last_updated, array_length(document_digests,1) AS digests, COALESCE((SELECT COUNT(*) FROM jsonb_each(resume_tokens)),0) AS resume_tokens, next_eligible_run, failure_count FROM vex.connector_states WHERE connector_id = 'excititor:oracle'; SELECT provider_id, COUNT(*) AS docs FROM vex.vex_raw_documents WHERE provider_id = 'excititor:oracle' GROUP BY provider_id;\"",
"result": "pass",
"state": {
"lastUpdated": "2026-04-22 06:46:15.261191+00",
"documentDigests": 1,
"resumeTokens": 0,
"nextEligibleRun": null,
"failureCount": 0,
"rawDocuments": 1
}
},
{
"name": "disposable-oracle-only-run",
"command": "docker compose -f devops/compose/docker-compose.stella-services.yml run --rm --no-deps -d --name stellaops-excititor-worker-oracle-qa-check -e Excititor__Worker__Providers__0__ProviderId=excititor:oracle -e Excititor__Worker__Providers__0__InitialDelay=00:00:00 -e Excititor__Worker__Providers__0__Interval=24:00:00 -e Excititor__Worker__Providers__0__Settings__RequestDelay=00:00:00.2500000 excititor-worker",
"result": "pass",
"containerId": "4f7a034ca740bfd715e25fdd8606d5e72ae9cd204091742357fdb39d2ef518c8"
},
{
"name": "runtime-logs",
"command": "docker logs stellaops-excititor-worker-oracle-qa-check",
"result": "pass",
"runId": "5fa3edb0-a3af-4ec1-b9bb-dce9baa32d09",
"evidence": [
"Provider excititor:oracle run started at 04/22/2026 08:07:11 +00:00. Interval=24.00:00:00.",
"GET https://www.oracle.com/ocom/groups/public/@otn/documents/webcontent/rss-otn-sec.xml -> 200",
"Oracle CSAF catalogue loaded.",
"GET https://www.oracle.com/docs/tech/security-alerts/cpujul2019-5072835csaf.json -> 404",
"GET https://www.oracle.com/docs/tech/security-alerts/cve-2016-0603-2874360csaf.json -> 404",
"GET https://www.oracle.com/docs/tech/security-alerts/cve-2017-10269-4021872csaf.json -> 404",
"GET https://www.oracle.com/docs/tech/security-alerts/cve-2019-2729-5570780csaf.json -> 404",
"GET https://www.oracle.com/docs/tech/security-alerts/cve-2020-14750csaf.json -> 404",
"Oracle CSAF document URI is unavailable; entry skipped.",
"Connector excititor:oracle persisted 0 raw document(s) this run.",
"Orchestrator job completed: runId=5fa3edb0-a3af-4ec1-b9bb-dce9baa32d09 connector=excititor:oracle documents=0 claims=0 duration=00:00:03.6134483",
"Provider excititor:oracle run completed at 04/22/2026 08:07:19 +00:00 (duration 00:00:07.8903177)."
]
},
{
"name": "post-run-state",
"command": "docker exec -i stellaops-postgres psql -U stellaops -d stellaops_platform -v ON_ERROR_STOP=1 -c \"SELECT connector_id, last_updated, array_length(document_digests,1) AS digests, COALESCE((SELECT COUNT(*) FROM jsonb_each(resume_tokens)),0) AS resume_tokens, next_eligible_run, failure_count FROM vex.connector_states WHERE connector_id = 'excititor:oracle'; SELECT provider_id, COUNT(*) AS docs FROM vex.vex_raw_documents WHERE provider_id = 'excititor:oracle' GROUP BY provider_id;\"",
"result": "pass",
"state": {
"lastUpdated": "2026-04-22 06:46:15.261191+00",
"documentDigests": 1,
"resumeTokens": 0,
"nextEligibleRun": null,
"failureCount": 0,
"rawDocuments": 1
},
"assertions": [
"last_updated remained unchanged across successful completion",
"failure_count stayed at 0",
"raw document count stayed stable at 1",
"historical 404s did not move the provider into backoff"
]
},
{
"name": "cleanup",
"command": "docker stop stellaops-excititor-worker-oracle-qa-check",
"result": "pass",
"evidence": [
"stellaops-excititor-worker-oracle-qa-check"
]
}
],
"behaviorVerified": [
"The Oracle CSAF provider remains installed and runnable in the live Excititor worker.",
"Historical Oracle CSAF URLs that now return 404 are skipped cleanly without failing the provider run.",
"A successful Oracle worker completion preserves connector-managed cursor state and does not create duplicate raw documents.",
"The current Oracle state remains healthy for mirror operation: one stored raw document, no backoff, and no failure accumulation."
],
"verdict": "pass"
}

View File

@@ -1,7 +1,7 @@
{
"module": "excititor",
"featureCount": 18,
"lastUpdatedUtc": "2026-02-13T20:00:00Z",
"lastUpdatedUtc": "2026-04-22T08:08:08.8206436Z",
"features": {
"vex-claim-normalization": {
"status": "done", "tier": 2, "retryCount": 0, "sourceVerified": true, "buildVerified": true, "e2eVerified": true,
@@ -53,9 +53,9 @@
},
"vex-source-registration-and-verification-pipeline": {
"status": "done", "tier": 2, "retryCount": 0, "sourceVerified": true, "buildVerified": true, "e2eVerified": true,
"skipReason": null, "lastRunId": "run-001", "lastUpdatedUtc": "2026-02-13T20:00:00Z",
"skipReason": null, "lastRunId": "run-003", "lastUpdatedUtc": "2026-04-22T08:08:08.8206436Z",
"featureFile": "docs/features/checked/excititor/vex-source-registration-and-verification-pipeline.md",
"notes": ["[2026-02-13T20:00:00Z] done: run-001 Tier 0/1/2d passed. 73/73 Worker.Tests passed. VexWorkerHostedService, DefaultVexProviderRunner, WorkerSignatureVerifier, VexWorkerPluginCatalogLoader verified."]
"notes": ["[2026-04-22T08:08:08.8206436Z] done: run-003 re-verified the Oracle branch of the live VEX source registration pipeline. Tier 0 confirmed the Oracle CSAF connector, catalog loader, targeted test classes, and default provider seeding under src/Concelier. Tier 1 targeted xUnit helper runs passed for OracleCatalogLoaderTests (3/3) and OracleCsafConnectorTests (4/4). Tier 2 disposable Oracle worker run 5fa3edb0-a3af-4ec1-b9bb-dce9baa32d09 completed successfully against the live RSS catalog, skipped multiple historical 404 CSAF URLs without failing, and preserved last_updated=2026-04-22 06:46:15.261191+00 with docs=1 and failure_count=0."]
},
"excititor-vex-observation-and-linkset-stores": {
"status": "done", "tier": 2, "retryCount": 0, "sourceVerified": true, "buildVerified": true, "e2eVerified": true,