- Implemented EmailChannelTestProvider to generate email preview payloads. - Implemented SlackChannelTestProvider to create Slack message previews. - Implemented TeamsChannelTestProvider for generating Teams Adaptive Card previews. - Implemented WebhookChannelTestProvider to create webhook payloads. - Added INotifyChannelTestProvider interface for channel-specific preview generation. - Created ChannelTestPreviewContracts for request and response models. - Developed NotifyChannelTestService to handle test send requests and generate previews. - Added rate limit policies for test sends and delivery history. - Implemented unit tests for service registration and binding. - Updated project files to include necessary dependencies and configurations.
12 KiB
10 · Concelier + CLI Quickstart
This guide walks through configuring the Concelier web service and the stellaops-cli
tool so an operator can ingest advisories, merge them, and publish exports from a
single workstation. It focuses on deployment-facing surfaces only (configuration,
runtime wiring, CLI usage) and leaves connector/internal customization for later.
0 · Prerequisites
- .NET SDK 10.0.100-preview (matches
global.json) - MongoDB instance reachable from the host (local Docker or managed)
trivy-dbbinary onPATHfor Trivy exports (andorasif publishing to OCI)- Plugin assemblies present in
StellaOps.Concelier.PluginBinaries/(already included in the repo) - Optional: Docker/Podman runtime if you plan to run scanners locally
Tip
– air-gapped installs should preload
trivy-dbandorasbinaries into the runner image since Concelier never fetches them dynamically.
1 · Configure Concelier
-
Copy the sample config to the expected location (CI/CD pipelines can stamp values into this file during deployment—see the “Deployment automation” note below):
mkdir -p etc cp etc/concelier.yaml.sample etc/concelier.yaml -
Edit
etc/concelier.yamland update the MongoDB DSN (and optional database name). The default template configures plug-in discovery to look inStellaOps.Concelier.PluginBinaries/and disables remote telemetry exporters by default. -
(Optional) Override settings via environment variables. All keys are prefixed with
CONCELIER_. Example:export CONCELIER_STORAGE__DSN="mongodb://user:pass@mongo:27017/concelier" export CONCELIER_TELEMETRY__ENABLETRACING=false -
Start the web service from the repository root:
dotnet run --project src/StellaOps.Concelier.WebService
On startup Concelier validates the options, boots MongoDB indexes, loads plug-ins,
and exposes:
- `GET /health` – returns service status and telemetry settings
- `GET /ready` – performs a MongoDB `ping`
- `GET /jobs` + `POST /jobs/{kind}` – inspect and trigger connector/export jobs
> **Security note** – authentication now ships via StellaOps Authority. Keep
> `authority.allowAnonymousFallback: true` only during the staged rollout and
> disable it before **2025-12-31 UTC** so tokens become mandatory.
### Authority companion configuration (preview)
1. Copy the Authority sample configuration:
```bash
cp etc/authority.yaml.sample etc/authority.yaml
-
Update the issuer URL, token lifetimes, and plug-in descriptors to match your environment. Authority expects per-plugin manifests in
etc/authority.plugins/; samplestandard.yamlandldap.yamlfiles are provided as starting points. For air-gapped installs keep the default plug-in binary directory (../StellaOps.Authority.PluginBinaries) so packaged plug-ins load without outbound access. -
Environment variables prefixed with
STELLAOPS_AUTHORITY_override individual fields. Example:export STELLAOPS_AUTHORITY__ISSUER="https://authority.stella-ops.local" export STELLAOPS_AUTHORITY__PLUGINDIRECTORIES__0="/srv/authority/plugins"
2 · Configure the CLI
The CLI reads configuration from JSON/YAML files and environment variables. The
defaults live in src/StellaOps.Cli/appsettings.json and expect overrides at runtime.
| Setting | Environment variable | Default | Purpose |
|---|---|---|---|
BackendUrl |
STELLAOPS_BACKEND_URL |
empty | Base URL of the Concelier web service |
ApiKey |
API_KEY |
empty | Reserved for legacy key auth; leave empty when using Authority |
ScannerCacheDirectory |
STELLAOPS_SCANNER_CACHE_DIRECTORY |
scanners |
Local cache folder |
ResultsDirectory |
STELLAOPS_RESULTS_DIRECTORY |
results |
Where scan outputs are written |
Authority.Url |
STELLAOPS_AUTHORITY_URL |
empty | StellaOps Authority issuer/token endpoint |
Authority.ClientId |
STELLAOPS_AUTHORITY_CLIENT_ID |
empty | Client identifier for the CLI |
Authority.ClientSecret |
STELLAOPS_AUTHORITY_CLIENT_SECRET |
empty | Client secret (omit when using username/password grant) |
Authority.Username |
STELLAOPS_AUTHORITY_USERNAME |
empty | Username for password grant flows |
Authority.Password |
STELLAOPS_AUTHORITY_PASSWORD |
empty | Password for password grant flows |
Authority.Scope |
STELLAOPS_AUTHORITY_SCOPE |
concelier.jobs.trigger |
OAuth scope requested for backend operations |
Authority.TokenCacheDirectory |
STELLAOPS_AUTHORITY_TOKEN_CACHE_DIR |
~/.stellaops/tokens |
Directory that persists cached tokens |
Authority.Resilience.EnableRetries |
STELLAOPS_AUTHORITY_ENABLE_RETRIES |
true |
Toggle Polly retry handler for Authority HTTP calls |
Authority.Resilience.RetryDelays |
STELLAOPS_AUTHORITY_RETRY_DELAYS |
1s,2s,5s |
Comma- or space-separated backoff delays (hh:mm:ss) |
Authority.Resilience.AllowOfflineCacheFallback |
STELLAOPS_AUTHORITY_ALLOW_OFFLINE_CACHE_FALLBACK |
true |
Allow CLI to reuse cached discovery/JWKS metadata when Authority is offline |
Authority.Resilience.OfflineCacheTolerance |
STELLAOPS_AUTHORITY_OFFLINE_CACHE_TOLERANCE |
00:10:00 |
Additional tolerance window applied to cached metadata |
Example bootstrap:
export STELLAOPS_BACKEND_URL="http://localhost:5000"
export STELLAOPS_RESULTS_DIRECTORY="$HOME/.stellaops/results"
export STELLAOPS_AUTHORITY_URL="https://authority.local"
export STELLAOPS_AUTHORITY_CLIENT_ID="concelier-cli"
export STELLAOPS_AUTHORITY_CLIENT_SECRET="s3cr3t"
dotnet run --project src/StellaOps.Cli -- db merge
# Acquire a bearer token and confirm cache state
dotnet run --project src/StellaOps.Cli -- auth login
dotnet run --project src/StellaOps.Cli -- auth status
dotnet run --project src/StellaOps.Cli -- auth whoami
Refer to docs/dev/32_AUTH_CLIENT_GUIDE.md for deeper guidance on tuning retry/offline settings and rollout checklists.
To persist configuration, you can create stellaops-cli.yaml next to the binary or
rely on environment variables for ephemeral runners.
3 · Operating Workflow
-
Trigger connector fetch stages
dotnet run --project src/StellaOps.Cli -- db fetch --source osv --stage fetch dotnet run --project src/StellaOps.Cli -- db fetch --source osv --stage parse dotnet run --project src/StellaOps.Cli -- db fetch --source osv --stage mapUse
--mode resumewhen continuing from a previous window:dotnet run --project src/StellaOps.Cli -- db fetch --source redhat --stage fetch --mode resume -
Merge canonical advisories
dotnet run --project src/StellaOps.Cli -- db merge -
Produce exports
# JSON tree (vuln-list style) dotnet run --project src/StellaOps.Cli -- db export --format json # Trivy DB (delta example) dotnet run --project src/StellaOps.Cli -- db export --format trivy-db --deltaConcelier always produces a deterministic OCI layout. The first run after a clean bootstrap emits a full baseline; subsequent
--deltaruns reuse the previous baseline’s blobs when only JSON manifests change. If the exporter detects that a prior delta is still active (i.e.,LastDeltaDigestis recorded) it automatically upgrades the next run to a full export and resets the baseline so operators never chain deltas indefinitely. The CLI exposes--publish-full/--publish-delta(for ORAS pushes) and--include-full/--include-delta(for offline bundles) should you need to override the defaults interactively.Smoke-check delta reuse: after the first baseline completes, run the export a second time with
--deltaand verify that the new directory reportsmode=deltawhile reusing the previous layer blob.export_root=${CONCELIER_EXPORT_ROOT:-exports/trivy} base=$(ls -1d "$export_root"/* | sort | tail -n2 | head -n1) delta=$(ls -1d "$export_root"/* | sort | tail -n1) jq -r '.mode,.baseExportId' "$delta/metadata.json" base_manifest=$(jq -r '.manifests[0].digest' "$base/index.json") delta_manifest=$(jq -r '.manifests[0].digest' "$delta/index.json") printf 'baseline manifest: %s\ndelta manifest: %s\n' "$base_manifest" "$delta_manifest" layer_digest=$(jq -r '.layers[0].digest' "$base/blobs/sha256/${base_manifest#sha256:}") cmp "$base/blobs/sha256/${layer_digest#sha256:}" \ "$delta/blobs/sha256/${layer_digest#sha256:}"cmpreturning exit code0confirms the delta export reuses the baseline’sdb.tar.gzlayer instead of rebuilding it. -
Manage scanners (optional)
dotnet run --project src/StellaOps.Cli -- scanner download --channel stable dotnet run --project src/StellaOps.Cli -- scan run --entry scanners/latest/Scanner.dll --target ./sboms dotnet run --project src/StellaOps.Cli -- scan upload --file results/scan-001.json
Add --verbose to any command for structured console logs. All commands honour
Ctrl+C cancellation and exit with non-zero status codes when the backend returns
a problem document.
4 · Verification Checklist
- Concelier
/healthreturns"status":"healthy"and Storage bootstrap is marked complete after startup. - CLI commands return HTTP 202 with a
Locationheader (job tracking URL) when triggering Concelier jobs. - Export artefacts are materialised under the configured output directories and their manifests record digests.
- MongoDB contains the expected
document,dto,advisory, andexport_statecollections after a run.
5 · Deployment Automation
- Treat
etc/concelier.yaml.sampleas the canonical template. CI/CD should copy it to the deployment artifact and replace placeholders (DSN, telemetry endpoints, cron overrides) with environment-specific secrets. - Keep secret material (Mongo credentials, OTLP tokens) outside of the repository; inject them via secret stores or pipeline variables at stamp time.
- When building container images, include
trivy-db(andorasif used) so air-gapped clusters do not need outbound downloads at runtime.
5 · Next Steps
- Enable authority-backed authentication in non-production first. Set
authority.enabled: truewhile keepingauthority.allowAnonymousFallback: trueto observe logs, then flip it tofalsebefore 2025-12-31 UTC to enforce tokens. - Automate the workflow above via CI/CD (compose stack or Kubernetes CronJobs).
- Pair with the Concelier connector teams when enabling additional sources so their module-specific requirements are pulled in safely.
6 · Authority Integration
-
Concelier now authenticates callers through StellaOps Authority using OAuth 2.0 resource server flows. Populate the
authorityblock inconcelier.yaml:authority: enabled: true allowAnonymousFallback: false # keep true only during the staged rollout window issuer: "https://authority.example.org" audiences: - "api://concelier" requiredScopes: - "concelier.jobs.trigger" clientId: "concelier-jobs" clientSecretFile: "../secrets/concelier-jobs.secret" clientScopes: - "concelier.jobs.trigger" bypassNetworks: - "127.0.0.1/32" - "::1/128" -
Store the client secret outside of source control. Either provide it via
authority.clientSecret(environment variableCONCELIER_AUTHORITY__CLIENTSECRET) or pointauthority.clientSecretFileto a file mounted at runtime. -
Cron jobs running on the same host can keep using the API thanks to the loopback bypass mask. Add additional CIDR ranges as needed; every bypass is logged.
-
Export the same configuration to Kubernetes or systemd by setting environment variables such as:
export CONCELIER_AUTHORITY__ENABLED=true export CONCELIER_AUTHORITY__ALLOWANONYMOUSFALLBACK=false export CONCELIER_AUTHORITY__ISSUER="https://authority.example.org" export CONCELIER_AUTHORITY__CLIENTID="concelier-jobs" export CONCELIER_AUTHORITY__CLIENTSECRETFILE="/var/run/secrets/concelier/authority-client" -
CLI commands already pass
Authorizationheaders when credentials are supplied. Configure the CLI with matching Authority settings (docs/09_API_CLI_REFERENCE.md) so that automation can obtain tokens with the same client credentials. Concelier logs every job request with the client ID, subject (if present), scopes, and abypassflag so operators can audit cron traffic.