# Connector Setup Guide — Concelier + Excititor
Operator reference for bringing up the Concelier (advisory source) and Excititor (VEX provider) connectors. This guide describes the federated source catalog (Concelier advisory sources + Excititor VEX providers, surfaced through one /api/v1/advisory-sources/catalog endpoint), which connectors are backend-wired on ingest today, and the credential-acquisition steps for the few providers that require operator-minted secrets.
RETIRED OPERATOR PATH (2026-08-25). Do not use this guide to bring up a service or obtain credentials. The Concelier/Excititor plane is stopped and backs nothing running; remaining source retires under
SPRINT_20260722_003VULN-B1. Live ingestion is owned bysrc/Vulnerabilities, whose Tier-0 CVE path uses credential-free CVE List v5. There is no live CVE Services credential path. The snapshot and procedures below are historical migration evidence; use the Vulnerability Operations Runbook.
Reconciliation note (verify against source): the runtime snapshot below (source list, doc counts, health timestamps) was captured against a 2026-04-22 dev stack and is not kept current. The connector landscape has grown substantially since then — see “Backend-wired reality” for the source-of-truth pointers. Treat all counts/timestamps in this file as illustrative, not authoritative; re-run
sources status/ the DB queries below to get live state.
Backend-wired reality (source of truth)
The authoritative connector catalog lives in src/Concelier/__Libraries/StellaOps.Concelier.Core/Sources/SourceDefinitions.cs (SourceDefinitions.All). Each connector library under src/Concelier/__Libraries/StellaOps.Concelier.Connector.* ships an IDependencyInjectionRoutine and a plugin DLL (StellaOps.Concelier.Plugin.*.dll) that the WebService loads on startup; a source becomes runnable when its connector registers a fetch job (source:{id}:fetch) in the scheduler. The current per-connector auth/credential matrix — the single source of truth for “what needs a secret” — is docs/modules/concelier/connectors/credentials-matrix.md.
Catalog ≠runnable. A source can be present in SourceDefinitions.All but not runnable on a given host if no connector plugin registers its fetch job. Unlike the older “no-op enable” behaviour, the server-side REST enable/sync path now returns 501 Not Implemented (problem type https://stellaops.org/problems/not-implemented, code NOT_IMPLEMENTED) for a cataloged-but-unrunnable source rather than silently accepting it — see IsSourceRunnable in ConfiguredAdvisorySourceService.cs and the enable/sync handlers in SourceManagementEndpointExtensions.cs.
A large set of connectors that this guide previously listed as “aspirational / NOT backend-wired” now ship real connector libraries with DI routines and config contributors, including: npm, pypi, go, rubygems, maven, crates, packagist, hex, nuget, rustsec, pypa, govuln, bundler-audit, intel, amd, siemens, kaspersky-ics, cccs, jpcert (JVN), krcert (KISA), cert-fr, cert-in, cert-de (CERT-Bund), cert-cc, aws, gcp, azure, arch, gentoo, apple, fstec-bdu, nkcki. Several of those are alias-only or stubs (see the caveats below), but they are no longer unmapped catalog entries. mitre-attack / mitre-d3fend were removed entirely (PM Path 2 decision, Sprint 20260513_008).
Caveats from the live credentials matrix (verify there before relying on a row):
- Covered by OSV:
npm,pypi,go,rubygems,maven,crates,packagist,hex,rustsec,pypa,govuln,bundler-audit,chainguard, andwolfiare controlled as ecosystem aliases, but ingestion runs through the parentosvconnector. Their direct row counts stay zero by design; the setup UI folds them into theOSVrow as “Also covering …” so they do not appear as separate failed connector rows. - Covered by GHSA:
nugetis a package-ecosystem filter for theghsaconnector, not a standalone NuGet advisory feed in this stack. The setup UI folds it into theGitHub Security Advisoriesrow. - Canonical aliases:
rhelis covered by the runnableredhatsource, andazureis covered by themicrosoft/MSRC source. Their rows exist for operator filtering and attribution, not for direct fetch jobs. The setup UI folds them into the parentRed Hat SecurityandMicrosoft Securityrows. - Removed legacy stub:
armwas removed from the advisory source catalog and project references because its production backend failed closed and no approved machine-readable public Arm feed has been identified. - Removed speculative rows:
poc-githubanddocker-officialwere removed from the advisory source catalog.poc-githubwas not a safe curated advisory source, anddocker-officialpointed at Docker Hub/Official Images metadata, not an official CVE/VEX advisory feed. - Real missing connectors: rows that are neither directly runnable nor covered by a parent source remain disabled and show as
Connector missinguntil a connector implementation is added. Current candidates are tracked in the Concelier implementation sprint and source coverage matrix. - classified geo (export-control gated):
kaspersky-ics,fstec-bdu,nkckirequire legal/export-control review before a credential or route reaches prod.
Concelier runtime snapshot (illustrative — 2026-04-22 dev stack, stale)
| Source | Backend wired? | Health check | Docs in DB | Last updated |
|---|---|---|---|---|
redhat | YES | healthy | 651 | 2026-04-22 17:16 |
osv | YES | healthy (498ms) | 59 | 2026-04-22 17:40 |
debian | YES | healthy | 41 | 2026-04-22 17:07 |
suse | YES | healthy | 26 | 2026-04-22 17:00 |
alpine | YES | healthy | 8 | 2026-04-22 17:06 |
ubuntu | YES | healthy | 2 | 2026-04-22 17:41 |
auscert | YES | healthy | 0 | never |
vmware | YES | healthy | 0 | never |
stella-mirror | YES | unhealthy (404) | 0 | never |
The stella-mirror failure on the dev stack is expected — that source is a downstream relay that pulls a pre-aggregated bundle from a parent Stella Ops deployment’s evidence-locker/mirror exports endpoint (typically an air-gap relay). It is disabled by default; set STELLA_MIRROR_BASE_URL to the parent’s mirror root and flip enabled=true on the vuln.sources row to activate. (Note: Stella Ops is itself the mirror publisher — this connector is for consumers of that feed, not the publisher side.)
Excititor — VEX providers (federated into the same catalog)
Excititor VEX providers surface through the unified catalog under the excititor:{provider} source-id namespace, with backend = "excititor" on each entry (Sprint 20260503-012, B-VEXUNI-002). Mutating an excititor:* source via the Concelier /api/v1/advisory-sources/... endpoints returns a 308 Permanent Redirect to the canonical Excititor management surface (/excititor/providers/{id}/...); Excititor’s VexProviderRuntimeSettingsCache / VexProviderConfigurationService remain the single source of truth for trust weight, signing material, and PGP fingerprints. The Concelier facade never duplicates that state.
The provider list and base URIs are owned by Excititor, not by this guide — enumerate them from the catalog (backend=excititor) or the vex.providers table rather than trusting a frozen snapshot. The previously listed excititor:redhat, excititor:ubuntu, excititor:cisco, and excititor:oracle entries are illustrative.
Provider management is available to operators with vex.admin, integration:write, or integration:operate. The unified source catalog and the dedicated VEX provider catalog must use the same scope gate as the Excititor API so integration operators can enable, configure, and run VEX providers without a separate vex.admin grant.
2026-06-02 local verification on https://stella-ops.local enabled and ran all 7 Excititor providers: Cisco, MSRC, OCI OpenVEX, Oracle, Red Hat, SUSE Rancher, and Ubuntu. All provider counters ended in succeeded. Cisco exceeded the frontdoor request timeout but completed in Excititor with 2 stored documents and 9 claims; use provider counters/history rather than the gateway timeout alone when diagnosing long-running provider runs.
Note about Cisco: the VEX side uses Cisco’s public CSAF feed (unauthenticated). The Concelier advisory side of Cisco (Connector.Vndr.Cisco) is now backend-wired and DOES require PSIRT openVuln OAuth client credentials (client_credentials) — see the credential section below.
Catalog and runnable connectors
The catalog and enable operation have separate contracts:
- The catalog has been largely closed out: most former “aspirational” ids now ship real connector libraries (see “Backend-wired reality” above).
- The server REST path (
POST /api/v1/advisory-sources/{id}/enableand/sync) gates onIsSourceRunnableand returns 501 Not Implemented for a cataloged-but-unrunnable source — it no longer fakes an[OK]. - The CLI
sources enablehandler (SourcesCommandHandlers.HandleSourcesEnableAsync) still operates against a local in-processISourceRegistryand prints[OK] Enabled source: <id>/[FAIL] ... (not found)— it does not perform the server-side runnability gate. Prefer the server-side path (db connectors configure, the REST endpoints, or the UI) for authoritative persistence.
Historical tracking sprints (SPRINT_20260422_004, SPRINT_20260422_007) are archived; do not rely on their status here — verify the current catalog against SourceDefinitions.All and the credentials matrix.
Credential requirements
Authoritative source of truth: docs/modules/concelier/connectors/credentials-matrix.md (per-connector auth mechanism, config keys, rate limits, geo flags), grounded in each connector’s *Options.cs + *DependencyInjectionRoutine.cs. Read it before acting on anything below.
Other current-state inventories:
docs/modules/concelier/connectors.mddocs/modules/concelier/connectors/credentials-acquisition.mddocs/modules/concelier/operations/source-credentials.mddocs/modules/excititor/operations/provider-control-plane.mddocs/modules/excititor/operations/provider-credentials.md
Connectors that actually require an operator-minted secret are few. Per the credentials matrix:
- OAuth2 client_credentials (require a secret):
microsoft(MSRC),cisco. - PAT-optional (works anonymously; token only raises rate limits):
ghsa. - Optional API key (public fallback exists):
cve(public cvelistV5 mirror by default; CVE Services credentials optional).redhataccepts an optional subscription token with an anonymous Hydra fallback. - none-public (no credential — network/geo policy only):
oracle,adobe,chromium,apple,vmware,siemens,intel,cccs,jpcert,krcert,cert-de,cert-fr,cert-in, and the classified-geo feeds.
Many connectors register an editable config schema (a configuration contributor). Enumerate UI/CLI-configurable sources via the catalog (supportsConfiguration: true) rather than a hard-coded list.
The sections below keep the acquisition steps for the connectors that genuinely require a minted secret.
GitHub Security Advisories (GHSA)
What Stella Ops needs: nothing mandatory. The GHSA connector reads GitHub’s public global-advisory REST API anonymously by default and falls back to OSV. A token is optional and only raises rate limits / supports enterprise routing (the connector sends it as Authorization: Bearer <token>; there is no fixed scope requirement). Configure it via concelier:sources:ghsa:ApiToken.
Steps (only if you want higher rate limits):
- https://github.com/settings/tokens → generate a token (classic or fine-grained).
- Name:
stella-ops-concelier-ghsa. A read-only public-advisory scope is sufficient; noread:packages/public_repowrite scopes are required for global advisory reads. - If your GitHub org enforces SAML SSO: Configure SSO next to the token → authorize per org.
- Store the value under
concelier:sources:ghsa:ApiToken(or the Platform credential store, see below).
Cisco PSIRT openVuln (Concelier advisory cisco connector; VEX uses public CSAF)
What Stella Ops needs: a Cisco PSIRT OAuth 2.0 client (grant_type=client_credentials). Plaintext schema stored as "{clientId}:{clientSecret}"; token endpoint defaults to https://id.cisco.com/oauth2/default/v1/token.
Steps:
- https://apiconsole.cisco.com/ → Register a New App.
- Tick Client Credentials grant. Enable the openVuln API entitlement.
- Copy
client_id+client_secretfrom the app detail page. - Store via
concelier:sources:cisco:ClientId/:ClientSecret(optionally:TokenEndpoint,:BaseUri) or the Platform credential store.
Cisco ref: https://developer.cisco.com/docs/psirt/authentication/.
Microsoft MSRC (Concelier advisory + Excititor VEX)
What Stella Ops needs: Concelier’s MSRC advisory connector still uses a Microsoft Entra confidential client app with the consent and scope required by your MSRC onboarding flow. Excititor’s excititor:msrc VEX provider runs in public mode by default; configure Entra fields there only when selecting authMode=ClientCredentials or when pointing at a mirror that requires bearer tokens.
Steps:
- https://entra.microsoft.com/ → App registrations → New registration.
- Name:
stella-ops-concelier-msrc. Single-tenant. Redirect URI blank. - From Overview: copy Directory (tenant) ID + Application (client) ID.
- Certificates & secrets → New client secret → 24-month expiry → copy the
Valuecolumn immediately. - Grant the application permissions and consent required by your MSRC onboarding process before storing the values in Stella Ops. For Excititor VEX, skip these steps when staying on
authMode=Public.
Config keys (Concelier microsoft connector): concelier:sources:microsoft:TenantId, :ClientId, :ClientSecret, :Scope (default api://api.msrc.microsoft.com/.default). The runtime overlay stores the resolved secret as "{aadTenantId}:{clientId}:{clientSecret}". The connector skips-with-WARN when no credential is resolvable (Sprint 037).
Microsoft refs: https://learn.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app, https://learn.microsoft.com/en-us/entra/identity-platform/how-to-add-credentials, MSRC SUG: https://api.msrc.microsoft.com/sug/v2.0/swagger.
Where credentials are stored (precedence)
Credentialed connectors resolve secrets in this order (RFC-0001 §8.2, wired under SPRINT_20260512_021):
- Platform credential store via
IRemoteCredentialResolver— the preferred path. Managed through the Console connector-credentials surface and governed by theconnector:credentials:read/connector:credentials:writescopes (StellaOpsScopes.ConnectorCredentialsRead/...Write). - Env var / source config — e.g.
concelier:sources:cisco:ClientId. With theCONCELIER_env prefix and:→__, that key is the env varCONCELIER_concelier__sources__cisco__ClientId; equivalentlyconcelier.sources.cisco.clientIdinetc/concelier.yaml. - Connector natural fallback — anonymous/public access or skip-with-WARN, per the credentials matrix step-3 column.
Credential dry-run (verify a stored secret without ingesting)
POST /api/v1/connectors/{connectorId}/dry-run-credential (body { "credentialId": "<guid>" }) exercises a connector’s auth path with a single upstream vendor call — no advisory persistence and no source-state mutation (only the standard Platform runtime-read audit row). It is governed by the concelier:credentials:dry-run scope (StellaOpsScopes.ConcelierCredentialsDryRun, policy Concelier.Credentials.DryRun). The {connectorId} path segment matches the connector’s namespaced IConnectorDryRun.ConnectorId (e.g. concelier:ghsa, concelier:cisco). Connectors that do not register an IConnectorDryRun handler return 501 Not Implemented (type https://stellaops.org/problems/not-implemented) — use the Platform metadata-only Verify endpoint instead. As of the source verified for this revision, the connectors that implement dry-run are GHSA (concelier:ghsa), Cisco (concelier:cisco), CVE (concelier:cve), MSRC (concelier:msrc), and Red Hat (concelier:redhat), plus the Excititor Red Hat CSAF provider (excititor:redhat-csaf); every other connector returns 501. Verify the live set against the registered IConnectorDryRun implementations (ConnectorDryRunRegistry.SupportedConnectorIds) rather than this list. The endpoint declines (409 Conflict) when the credential state is not active.
Day-to-day operator commands
# Using the CLI (src/Cli/StellaOps.Cli/bin/Debug/net10.0/StellaOps.Cli.dll):
dotnet StellaOps.Cli.dll sources list --json # catalog view (local registry)
dotnet StellaOps.Cli.dll sources status # configuration status summary
dotnet StellaOps.Cli.dll sources check <id> # connectivity probe
dotnet StellaOps.Cli.dll sources enable <id> [<id>...] # enable (local registry; not the server runnability gate)
dotnet StellaOps.Cli.dll sources disable <id>
dotnet StellaOps.Cli.dll db fetch --source <id> --stage fetch # trigger ingest (stage: fetch|parse|map)
dotnet StellaOps.Cli.dll db merge # run canonical merge reconciliation
dotnet StellaOps.Cli.dll db export --format json # run export job (json only; trivy-db retired 2026-08-09)
dotnet StellaOps.Cli.dll db connectors configure <id> --set Key=Value # persist connector config via REST
Command-surface notes (verify against CommandFactory.cs / DbCommandGroup.cs):
- The top-level
dbgroup (CommandFactory.BuildConcelierDbCommand) providesfetch,merge, andexport, dispatched to backend jobs.db fetch --source <id> --stage <fetch|parse|map> [--mode init|resume|cursor]is the real ingest trigger. - A separate
dbbuilder (DbCommandGroup) providesdb statusanddb connectors {list|status|test|configure}.db connectors list/status/testcurrently emit synthetic/hardcoded sample data (NOT live connector state) — onlydb connectors configure(and thesources/REST paths) hit live endpoints. Do not rely ondb connectors listoutput as ground truth.
Environment:
STELLAOPS_BACKEND_URL=https://stella-ops.local(required fordb fetch). Notedb status/db connectorsuseSTELLA_API_URL(defaulthttp://localhost:5080).- Self-signed cert: resolve by either trusting the dev cert system-wide or running the CLI from a container already in the compose network (the CLI currently has no
--insecureflag).
Verify persisted state directly:
SELECT key, source_type, enabled FROM vuln.sources ORDER BY key;
SELECT s.key, COUNT(d.*) AS docs, MAX(d.updated_at) AS last_update
FROM vuln.sources s LEFT JOIN concelier.source_documents d ON d.source_id = s.id
GROUP BY s.key ORDER BY docs DESC;
SELECT id, kind, enabled, array_to_string(base_uris,' | ') FROM vex.providers ORDER BY id;
What the UI workflow looks like
- Open the advisory sources catalog (served from the federated
GET /api/v1/advisory-sources/catalog; each row carries abackenddiscriminator ofconcelierorexcititor). - Each source row shows
enabled,readiness(ready/blocked/disabled/unsupported), and — whensupportsConfigurationis true — the stored configuration schema. - Use View more details on a row to inspect the Stored Connector Configuration and compact sync summary. Use View error history to open the source history dialog; it is backed by
GET /api/v1/advisory-sources/{id}/sync-historyand shows readiness, fetch job, ready-for-sync state, persisted last error/success/error count, and recent coordinator runs without expanding the row. readiness=blockedmeans the source is persisted as enabled but is missing required fields (credentials, URIs). The source is excluded from automatic and manual sync with a blocked-outcome response carrying the error codeSOURCE_CONFIG_REQUIRED(seeConfiguredAdvisorySourceService.cs); anunsupportedreadiness instead means no runnable fetch job is registered on this host.- Paste credentials in the source’s detail editor (
PUT /api/v1/advisory-sources/{id}/configuration). The server persists them; subsequent reads surface only a masked “secret retained” badge (isSecretRetained) — secrets are never echoed back. - Updating an unrelated field doesn’t require re-entering the secret; when a sensitive field is submitted empty, the server leaves the existing secret in place. Per-field validation failures return
422with the offendingfieldKey.
Local fixture-mode source sync
When running the local fixture lane, apply devops/compose/docker-compose.integration-fixtures.yml together with devops/compose/docker-compose.fixture-mode.yml; the stellaops-advisory-fixture nginx container must be present on the Compose network before Concelier sync jobs run. If the fixture container is missing, fixture hostnames can resolve incorrectly inside the stack and many sources surface as upstream 404/DNS failures.
Fixture-mode deliberately uses a smaller deterministic corpus than live upstreams:
- OSV is pinned to the fixture archives that exist locally (
PyPI,npm,Maven,Go,crates.io) so the connector does not request missing archives such asHex/all.zip. - CERT-In accepts both
concelier:sources:cert-inand the historicalconcelier:sources:certInsection names; keep both env forms in local overlays for compatibility. - VMware uses the fixture-only
/vendor/vmware/index.jsonindex. The Broadcom-shaped portal path is reserved for connector parser tests and can trigger the live portal CSRF flow. - Missing fixture files should return an explicit fixture
404, not the nginx health JSON, so connector failures identify the absent corpus item instead of a content-type mismatch.
Authorization (scopes & policies)
Verified against src/Concelier/StellaOps.Concelier.WebService/Program.cs and the canonical scope catalog (src/Authority/.../StellaOpsScopes.cs):
- Catalog / status / configuration reads (
/catalog,/status,GET .../configuration,/check-result) use policyConcelier.Advisories.Read, which requires theadvisory:readscope alone. It does not require anaoc:verifypairing. (The earlier claim that the read policy requiresadvisory:read+aoc:verifywas incorrect — that pairing applies only to the separateConcelier.Aoc.Verifypolicy on the AOC verify endpoint.) - Source mutations (
enable,disable,check,sync,configurationPUT, batch operations) use policyConcelier.Sources.Manage, which requires any ofintegration:writeorintegration:operate(AddStellaOpsAnyScopePolicy). Note this is theintegration:*scope family, not aconcelier.sources.managescope. - Credential dry-run uses
concelier:credentials:dry-run(policyConcelier.Credentials.DryRun). - Console connector-credentials management uses
connector:credentials:read/connector:credentials:write.
Follow-up for this stack
- The connector catalog has been largely closed out vs. the 2026-04-22 snapshot; the remaining gaps are split into explicit parent-covered aliases and real missing connectors. Track current state against
SourceDefinitions.All, the source coverage metadata returned by/api/v1/advisory-sources/catalog, and the credentials matrix rather than archived sprint snapshots.
