Files
git.stella-ops.org/docs/modules/excititor/operations/provider-credentials.md
master df66ce10c3 feat(excititor): OCI OpenVEX artifact-backed configuration (SPRINT_20260423_001)
Closes SPRINT_20260423_001 — all 3 tasks DONE, sprint archived. Extends
the scalar persisted-settings model (7efa424fe) with an artifact-
reference storage layer for the complex OCI OpenVEX connector, which
carries image subscription lists + cosign keys + TUF roots that don't
fit the flat values/clearKeys shape.

OCI-CFG-001 — Storage model:
- New vex.provider_artifact_refs table via embedded migration
  009_vex_provider_artifact_refs.sql (auto-applied per §2.7). Columns:
  artifact_id (UUID PK), provider_id, tenant_id, mime_type, size_bytes,
  sha256, payload bytea, staged_at, staged_by. RLS via
  current_setting('app.tenant_id', TRUE); size_bytes CHECK >= 0.
- Upload / list / meta / delete API under /excititor/providers/{id}/
  artifacts. Multipart upload returns { artifactId, sha256, ... };
  meta never returns payload. Scopes: read=vex.read, write=vex.admin.
- VexProviderArtifactMaterializer: scoped session writes artifacts to
  %TMP%/stella-excititor-artifacts/<guid>/<artifactId>.bin with
  chmod 0700/0600 on POSIX; Dispose cleans up the scratch root.
  IDisposable + IAsyncDisposable, idempotent cleanup.
- PostgresVexProviderArtifactStore uses raw Npgsql for bytea I/O
  (bypasses EF compiled-model cache + change tracking); EF entity
  ProviderArtifactRefRow added for future EF-consumer completeness.

OCI-CFG-002 — Config wiring:
- VexProviderConfigurationFieldDefinition.FieldShape extended:
  scalar | list<string> | artifactRef | list<artifactRef>.
- list<string> encoded as newline-or-JSON text; artifactRef stored as
  the artifact UUID. Snapshot exposes FieldShape for clients.
- OCI-specific blocked sub-codes (all inside PROVIDER_CONFIG_INVALID /
  _REQUIRED envelope): PROVIDER_CONFIG_MISSING_IMAGE_SUBSCRIPTIONS,
  _INVALID_IMAGE_REFERENCE, _MISSING_COSIGN_KEY, _MISSING_COSIGN_ISSUER,
  _MISSING_COSIGN_SUBJECT, _MISSING_TUF_ROOT, _INVALID_COSIGN_MODE,
  _HTTP_REGISTRY_BLOCKED.
- Readiness reuses OciOpenVexAttestationConnectorOptions validator.

OCI-CFG-003 — CLI + Web:
- CLI `stella vex providers configure` flags: --image (repeatable),
  --upload-artifact <key>=@<path> (repeatable), --clear-artifact,
  --list-artifacts, --host-path-compat (CLI-only compatibility mode).
- New subcommand `stella vex providers artifacts <provider>` lists
  staged artifacts.
- OciOpenVexConfigurationComponent (Angular standalone): image-
  subscription list editor, artifact slots with file upload + staged
  meta, scalar fields for cosign mode/issuer/subject/registry auth/
  offline bundle, staged-artifact table with delete. Conditionally
  rendered in vex-provider-catalog when provider.id == 'excititor:
  oci-openvex'.
- docs/modules/excititor/operations/provider-credentials.md §5 OCI
  OpenVEX rewritten with 4 canonical setup flows: keyless, keypair,
  TUF+offline, private-registry.

Tests: targeted xUnit via scripts/test-targeted-xunit.ps1:
- VexProviderConfigurationServiceTests — 8/8 (regression)
- VexProviderOciOpenVexTests — 13/13 (OCI schema + sub-codes + artifact
  service size/quota/tenant-isolation + materializer tempfile lifecycle)

