# Connector Setup Guide — Concelier + Excititor Operator reference for bringing up the Concelier (advisory source) and Excititor (VEX provider) connectors. This guide distinguishes the **aspirational catalog** (~78 entries exposed through `stellaops-cli sources list`) from the **actually backend-wired connectors** that run on ingest today, and lays out credential-creation steps for the few providers that require operator-minted secrets. ## Actual state (verified 2026-04-22 against the local dev stack) ### Concelier — 9 wired sources, 8 healthy, 787 advisories ingested | 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 expects a reachable StellaOps infrastructure mirror that's not wired in dev. ### Excititor — 4 wired providers, all enabled | Provider | Kind | Base URIs | |---|---|---| | `excititor:redhat` | distro | _(pulls via CSAF feeds)_ | | `excititor:ubuntu` | distro | `https://ubuntu.com/security/notices.json` | | `excititor:cisco` | vendor | `https://www.cisco.com/.well-known/csaf/` (public CSAF — no auth) | | `excititor:oracle` | vendor | _(pulls via public Oracle Critical Patch Updates)_ | **Note about Cisco**: the VEX side uses Cisco's public CSAF feed (unauthenticated). The **Concelier advisory** side of Cisco (which WOULD require PSIRT openVuln OAuth) is currently in the aspirational catalog but not backend-wired. ### Aspirational catalog (~65 entries — NOT yet backend-wired) `stellaops-cli sources list` reports 78 entries. The other ~65 (npm, pypi, go, rubygems, maven, crates, packagist, hex, rustsec, pypa, govuln, bundler-audit, exploitdb, metasploit, intel, amd, arm, siemens, kaspersky-ics, cert-ua/pl/in, krcert, fstec-bdu, nkcki, mitre-attack, mitre-d3fend, nuget, poc-github, and more) are present in the static catalog but have no `source_type` → connector mapping in the backend. Calling `stellaops-cli sources enable ` on these returns `[OK]` but does NOT persist the source — the call is a no-op because there's no runtime implementation to register against. Tracked in: - `docs/implplan/SPRINT_20260422_004_Concelier_full_connector_control_plane.md` (archived — covered Excititor backend; Concelier-catalog mapping remains) - `docs/implplan/SPRINT_20260422_007_Concelier_excititor_persisted_provider_credentials.md` (open — persisted per-provider configuration) ## Credential requirements Only the following connectors need operator-minted credentials — and **all three are currently in the aspirational catalog only**. You cannot configure them against a running backend until the connector code is wired. Steps are retained here so they're ready when that sprint lands. ### GitHub Security Advisories (GHSA) **What Stella Ops needs**: a GitHub Personal Access Token (classic). Steps: 1. → **Generate new token (classic)**. 2. Name: `stella-ops-concelier-ghsa`. Expiration: 90 days minimum. 3. Scopes: `read:packages` + `public_repo` (or the fine-grained `read:public_repo` equivalent). 4. If your GitHub org enforces SAML SSO: **Configure SSO** next to the token → authorize per org. ### Cisco PSIRT openVuln (Concelier advisory only; VEX uses public CSAF) **What Stella Ops needs**: a Cisco PSIRT OAuth 2.0 client (grant_type=client_credentials). Steps: 1. → **Register a New App**. 2. Name: `stella-ops-concelier-psirt`. Tick **Client Credentials** grant. Grant **openVuln API**. 3. Copy `client_id` + `client_secret` from the app detail page. Cisco ref: . ### Microsoft MSRC (Concelier advisory + Excititor VEX — not yet wired for either) **What Stella Ops needs**: a Microsoft Entra confidential client app with `SecurityUpdates.Read.All` API permission. Steps: 1. → **App registrations** → **New registration**. 2. Name: `stella-ops-concelier-msrc`. Single-tenant. Redirect URI blank. 3. From Overview: copy **Directory (tenant) ID** + **Application (client) ID**. 4. **Certificates & secrets** → **New client secret** → 24-month expiry → copy the `Value` column **immediately**. 5. **API permissions** → **Add a permission** → Security Updates API (App ID `83b40db2-0d04-4b56-9e77-0e7d76a47d4b`) → Application permissions → `SecurityUpdates.Read.All` → Grant admin consent. Microsoft refs: , . ## Day-to-day operator commands ```bash # Using the CLI (src/Cli/StellaOps.Cli/bin/Debug/net10.0/StellaOps.Cli.dll): dotnet StellaOps.Cli.dll sources list --json # catalog view dotnet StellaOps.Cli.dll sources status # runtime readiness dotnet StellaOps.Cli.dll sources check # connectivity probe dotnet StellaOps.Cli.dll sources enable [...] # enable (no-op for unwired) dotnet StellaOps.Cli.dll sources disable dotnet StellaOps.Cli.dll db fetch --source --stage fetch # trigger ingest ``` Environment: - `STELLAOPS_BACKEND_URL=https://stella-ops.local` (required for `db fetch`) - 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 `--insecure` flag). Verify persisted state directly: ```sql 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 1. `/setup/integrations` → advisory sources catalog. 2. Each source row shows `enabled`, `readiness` (`ready` / `blocked` / `disabled` / `unsupported`), and the stored configuration schema. 3. `readiness=blocked` means the source is persisted as enabled but is missing required fields (credentials, URIs). The source will be excluded from automatic and manual sync with a blocked-outcome response (contract: `SOURCE_CONFIG_REQUIRED`, delivered via SPRINT_20260422_003 SRC-CREDS-005 work landed earlier today). 4. Paste credentials in the source's detail editor. The server persists them; subsequent reads surface only a masked "secret retained" badge — secrets are never echoed back. 5. Updating an unrelated field doesn't require re-entering the secret; the server detects "no change" and preserves the stored value. ## Follow-up for this stack - ~65 aspirational catalog entries still need backend connector wiring — tracked in `SPRINT_20260422_004` and follow-up sprints. - `Concelier.Advisories.Read` policy requires `advisory:read` scope which requires `aoc:verify` scope pairing, and the `stellaops-cli` OAuth client isn't allowed to mint `aoc:verify`. The UI (`stella-ops-ui` client, authorization_code flow) CAN mint it. Result: the CLI can execute the write path (enable, disable, sync) but cannot call the read-only status/catalog endpoints directly — it uses a separate auth path. This is a known asymmetry; documented here for future operators.