feat(excititor): persisted provider configuration + blocked-readiness (EXCITITOR-CFG-01/02/03)
Closes 3 of 4 tasks in SPRINT_20260422_007. EXCITITOR-CFG-04 (OCI
binary-material handling) stays BLOCKED pending a secret-reference
storage-model design decision — sprint header called that out as a
scope boundary.
Mirrors the SRC-CREDS pattern (commits 838257245 + earlier) to give
Excititor VEX providers the same persisted-credentials + blocked-
readiness contract that advisory sources now have.
Persistence (EXCITITOR-CFG-01):
- New vex.provider_settings table via embedded migration
007_vex_provider_settings.sql (auto-applied by AddStartupMigrations).
Key: provider_id; columns: settings jsonb, updated_by, timestamps.
- PostgresVexProviderSettingsStore (Dapper) + ProviderSettingsRow EfCore
model + InMemoryVexProviderSettingsStore for tests.
- IVexProviderSettingsStore + VexProviderSettingsRecord added to
StellaOps.Excititor.Core/Storage.
- Existing vex.providers row (trust, discovery, base_uris, enabled)
untouched — additive only.
API surface:
- GET /excititor/providers/{id}/configuration → masked snapshot with
fields: key, label, inputType, sensitive, required, value, hasValue,
isSecretRetained, helpText, placeholder. Plaintext secrets never
returned.
- PUT /excititor/providers/{id}/configuration with { values, clearKeys }.
Sensitive fields submitted blank are retained; clearKeys explicitly
deletes.
- Field schemas shipped for excititor:cisco / msrc / suse-rancher.
Effective settings + readiness (EXCITITOR-CFG-02):
- VexProviderConfigurationService.ComputeConfigurationFailure drives
readiness. When persisted-enabled but missing required fields, the
provider status reports blockingReasonCode=PROVIDER_CONFIG_REQUIRED
(or PROVIDER_CONFIG_INVALID on validation failure), readiness=blocked.
Configuration failures take priority over retry-backoff reasons so the
actionable message surfaces first.
- VexIngestOrchestrator.ValidateConnectorAsync + ExecuteRunAsync resolve
effective settings from VexProviderRuntimeSettingsCache; same
settings flow into DefaultVexProviderRunner (worker scheduled runs).
Previously those paths validated against empty / schedule-only options.
CLI + Web (EXCITITOR-CFG-03):
- CLI: `stella vex providers configure <provider> [--set k=v] [--clear k]
[--format text|json]`. Aliases cisco/msrc/rancher → excititor:*.
- Web: VexProviderManagementApi.getConfiguration / updateConfiguration
+VexProviderConfigurationComponent (Angular standalone). Component
renders masked-secret + clear toggles + required indicators + help/
placeholder. Routing intentionally minimal (no new route added) to
avoid stepping on the parallel FE test agent.
Tests: targeted xUnit via scripts/test-targeted-xunit.ps1:
- VexProviderConfigurationServiceTests → Total: 8, Failed: 0
- ProviderManagementEndpointsTests regression → Total: 5, Failed: 0
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>