Worker-side wiring of VexProviderArtifactMaterializationSession into
DefaultVexProviderRunner (before cosign/TUF validation) is a natural
follow-up — the resolver + API + store exist; a future sprint ties
the runner into the session lifecycle when the first end-to-end OCI
provider scan lands.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 08:10:14 +03:00

13 KiB

Excititor Provider Credential Entry

Last updated: 2026-04-23

1. Purpose

Excititor now supports operator-supplied provider settings through the product surfaces operators already use:

  • Web UI provider management
  • stella vex providers configure ... in the CLI

Host configuration and environment variables remain compatibility fallbacks, but the primary operator path for supported credential-sensitive Excititor providers is persisted provider configuration owned by Stella Ops itself.

2. Operator entry paths

Web UI

Use:

  • Ops -> Integrations -> Advisory & VEX Sources -> VEX Providers

Then:

  1. Open the provider card.
  2. Open Provider Configuration.
  3. Enter or update the provider fields.
  4. Save the configuration.

Sensitive values never round-trip back to the browser. A stored secret is shown only as retained state. Leaving a password field blank keeps the retained secret. Explicitly checking the clear control removes the stored secret.

CLI

Inspect current persisted provider configuration:

stella vex providers configure excititor:cisco --server https://excititor.example.internal
stella vex providers configure excititor:suse-rancher --server https://excititor.example.internal
stella vex providers configure excititor:msrc --server https://excititor.example.internal

Update a provider:

stella vex providers configure excititor:cisco \
  --server https://excititor.example.internal \
  --set metadataUri=https://mirror.example.internal/cisco/provider-metadata.json \
  --set apiToken=...

stella vex providers configure excititor:suse-rancher \
  --server https://excititor.example.internal \
  --set discoveryUri=https://mirror.example.internal/rancher/vexhub.json \
  --set tokenEndpoint=https://auth.example.internal/oauth2/token \
  --set clientId=... \
  --set clientSecret=...

stella vex providers configure excititor:msrc \
  --server https://excititor.example.internal \
  --set tenantId=... \
  --set clientId=... \
  --set clientSecret=...

Clear stored fields:

stella vex providers configure excititor:msrc \
  --server https://excititor.example.internal \
  --clear clientSecret

Notes:

  • --set accepts key=value.
  • The current CLI path places literal values on the command line. If shell-history exposure is unacceptable for a secret, prefer the Web UI path or use an operator-approved secure shell/history procedure.

3. Blocked providers

If an operator enables a provider that still lacks required credentials or has an invalid persisted configuration, Excititor preserves the enable intent but reports the provider as blocked.

  • enabled=true means the operator wants the provider scheduled once it becomes usable.
  • readiness=blocked means the provider is intentionally on hold because required configuration is still missing or invalid.
  • Manual provider runs and batch ingest flows return a blocked result instead of pretending the provider is runnable.
  • Scheduled worker runs skip blocked providers and record the configuration reason instead of treating missing credentials as transient retry failures.

Current blocked codes:

  • PROVIDER_CONFIG_REQUIRED
  • PROVIDER_CONFIG_INVALID

4. Credential acquisition matrix

Provider Where to sign in or look What to create or capture Can the config be skipped? Entitlement / paywall notes
excititor:cisco Public Cisco CSAF metadata by default. Optional authenticated path depends on your Cisco API / mirror arrangement. Usually nothing for the default public path. Optionally capture metadataUri override and apiToken if your Cisco path requires bearer auth. Yes, for the default public Cisco CSAF metadata path. Configure it only when overriding the metadata URI or when your Cisco endpoint requires a token. No StellaOps-side paywall for the public path. Any token requirement depends on your Cisco-side arrangement, mirror, or entitlement.
excititor:suse-rancher Your Rancher Hub / SUSE-auth deployment, plus the corresponding identity provider or token service. discoveryUri, and when auth is required: tokenEndpoint, clientId, clientSecret, optional audience. Sometimes. Anonymous discovery is allowed only if the hub is intentionally exposed that way. Otherwise the authenticated fields are required together. No StellaOps-side paywall. Access depends on your Rancher Hub deployment and the identity provider that fronts it.
excititor:msrc https://entra.microsoft.com -> App registrations tenantId, clientId, clientSecret; optionally scope override if you are not using the default MSRC API scope. Not for the online MSRC client-credential path. No separate documented MSRC paywall, but you need a Microsoft Entra tenant plus permission to register the app and grant the required consent.
excititor:oci-openvex Registry, identity provider, cosign/PKI authority, and any offline artifact staging path used by your deployment. images subscription list plus cosign/TUF material. Binary material (cosign keys, TUF roots, offline bundles) is uploaded as server-side artifact references via /excititor/providers/{id}/artifacts. Image list is a flat string map entry; artifact slots carry opaque artifact IDs. Yes — images list must contain at least one valid OCI reference. Sprint 20260423_001 shipped the artifact-backed configuration path. Depends on your registry, cosign, and offline bundle environment.

