* feat(bp-newapi): chart maturation — ExternalSecret + first-otech vLLM channel + skip-render gates (#799)
Maturation work for the SME-3 turnkey-experience epic (#795). Aligns
the bp-newapi scratch chart with ADR-0003 (RBAC ↔ NewAPI user-create
hook contract) and gets it past the blueprint-release CI smoke render
that has blocked publication since PR #396 (run 25213444992 failed at
default-values render of v1.0.0).
Changes
-------
- templates/external-secret.yaml (NEW). Renders the
`catalyst-newapi-admin-token` ExternalSecret consumed by unified-rbac
(ADR-0003 §3.2 + §6) for issuing per-user keys against
`http://newapi.newapi.svc/api/v1/admin/users`. Sourced from OpenBao
via the `vault-region1` ClusterSecretStore (canonical default shipped
by bp-external-secrets-stores). Capabilities-gated on
`external-secrets.io/v1beta1` so cold installs without ESO don't
fail-render. Operator supplies the per-Sovereign OpenBao path via
`catalystIntegration.externalSecret.remoteRef.key`; canonical
convention is `sovereign/<sovereign-fqdn>/newapi/admin-token` with
property `ADMIN_API_TOKEN`. Per Inviolable Principle #4 every knob
is operator-overridable in the cluster overlay.
- values.yaml. Adds `catalystIntegration.externalSecret.{enabled,
refreshInterval, secretStoreRef.{kind,name}, remoteRef.{key,property}}`
block (default enabled=true, key="" so a misconfigured overlay fails
loudly at render rather than silently skipping). Adds
`defaultChannels.vllm` block — first-otech shorthand that composes a
vLLM-typed channel into the rendered channels list when enabled.
Default endpoint is empty per Inviolable Principle #4; the
`clusters/<sovereign>/bootstrap-kit/80-newapi.yaml` overlay supplies
the per-Sovereign URL (canonical first-otech reference =
`https://llm-api.omtd.bankdhofar.com` model `qwen3-coder`, the same
upstream Axon uses on the OpenOva marketing deployment).
- templates/_helpers.tpl. New `bp-newapi.effectiveChannels` helper
composes `.Values.channels` with `defaultChannels.vllm` (when
enabled). The `assertChannelAttestation` helper now operates on the
effective list so attestation gates apply to defaultChannels
composition too. `defaultChannels.vllm.enabled=true` with empty
endpoint fails-fast at render with a guided error message.
- templates/configmap.yaml. Channels rendering switches to the
effectiveChannels helper. OIDC block now skip-renders gracefully when
`auth.adminUI.keycloak.issuer` is unset (smoke-render path) instead
of `required`-failing; the per-Sovereign overlay sets the issuer.
- templates/deployment.yaml. Skip-render gate on Deployment when
`database.existingSecret`, `credentials.existingSecret`, or (when
Keycloak mode is selected) the OIDC client secret is missing. Removes
the four `required` calls that were failing CI smoke render. Service,
ServiceAccount, ConfigMap, NetworkPolicy still render so the smoke
test gets a non-empty output proving structural soundness; the actual
Deployment defers until the per-Sovereign overlay wires the secrets.
- templates/ingress.yaml. Same skip-render pattern: when either
`ingress.host` or `ingress.adminHost` is empty, the entire ingress
block is silently skipped. Matches the bp-keycloak / bp-openbao /
bp-external-dns HTTPRoute templates.
- Chart.yaml. version 1.0.0 → 1.1.0 (minor bump — additive features;
no breaking changes to existing operator overrides).
Verification
------------
`helm template` smoke render on default values now succeeds with 4
resources (NetworkPolicy / ServiceAccount / ConfigMap / Service); 168
lines, well above the CI 5-line minimum. With a full per-Sovereign
overlay (hosts + secrets + Keycloak issuer + ESO Capabilities + Traefik
Capabilities + defaultChannels.vllm.endpoint), 8 resources render
including Deployment, both Ingresses, the Traefik allowlist Middleware,
and the ExternalSecret. The composed qwen channel writes through to
`channels.yaml` with the expected endpoint + models + attestation.
Refs
----
ADR-0003 §3.2 + §6 — admin-token contract
Issue #795 (epic) — locked decisions
Issue #796 — hook contract spec (sequential blocker, merged)
Inviolable Principles #1, #3, #4
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(bootstrap-kit): slot 80 — bp-newapi default install (#799)
Adds the canonical install slot for bp-newapi to every fresh Sovereign's
bootstrap-kit. Sequenced after the W2.K1 dependency wave so NewAPI's
ExternalSecret + Postgres DSN dependencies resolve on first reconcile.
The HelmRelease declares `dependsOn: [bp-openbao, bp-keycloak, bp-cnpg]`:
- bp-openbao(08): admin-token ExternalSecret backend
- bp-keycloak(09): OIDC issuer for ops-staff admin UI at admin.<fqdn>
- bp-cnpg(16): Postgres backing for users/credits/channels/audit
Per-Sovereign overlays inherit the slot's defaults and override:
- ingress.host api.${SOVEREIGN_FQDN}
- ingress.adminHost admin.${SOVEREIGN_FQDN}
- auth.adminUI.keycloak.issuer
- database.existingSecret (Crossplane-claimed)
- credentials.existingSecret
- catalystIntegration.externalSecret.remoteRef.key sovereign/${FQDN}/newapi/admin-token
- defaultChannels.vllm.enabled true (first-otech)
- defaultChannels.vllm.endpoint (operator-supplied)
The `_template/` slot keeps `defaultChannels.vllm.enabled: false` so a
fresh Sovereign does not silently wire customers to a third-party
endpoint; the canonical first-otech reference (Qwen3 Coder via
`https://llm-api.omtd.bankdhofar.com`, same relay Axon uses on the
OpenOva marketing deployment) is documented in-line for operators
adopting the same upstream.
Refs: #795 (epic), ADR-0003
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(bootstrap-deps): register bp-newapi slot 80 in expected DAG (#799)
Fixes the dependency-graph-audit drift detection caught at PR #812 CI:
the audit script enumerates HelmReleases in clusters/_template/bootstrap-kit/
and compares to scripts/expected-bootstrap-deps.yaml; an HR present on
disk but absent from the expected DAG is treated as drift.
Adds the canonical entry for bp-newapi at slot 80 with the same
depends_on set declared on the HelmRelease itself
([bp-openbao, bp-keycloak, bp-cnpg]).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(bp-newapi): align blueprint.yaml spec.version with Chart.yaml (#799)
The TestBootstrapKit_BlueprintCardsHaveRequiredFields static-validation
gate asserts Chart.yaml version == blueprint.yaml spec.version. The
chart was bumped to 1.1.0 in c63ecd8c; bumping the blueprint metadata
to match.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Hatice Yildiz <hatice.yildiz@openova.io>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>