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>
This commit is contained in:
@@ -1,84 +0,0 @@
|
||||
# Sprint 20260423-001 — Excititor OCI OpenVEX artifact-backed configuration
|
||||
|
||||
## Topic & Scope
|
||||
- Implement the complex `excititor:oci-openvex` configuration path separated out of SPRINT_20260422_007 (EXCITITOR-CFG-04 was BLOCKED there because it needs a distinct secret-reference / artifact-reference storage model that the scalar-settings path can't cleanly absorb).
|
||||
- OCI OpenVEX connector configuration carries nested data that does not fit the flat string-map pattern the persisted-settings contract was designed for: image subscription lists (often dozens per tenant), registry credentials, cosign signature verification material (public keys, TUF trust roots, Fulcio identity constraints), and optional offline bundle inputs.
|
||||
- Working directory: `src/Concelier/__Libraries/StellaOps.Excititor.Core/`, `StellaOps.Excititor.Connectors.OCI.OpenVEX.Attest/`, `StellaOps.Excititor.Persistence/`, `StellaOps.Excititor.WebService/`, plus CLI + Web surfaces.
|
||||
- Expected evidence: new artifact-reference storage model, `VexProviderConfigurationService` extended for non-scalar field types, CLI + Web entries for the nested shape, focused tests, operator docs.
|
||||
|
||||
## Dependencies & Concurrency
|
||||
- Upstream: SPRINT_20260422_007 EXCITITOR-CFG-01/02/03 (archived via commit `7efa424fe`) shipped the scalar persisted-settings machinery. This sprint extends it for complex types.
|
||||
- Adjacent: SPRINT_20260422_008 FE-STAB4 (open, FE suite work) — no overlap.
|
||||
- Safe parallelism: stays within `src/Concelier/__Libraries/StellaOps.Excititor.*` + Excititor WebService + CLI + Web OCI configuration panel.
|
||||
|
||||
## Documentation Prerequisites
|
||||
- `docs-archived/implplan/SPRINT_20260422_007_Concelier_excititor_persisted_provider_credentials.md` — baseline CFG-01/02/03 contract.
|
||||
- `src/Concelier/__Libraries/StellaOps.Excititor.Connectors.OCI.OpenVEX.Attest/OciOpenVexAttestationConnectorOptions.cs` — the real options validator to reuse.
|
||||
- `docs/modules/excititor/operations/provider-control-plane.md` — current credential-entry dossier to extend.
|
||||
|
||||
## Delivery Tracker
|
||||
|
||||
### OCI-CFG-001 — Design + implement a staged artifact-reference storage model
|
||||
Status: TODO
|
||||
Dependency: none
|
||||
Owners: Developer / Implementer
|
||||
Task description:
|
||||
- Extend `vex.provider_settings` (or add a sibling table `vex.provider_artifact_refs`) so settings can carry references to server-side staged artifacts rather than inlined binary material. A reference is an opaque, operator-uploaded blob identified by an ID, mime type, and optional checksum / signature.
|
||||
- Define a minimal artifact-staging API: `POST /excititor/providers/{id}/artifacts` (multipart upload or base64) returning `{ artifactId, sha256 }`; `GET /excititor/providers/{id}/artifacts/{artifactId}/meta` for inspection (never returns the binary itself after staging); `DELETE` for removal.
|
||||
- Artifacts live server-side with tenant isolation (RLS) and a size cap (e.g. 10 MiB per artifact, 50 MiB per provider total).
|
||||
- Settings JSONB references artifacts by ID; the effective-settings resolver swaps refs for file-system-scoped material at runtime (e.g. writes a temp file to pass to cosign's verification library, then cleans up).
|
||||
|
||||
Completion criteria:
|
||||
- [ ] Artifact-reference storage schema + migration (embedded, auto-applied per §2.7).
|
||||
- [ ] Upload / meta / delete API with size-cap enforcement + tenant RLS.
|
||||
- [ ] Effective-settings resolver materializes artifact refs to disk for runtime consumption, cleaning up after.
|
||||
- [ ] Secrets never echoed on read — meta endpoint returns only `{ artifactId, sha256, mime, sizeBytes, stagedAt }`.
|
||||
|
||||
### OCI-CFG-002 — Wire OCI OpenVEX provider configuration to the new model
|
||||
Status: TODO
|
||||
Dependency: OCI-CFG-001
|
||||
Owners: Developer / Implementer
|
||||
Task description:
|
||||
- `VexProviderConfigurationService` must support nested field types: `artifactRef`, `list<string>` (image subscriptions), `list<artifactRef>` (multi-key / multi-TUF-root).
|
||||
- Reuse `OciOpenVexAttestationConnectorOptions` validator to compute readiness. Blocked reasons must be operator-facing: `PROVIDER_CONFIG_MISSING_COSIGN_KEY`, `PROVIDER_CONFIG_INVALID_IMAGE_REFERENCE`, etc. — sub-codes within the existing `PROVIDER_CONFIG_INVALID` envelope.
|
||||
- Worker + orchestrator paths: no change — they already read through the effective-settings resolver which now transparently materializes artifact refs.
|
||||
|
||||
Completion criteria:
|
||||
- [ ] OCI provider field schema exposes all 3 complex field types.
|
||||
- [ ] Validator-backed readiness surfaces OCI-specific missing-material reasons.
|
||||
- [ ] Targeted tests cover ready vs blocked vs invalid cases.
|
||||
|
||||
### OCI-CFG-003 — CLI + Web surfaces for complex fields
|
||||
Status: TODO
|
||||
Dependency: OCI-CFG-002
|
||||
Owners: Developer / Implementer, Documentation author
|
||||
Task description:
|
||||
- CLI: `stella vex providers configure excititor:oci-openvex --image ghcr.io/foo/bar:v1 --image ...` (repeatable), `--upload-artifact cosign-key=@/path/to/cosign.pub`, `--clear-artifact cosign-key`, `--list-artifacts`. Host-path inputs explicitly supported behind a `--host-path-compat` flag and marked in CLI help as compatibility mode (CLI-only, never surfaced in UI).
|
||||
- Web: new `OciOpenVexConfigurationComponent` (Angular standalone) with:
|
||||
- image subscription list editor (add/remove rows, chip view).
|
||||
- artifact-reference slots with upload + staged-secret rendering (similar masked-secret pattern).
|
||||
- readiness panel showing the OCI-specific blocked reasons inline with the offending field.
|
||||
- Routing: attach to the existing advisory-vex-sources detail flow via a conditional render when `provider.kind == 'oci-openvex'`.
|
||||
- Docs: extend `docs/modules/excititor/operations/provider-credentials.md` with an OCI OpenVEX operator dossier (image subscription list management, cosign material acquisition, TUF root setup if applicable, offline bundle flow if retained).
|
||||
|
||||
Completion criteria:
|
||||
- [ ] CLI commands cover list + upload + clear per artifact + image subscription editing.
|
||||
- [ ] Web OCI configuration component renders + submits correctly against the new API.
|
||||
- [ ] Operator doc updated with walk-through for the 3–4 canonical OCI OpenVEX setup shapes.
|
||||
|
||||
## Execution Log
|
||||
| Date (UTC) | Update | Owner |
|
||||
| --- | --- | --- |
|
||||
| 2026-04-23 | Sprint created by splitting EXCITITOR-CFG-04 out of SPRINT_20260422_007 (now archivable). OCI artifact-backed configuration needs its own storage-model design — scalar settings store can't absorb image subscription lists + binary credential material cleanly. | Claude |
|
||||
|
||||
## Decisions & Risks
|
||||
- **Decision**: artifact-reference table is a sibling of `vex.provider_settings`, not an extension of the JSONB column. Keeps scalar-settings semantics simple and lets binary material use its own RLS-enforced storage with size caps.
|
||||
- **Decision**: host-path compat stays in CLI only, flagged. The UI must not surface file paths on an operator's host because the server won't be able to read them in production deployments.
|
||||
- **Risk**: cosign/TUF verification libraries generally want on-disk paths. Mitigation: effective-settings resolver writes tempfiles per-request, ensures cleanup, keeps the temp directory chmod'd appropriately.
|
||||
- **Risk**: artifact size caps (10 MiB per artifact, 50 MiB per provider) may be too tight for some TUF-root scenarios. Mitigation: caps are soft + configurable via platform environment settings; document the tunable.
|
||||
- **Risk**: nested field types (`list<artifactRef>`) change the `values/clearKeys` API shape. Mitigation: keep the scalar shape unchanged, introduce a separate `/artifacts` endpoint path so the existing client code on scalar providers doesn't regress.
|
||||
|
||||
## Next Checkpoints
|
||||
- OCI-CFG-001 DONE: artifact-reference schema + upload/meta/delete API + effective-settings materializer.
|
||||
- OCI-CFG-002 DONE: OCI provider wired to the new model; validator-backed OCI-specific blocked reasons.
|
||||
- OCI-CFG-003 DONE: CLI + Web + docs; sprint archivable when worker can run a sealed OCI OpenVEX provider end-to-end.
|
||||
Reference in New Issue
Block a user