5. What operators should actually look for

Cisco CSAF

  • No login is needed for the default public Cisco CSAF metadata path.
  • Only collect metadataUri when pointing Excititor at an approved internal mirror.
  • Only collect apiToken when your Cisco-side path or mirror explicitly requires a bearer token.

SUSE Rancher VEX Hub

  • Rancher hub discovery document URI
  • OAuth or OIDC token endpoint when the hub requires authentication
  • Client ID and client secret for the hub reader application
  • Optional audience value when your token service requires it

Microsoft MSRC

  • Microsoft Entra Directory (tenant) ID
  • Microsoft Entra Application (client) ID
  • A newly created Client secret value
  • Confirm the app consent and scope expected by your MSRC onboarding process before storing the values in Stella Ops

OCI OpenVEX

Sprint 20260423_001 OCI-CFG-001/002/003 wired the artifact-backed configuration path.

The OCI OpenVEX provider carries configuration shapes the scalar settings store cannot cleanly absorb: a variable-length list of image subscriptions and binary cosign / TUF material that must not round-trip on reads. The implementation keeps the scalar settings JSONB column a flat string map and introduces a sibling artifact-reference store (vex.provider_artifact_refs) for binary material. The settings JSONB references artifact rows by opaque GUID.

4.1 Shape of the configuration

Field Shape Notes
images list<string> One OCI reference per line. At least one entry is required before the provider can run. Invalid references surface as PROVIDER_CONFIG_INVALID with sub-code PROVIDER_CONFIG_INVALID_IMAGE_REFERENCE. HTTP (non-TLS) registries are rejected unless allowHttpRegistries=true (sub-code PROVIDER_CONFIG_HTTP_REGISTRY_BLOCKED).
cosignMode scalar (None | Keyless | KeyPair) Controls which cosign verification material is required. Invalid modes surface as sub-code PROVIDER_CONFIG_INVALID_COSIGN_MODE.
cosignIssuer, cosignSubject scalar Required when cosignMode=Keyless. Sub-codes: PROVIDER_CONFIG_MISSING_COSIGN_ISSUER, PROVIDER_CONFIG_MISSING_COSIGN_SUBJECT.
cosignKey artifactRef Required when cosignMode=KeyPair. Staged artifact ID pointing to a PEM public/private key file. Sub-code PROVIDER_CONFIG_MISSING_COSIGN_KEY.
cosignCertificate artifactRef Optional certificate paired with the cosign key.
tufRoots list<artifactRef> One or more TUF root.json artifacts providing offline trust material. Sub-code PROVIDER_CONFIG_MISSING_TUF_ROOT when a TUF-dependent path requires one.
registryAuthority, registryUsername, registryPassword scalar Optional basic-auth / token material for private registries. registryPassword is sensitive: retained on blank save, cleared only via clearKeys.
allowHttpRegistries scalar bool Default false. Must be explicitly set to true to permit non-TLS registries.
offlineBundleRoot scalar Server-side path to offline attestation bundles. Leave blank when bundles are uploaded via the artifact path.

4.2 Artifact-staging API

