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>
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:
- Open the provider card.
- Open Provider Configuration.
- Enter or update the provider fields.
- 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:
--setacceptskey=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=truemeans the operator wants the provider scheduled once it becomes usable.readiness=blockedmeans 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_REQUIREDPROVIDER_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
metadataUriwhen pointing Excititor at an approved internal mirror. - Only collect
apiTokenwhen 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
- Microsoft Entra app registration quickstart: https://learn.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app
- Microsoft Entra application credentials: https://learn.microsoft.com/en-us/entra/identity-platform/how-to-add-credentials