Verb Path Purpose
POST /excititor/providers/{id}/artifacts Multipart upload (file field). Returns { artifactId, sha256, mime, sizeBytes, stagedAt }. The SHA-256 is the only payload-derived echo.
GET /excititor/providers/{id}/artifacts Lists staged artifacts for the provider (metadata only).
GET /excititor/providers/{id}/artifacts/{artifactId}/meta Returns the metadata projection for a single artifact. NEVER returns the payload.
DELETE /excititor/providers/{id}/artifacts/{artifactId} Removes a staged artifact.

Size caps: 10 MiB per artifact, 50 MiB per provider total. Tunable via Excititor:ProviderArtifacts:MaxArtifactSizeBytes / MaxProviderTotalSizeBytes environment settings. Cap violations surface as HTTP 400 with error codes ARTIFACT_TOO_LARGE / ARTIFACT_PROVIDER_QUOTA_EXCEEDED. Tenant isolation is enforced via RLS on vex.provider_artifact_refs.tenant_id.

At runtime, cosign/TUF verification libraries need on-disk paths. The effective-settings resolver materializes referenced artifacts to a per-request scratch directory (chmod 0700 on POSIX) and cleans up on session dispose — see VexProviderArtifactMaterializer.

4.3 Canonical setup flows

A. Keyless Sigstore, single image, default registry:

stella vex providers configure excititor:oci-openvex \
  --server https://excititor.example.internal \
  --image ghcr.io/acme/app:v1.2.3 \
  --set cosignMode=Keyless \
  --set cosignIssuer=https://token.actions.githubusercontent.com \
  --set cosignSubject='https://github.com/acme/repo/.github/workflows/release.yml@refs/tags/v1.*'

B. KeyPair cosign verification with operator-supplied public key:

stella vex providers configure excititor:oci-openvex \
  --server https://excititor.example.internal \
  --image ghcr.io/acme/app:v1 \
  --image ghcr.io/acme/sidecar:v1 \
  --set cosignMode=KeyPair \
  --upload-artifact cosignKey=@/secure/cosign/cosign.pub \
  --upload-artifact cosignCertificate=@/secure/cosign/cosign.crt

C. TUF trust roots + offline bundle:

stella vex providers configure excititor:oci-openvex \
  --server https://excititor.example.internal \
  --image registry.example.com/platform/base@sha256:... \
  --upload-artifact tufRoots=@/air-gap/tuf/root.json \
  --set offlineBundleRoot=/var/lib/stella/offline/openvex

D. Private registry with basic auth:

stella vex providers configure excititor:oci-openvex \
  --server https://excititor.example.internal \
  --image internal.registry.example.com/team/app:v3 \
  --set registryAuthority=internal.registry.example.com:5000 \
  --set registryUsername=stella-reader \
  --set registryPassword=<token>

4.4 Host-path compatibility (CLI only)

The CLI exposes --host-path-compat to preserve the legacy flow where cosign/TUF material is referenced by absolute path instead of uploaded as an artifact. Use it only when the Excititor server shares a filesystem with the operator workstation (typically a single-node sealed deployment). The UI deliberately never surfaces file-path inputs because the server cannot read arbitrary host paths in production-scale deployments. Host-path mode is visible in CLI --help as a compatibility-only flag.

4.5 Listing and clearing staged artifacts

# Show all artifacts staged against a provider
stella vex providers artifacts excititor:oci-openvex

# Clear a field's artifact binding (leaves the staged blob — delete the blob separately if unused)
stella vex providers configure excititor:oci-openvex --clear-artifact cosignCertificate

4.6 UI

The Web panel renders conditionally from the existing Advisory & VEX Sources detail flow when provider.kind === 'oci-openvex' (or the provider id matches excititor:oci-openvex). It provides the image-subscription list editor, artifact-reference slots with upload + staged-meta rendering, and a readiness hint surface for the OCI-specific blocked sub-codes. File-path inputs are intentionally omitted from the UI — use the CLI for host-path compat when that flow is needed.

6. References