Commit Graph

11 Commits

Author SHA1 Message Date
e3mrah
746901b671
feat(cnpg-pair): C-DB-1 — bp-cnpg-pair Blueprint (active-hotstandby CNPG cluster-pair across regions) (#1101) (#1153)
EPIC-6 Slice C-DB-1+C-DB-2. Active-hotstandby CNPG cluster-pair as a
companion to bp-cnpg: primary CNPG Cluster CR in region A, replica
Cluster CR in region B configured as a CNPG replica cluster
(replica.enabled=true + externalCluster), WAL streaming over a
Cilium ClusterMesh-shared Service. Per ADR-0001 §9 ClusterMesh is the
only canonical inter-region transport — never public TLS.

What ships:
  platform/cnpg-pair/
  ├── chart/
  │   ├── Chart.yaml             # bp-cnpg-pair 0.1.0; no-upstream + smoke-render-mode=default-off
  │   ├── values.yaml            # default-OFF gate; placement schema constrains active-hotstandby ONLY
  │   ├── templates/
  │   │   ├── _helpers.tpl              # fail-fast on empty image.tag; region pair validation
  │   │   ├── primary-cluster.yaml      # CNPG Cluster CR (region-pinned via openova.io/region affinity)
  │   │   ├── replica-cluster.yaml      # CNPG Cluster CR (replica.enabled=true; externalClusters[])
  │   │   ├── service-replication.yaml  # Cilium ClusterMesh global Service
  │   │   ├── failover-readiness.yaml   # probe Pod flips Ready when WAL lag < threshold
  │   │   ├── networkpolicy.yaml        # default-deny carve-outs for replication + probe
  │   │   └── audit-config.yaml         # NATS audit subjects + types this Blueprint emits
  │   ├── blueprint.yaml          # configSchema + placementSchema (active-hotstandby ONLY)
  │   ├── README.md               # 80-line deployment + failover semantics
  │   └── tests/cnpg-pair-render.sh  # 5-case render gate
  └── DESIGN.md                   # topology, lag-threshold rationale, deferred C-DB-3 plan

Default-OFF gate per the brief: helm template with default values
renders ZERO resources; helm template with cnpgPair.enabled=true +
both regions + image.tag renders 8 resources (2 Cluster CRs, 1
Service, 1 Deployment, 3 NetworkPolicies, 1 audit-config ConfigMap).
Empty image.tag fails fast at template-render per Inviolable
Principle #4a; same primary/replica region fails fast (degenerate
pair). All 5 render gates pass locally; helm lint + YAML parse clean.

CI smoke-render gate fix (single-line behavior change in
blueprint-release.yaml): adds a `catalyst.openova.io/smoke-render-
mode: default-off` annotation opt-in so charts that legitimately
render zero at default values (this chart + future bp-*-pair
Blueprints) skip the `<5 lines` empty-render check. The chart's own
tests/cnpg-pair-render.sh covers the enabled-render path; without
the annotation the empty-render check still fires unchanged.

Seam-map additions (return diff for 01-canonical-seams.md Platform
table):
  - service.cilium.io/global=true ClusterMesh global Service annotation
    (first chart in the repo to use it; pattern reused by Continuum
    K-Cont-2 for HTTPRoute weight=0 cross-region drains)
  - bp-*-pair active-hotstandby cluster-pair pattern (primary+replica
    Cluster CRs colocated in one Blueprint, region-pinned via
    openova.io/region node-affinity)
  - audit-config ConfigMap co-located with the emitting Blueprint
    (label-selector discovery for K-Cont-2 + U-DR-1; future
    bp-*-pair Blueprints follow this convention)
  - smoke-render-mode=default-off Chart.yaml annotation opt-in for
    the blueprint-release smoke gate

C-DB-2 (publish): existing blueprint-release.yaml workflow auto-
detects `platform/*/chart/**` paths — no allowlist edit required.
First push triggers `ghcr.io/openova-io/bp-cnpg-pair:0.1.0` build.

C-DB-3 (1M-row acceptance test) DEFERRED — full plan documented in
DESIGN.md "Deferred — C-DB-3 acceptance test plan" section so the
future implementer's brief is self-contained.

Tests:
  - bash platform/cnpg-pair/chart/tests/cnpg-pair-render.sh ✓ 5/5 PASS
  - helm lint platform/cnpg-pair/chart ✓ clean
  - helm template ... | python3 yaml.safe_load_all ✓ 8 docs parse clean
  - smoke-gate logic simulated locally ✓ default-off annotation honored

Pre-existing CI failures untouched:
  - TestPinIssue rate-limit flake — not affected by chart-only slice
  - TestBootstrapKit/gitea version drift — only iterates over a fixed
    10-chart bootstrap list (no cnpg-pair entry)

Out of scope per brief (all deferred to dedicated slices):
  - K-Cont-2 reconciler logic
  - K-Cont-3 lease witness
  - K-Cont-4 Cloudflare Worker
  - C-DB-3 1M-row acceptance test
  - Application controller changes
  - U-DR-1 UI

Co-authored-by: hatiyildiz <hati.yildiz@openova.io>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 05:16:55 +04:00
e3mrah
2de8bb68b9
fix(ci): bump helm 3.16.3 → 3.18.4 in blueprint-release — fixes seaweedfs smoke-render (#336)
'function fromToml not defined' error on bp-seaweedfs publish.
Upstream seaweedfs/seaweedfs 4.22.0 (templates/shared/security-configmap.yaml:21)
uses fromToml which exists in 3.13+ but the rendered context in the smoke
step needs newer Sprig functions present in 3.18+. Bump unblocks the
chain of HRs (bp-loki, bp-mimir, bp-tempo, bp-velero, bp-harbor, bp-grafana)
all blocked on bp-seaweedfs publish.

Co-authored-by: hatiyildiz <hatice.yildiz@openova.io>
2026-04-30 23:27:45 +04:00
e3mrah
2d1799d738
fix(bp-crossplane): split XRDs+Compositions into bp-crossplane-claims (#247)
Resolves install ordering on fresh clusters where the apiserver rejects
CompositeResourceDefinition CRs because the apiextensions.crossplane.io
CRDs registered by the crossplane subchart aren't live yet at apply time.

- bp-crossplane bumped 1.1.2 -> 1.1.3 (controller-only payload)
- NEW bp-crossplane-claims@1.0.0 carries XRDs + Compositions
- Flux HelmRelease for crossplane-claims uses dependsOn: [bp-crossplane]
- composition-validate.sh + fixtures relocate to the new chart
- blueprint-release CI: opt-out annotation
  catalyst.openova.io/no-upstream=true permits zero-deps charts that
  legitimately ship only Catalyst-authored CRs (the original hollow-chart
  rule remains in force for every other umbrella chart)

Live error this fixes (from otech.omani.works):
  no matches for kind "CompositeResourceDefinition" in version
  "apiextensions.crossplane.io/v1" -- ensure CRDs are installed first

Pattern: intra-chart CRD-ordering breaks -> split charts + Flux dependsOn.
Apply universally to similar cases going forward.

Co-authored-by: hatiyildiz <hatice.yildiz@openova.io>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 16:55:05 +04:00
hatiyildiz
d34facc040 fix(bp-*): observability toggles default false — break circular CRD dependency
bp-cilium@1.1.0 install fails on every fresh Sovereign with:

  no matches for kind "ServiceMonitor" in version "monitoring.coreos.com/v1"
  — ensure CRDs are installed first

Cascades to all 10 other bp-* HelmReleases ("dep is not ready") since
bp-cilium is the root of the bootstrap dep graph. Verified live on
omantel.omani.works 2026-04-29 (issue #182).

Root cause: platform/cilium/chart/values.yaml and
platform/cert-manager/chart/values.yaml hardcoded
`serviceMonitor.enabled: true`. The monitoring.coreos.com/v1 CRDs ship
with kube-prometheus-stack — an Application-tier Blueprint that itself
depends on the bootstrap-kit. Hardcoding `true` creates a circular CRD
ordering: bp-cilium wants the CRD bp-kube-prometheus-stack provides, but
bp-kube-prometheus-stack cannot install before bp-cilium.

The `trustCRDsExist=true` mitigation only suppresses Helm's render-time
gate; the apiserver still rejects the resource at install-time.

Violates INVIOLABLE-PRINCIPLES.md #4 (never hardcode): observability
toggles MUST be operator-tunable, not chart-level constants assuming an
observability tier exists.

This commit:

A. Defaults every observability toggle false in the affected wrappers:
   - platform/cilium/chart/values.yaml:
     cilium.prometheus.enabled: false
     cilium.prometheus.serviceMonitor.enabled: false
     (trustCRDsExist removed — no longer relevant)
   - platform/cert-manager/chart/values.yaml:
     cert-manager.prometheus.enabled: false
     cert-manager.prometheus.servicemonitor.enabled: false
   - platform/crossplane/chart/values.yaml:
     crossplane.metrics.enabled: false
     (uniformity rule — does not break install but holds the invariant)

B. Bumps affected wrapper charts 1.1.0 → 1.1.1:
   - bp-cilium, bp-cert-manager, bp-crossplane (leaves)
   - bp-catalyst-platform (umbrella; deps repinned to 1.1.1 for the 3)

C. Updates clusters/_template/bootstrap-kit/* and
   clusters/omantel.omani.works/bootstrap-kit/* HelmRelease versions to
   1.1.1 so the live Sovereign picks up the fix on Flux reconcile.

D. Adds platform/<name>/chart/tests/observability-toggle.sh under each
   affected chart. Each script asserts:
     - default render produces zero monitoring.coreos.com refs
     - opt-in render with --set <toggle>=true succeeds and produces a
       ServiceMonitor (proves the toggle is wired)
     - explicit-off render succeeds and produces zero refs
   Wired into .github/workflows/blueprint-release.yaml via a new
   "Run chart integration tests" step that executes every chart/tests/
   *.sh on every publish — a regression that re-introduces a hardcoded
   `true` fails the publish job before the OCI artifact is pushed.

E. Documents the rule in docs/BLUEPRINT-AUTHORING.md §11.2
   "Observability toggles must default false". References Principle #4
   and provides the canonical pattern (default off in wrapper values,
   opt-in via per-cluster overlay at clusters/<sovereign>/...).

Per-chart audit table (which toggle was hardcoded → new default):

| Chart            | Toggle                                                   | Was  | Now   |
|------------------|----------------------------------------------------------|------|-------|
| bp-cilium        | cilium.prometheus.enabled                                | true | false |
| bp-cilium        | cilium.prometheus.serviceMonitor.enabled                 | true | false |
| bp-cert-manager  | cert-manager.prometheus.enabled                          | true | false |
| bp-cert-manager  | cert-manager.prometheus.servicemonitor.enabled           | true | false |
| bp-crossplane    | crossplane.metrics.enabled                               | true | false |
| bp-flux          | (no observability hardcodes)                             | n/a  | n/a   |
| bp-sealed-secrets| (no observability hardcodes)                             | n/a  | n/a   |
| bp-spire         | (no observability hardcodes)                             | n/a  | n/a   |
| bp-nats-jetstream| (no observability hardcodes)                             | n/a  | n/a   |
| bp-openbao       | (no observability hardcodes)                             | n/a  | n/a   |
| bp-keycloak      | (no observability hardcodes)                             | n/a  | n/a   |
| bp-gitea         | (no observability hardcodes)                             | n/a  | n/a   |
| bp-powerdns      | (no observability hardcodes)                             | n/a  | n/a   |
| bp-catalyst-platform | (umbrella, no values overlay)                        | n/a  | n/a   |

Local gates green:
  helm dep build      ✓ all 3 affected charts
  helm lint           ✓ all 3
  helm template       ✓ all 3 — 0 monitoring.coreos.com refs in default
  tests/observability-toggle.sh  ✓ all 9 sub-cases pass

Closes the install path for bp-cilium 1.1.1 on a fresh Sovereign;
unblocks the full bp-* dep graph.

Refs: https://github.com/openova-io/openova/issues/182

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 18:08:09 +02:00
hatiyildiz
35dcb84de1 fix(blueprint-release): Guard 3 reads Chart.yaml at GITHUB_WORKSPACE-rooted path
`helm pull --destination /tmp/pulled` is the right shape; the previous
`cd /tmp/pulled && helm pull ...` made yq's read of
`platform/<name>/chart/Chart.yaml` resolve relative to /tmp/pulled and
fail with "no such file or directory" before any subchart check ran.

Drops the cd, anchors chart_yaml on $GITHUB_WORKSPACE, passes
--destination to helm pull. Guards 1 and 2 do not cd anywhere and stay
unchanged.

Caught by the first dispatch on bp-cilium + bp-cert-manager — both
artifacts pushed to GHCR successfully and the listing line
("pulled entries: 159" for bp-cilium) confirmed the upstream subchart
bytes are in the OCI artifact; the guard logic just couldn't read
Chart.yaml to enumerate which deps to verify against.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 17:47:35 +02:00
hatiyildiz
54418bd5c9 feat(blueprint-release): verify upstream subchart present at every step (build/package/push/pull)
Hardens .github/workflows/blueprint-release.yaml against the
"hollow chart" failure mode that broke Phase 1 on every Sovereign
when bp-cert-manager:1.0.0 published as an empty wrapper carrying
only a ClusterIssuer overlay with no upstream cert-manager
subchart bytes inside the OCI artifact.

Adds four structural guards on every Blueprint publish:

  Guard 1 (post helm-dependency-build) — for each entry in
    Chart.yaml `dependencies:`, assert chart/charts/<dep>-<ver>.tgz
    OR chart/charts/<dep>/Chart.yaml exists. Zero declared deps =
    explicit hollow-chart failure with a link to issue #181 and
    BLUEPRINT-AUTHORING.md §11.1 in the error message.

  Guard 2 (post helm-package) — `tar -tzf` the produced .tgz and
    assert each declared subchart is inside <chart_name>/charts/
    in the package itself, not just in the working tree.

  Guard 3 (post helm-push) — `helm pull` the artifact back from
    GHCR and re-verify deps survived the round-trip; catches any
    registry-side stripping or path mangling.

  Smoke step — `helm template` the packaged chart with default
    values; render must succeed and produce non-trivial output;
    rendered manifests upload as a workflow artifact for forensics
    on every run (success or fail).

Uses yq (v4.44.3 pinned) for streaming YAML parsing of the
declared `dependencies:` block — awk/grep on YAML is too fragile
to be the structural guard against hollow charts.

Documents the contract in docs/BLUEPRINT-AUTHORING.md §11.1
"Umbrella shape (hard contract — CI-enforced)" — every Blueprint
chart at platform/<name>/chart/ MUST declare upstream deps under
`dependencies:`, the four CI guards above structurally enforce it,
and the verifying-an-existing-artifact recipe (`helm pull` + `tar
tzf | grep`) is documented so the contract is operator-checkable
post-publish.

Preserves the per-Blueprint matrix shape and the
`workflow_dispatch.inputs.{blueprint,tree}` contract; no changes
to any Blueprint's Chart.yaml.

Closes #181

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 17:45:43 +02:00
hatiyildiz
3864eef4e7 docs(reconcile-pass-2): align docs with ground truth at 6afdb303
- Wizard step canonical order updated to Org → Topology → Provider →
  Credentials → Components → Domain → Review (RUNBOOK-PROVISIONING,
  DEMO-RUNBOOK, IMPLEMENTATION-STATUS); SKU pickers cross-ref the
  PROVIDER_NODE_SIZES per-provider catalog (#176).
- StepComponents UX rewritten: single flat marketplace card grid with
  family chips + product/family routes, two tabs (Choose Your Stack +
  Always Included) — replaces the prior "two-tab Mandatory infra/Apps"
  + "grouped by product header" prose (PRODUCT-FAMILIES, RUNBOOK-
  PROVISIONING, DEMO-RUNBOOK, COMPONENT-LOGOS).
- CORTEX familyDependencies = [] reflected in PRODUCT-FAMILIES; the
  Specter / BGE cascade narratives rewritten to component-level-only
  resolution (langfuse → cnpg, librechat → ferretdb → cnpg) — fixes
  the "selecting Spector pulls entire FABRIC" over-broad claim.
- catalyst-api OpenTofu workdir realigned from /var/lib/catalyst/...
  to /tmp/catalyst/tofu/<fqdn>/ via CATALYST_TOFU_WORKDIR env var
  (commit 27527e4c) — fixes runtime drift in RUNBOOK-PROVISIONING,
  SOVEREIGN-PROVISIONING, DEMO-RUNBOOK; DEMO-RUNBOOK kubectl exec
  ns corrected from catalyst-system to catalyst.
- Logo asset story rewritten: 58 logos (44 SVG + 14 PNG) sourced from
  CNCF artwork + project repos at #169b1d1c/#30ff318d, replacing the
  prior 62 stylised in-house marks; CI smoke-test (#6a7d2dd8)
  cross-referenced.
- 12 G2 bootstrap-kit charts (original 11 + bp-powerdns #167) aligned
  in PROVISIONING-PLAN Group F + blueprint-release.yaml comment +
  SOVEREIGN-PROVISIONING header; previously stale at 11.
- README repo-structure note updated: 12-component bootstrap kit +
  axon + external-dns leaf chart are built; 45 platform / 4 product
  folders remain README-only (was: "every folder except axon").
- ORCHESTRATOR-STATE main-tip SHA advanced from dd578d1c6afdb303
  with one-line summary of the post-Pass-1 batch.
- VALIDATION-LOG: Reconcile Pass 2 entry appended (drift fixed across
  10 files; six-category rubric).

Reconcile Pass 2 against main @ 6afdb303 — 10 files patched plus
VALIDATION-LOG entry. Doc patches are landing first so the in-flight
wizard step-reorder branch will merge into a doc set that already
names the canonical order, avoiding a second drift round.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 11:48:57 +02:00
hatiyildiz
77a3014f74 fix(workflow): blueprint-release supports products/ tree on workflow_dispatch
Adds a `tree` input (default `platform`) so manual triggers can build
umbrella charts under products/ — e.g.
  gh workflow run blueprint-release.yaml -f blueprint=catalyst -f tree=products
will dispatch a build of products/catalyst/chart.

Push-triggered builds already detect both platform/* and products/* via
the diff filter; this only fixes the workflow_dispatch path which was
hardcoded to platform/.
2026-04-28 19:43:47 +02:00
hatiyildiz
497643a4bf fix(catalyst): #104 #107 — bp-catalyst-platform umbrella chart with 11 leaf deps
Issue #104: products/catalyst/chart/Chart.yaml had `name: catalyst-platform`
(missing the `bp-` prefix required by BLUEPRINT-AUTHORING.md §3) and no
`dependencies:` block. The Catalyst umbrella must depend on the 11 bootstrap-kit
leaf Blueprints so a single Flux HelmRelease at the umbrella OCI ref pulls in
the full Catalyst-Zero control plane.

Issue #107: bp-catalyst-platform was the missing 11th OCI artifact at
ghcr.io/openova-io. With this fix, blueprint-release.yaml will publish
ghcr.io/openova-io/bp-catalyst-platform:1.0.1 on push.

Changes:
- Rename chart to `bp-catalyst-platform`, bump version 1.0.0 -> 1.0.1
- Add `dependencies:` block listing all 11 leaves
  (cilium, cert-manager, flux, crossplane, sealed-secrets, spire,
   nats-jetstream, openbao, keycloak, gitea, external-dns), each
  pinned to 1.0.0 at oci://ghcr.io/openova-io
- Workflow blueprint-release.yaml: read chart name from Chart.yaml `name:`
  field instead of deriving `bp-<basename>` from the folder. The umbrella
  folder is `catalyst` but the chart name is `bp-catalyst-platform` —
  basename-derivation is wrong for any chart whose name doesn't equal
  `bp-<folder>`. Removes the implicit `bp-` prefix in the push step;
  Chart.yaml carries the full canonical name.
- Workflow: add `helm registry login ghcr.io` step before `helm dependency
  build` so OCI-hosted leaf deps resolve. The pre-existing docker login
  is for cosign/syft only; helm has its own auth store.

Disclosure (per INVIOLABLE-PRINCIPLES.md §8):
- bp-external-dns:1.0.0 is listed as a dependency but is not yet published;
  platform/external-dns/ has README + policies but no chart/ dir (issue #109
  scope). The umbrella build will fail on `helm dependency build` until #109
  authors the chart and publishes bp-external-dns:1.0.0. The dependency is
  declared anyway because the target-state contract per #104 is exactly 11
  leaves — partial declaration would be a quality compromise (principle #2).

Verified leaf chart names (platform/<x>/chart/Chart.yaml, all `bp-<x>`):
  cilium, cert-manager, flux, crossplane, sealed-secrets, spire,
  nats-jetstream, openbao, keycloak, gitea — all match.
Verified published OCI tags (10/11 at ghcr.io/openova-io/bp-<name>:1.0.0).
2026-04-28 19:39:48 +02:00
hatiyildiz
8efc6e091d fix(blueprint-release): syft scans local .tgz instead of pushed OCI ref
The CI run for commit 62d9c7d successfully pushed all 11 bp-<name>:1.0.0 OCI artifacts to ghcr.io and cosign-signed them. The remaining failure was the SBOM-generation step, which fails identically across all 11 charts with:

  - containerd: pull failed: connection error: desc = "transport: Error while dialing: dial unix /run/containerd/containerd.sock: connect: permission denied"

Root cause: syft's default for OCI refs (registry/image:tag) is to pull the image via containerd and scan its filesystem. The GitHub Actions runner blocks containerd socket access, so the pull fails.

Fix: point syft at the local .tgz file the previous step's `helm package` already wrote to /tmp/charts/. The tarball contains values.yaml + Chart.yaml + templates + blueprint.yaml + Catalyst metadata — the same content that's in the pushed OCI artifact, just from disk instead of registry. file:// scheme avoids containerd entirely.

After this commit, blueprint-release CI should green-build all 11 wrappers including SBOM generation + cosign attestation. Each successful run produces:
- ghcr.io/openova-io/bp-<name>:1.0.0 (helm chart OCI artifact, signed)
- + cosign keyless signature (GitHub OIDC issuer)
- + SBOM SPDX-JSON attestation
2026-04-28 12:58:52 +02:00
hatiyildiz
8c0f76640c feat(charts): G2 wrapper Helm charts for 11 bootstrap-kit components + blueprint-release CI
Per docs/PROVISIONING-PLAN.md and tickets [F] chart. Adds Catalyst-curated wrapper Helm charts at platform/<name>/chart/ for every component the bootstrap-kit installer (introduced in commit 07b4bcf) needs. Each chart is the canonical bp-<name> source per BLUEPRINT-AUTHORING.md §1's source-location rule.

11 charts created with Chart.yaml + values.yaml + blueprint.yaml each:

Network + GitOps:
- platform/cilium/chart — wraps cilium 1.16.5; kubeProxyReplacement, WireGuard mTLS, Hubble, Gateway API
- platform/flux/chart — wraps flux 2.4.0
- platform/crossplane/chart — wraps crossplane 1.18.0 + provider-hcloud manifest

Security:
- platform/cert-manager/chart — wraps cert-manager 1.16.2 with CRDs+ServiceMonitor
- platform/sealed-secrets/chart — wraps sealed-secrets 2.16.1 (transient bootstrap-only)
- platform/spire/chart — wraps spiffe/spire 1.10.4 (5-min SVID rotation)

Catalyst control-plane services:
- platform/nats-jetstream/chart — wraps nats 2.10.22 (3-node cluster, JetStream + KV)
- platform/openbao/chart — wraps openbao 2.1.0 (3-node Raft, region-local per SECURITY §5)
- platform/keycloak/chart — wraps keycloak 25.0.6 (Bitnami flavor, edge proxy mode)
- platform/gitea/chart — wraps gitea 10.5.0 (CNPG Postgres backend, no chart-bundled valkey/redis since Catalyst control plane uses JetStream)

New platform/ folders (added per AUDIT-PROCEDURE component-count anchor — was 53, now 55):
- platform/spire/README.md — workload identity Catalyst control plane component
- platform/nats-jetstream/README.md — control-plane event spine
- platform/sealed-secrets/README.md — transient bootstrap-only

Each blueprint.yaml declares:
- catalyst.openova.io/v1alpha1 Blueprint kind (canonical CRD per BLUEPRINT-AUTHORING §3)
- visibility: unlisted (mandatory infra, auto-installed by bootstrap kit, not a marketplace card)
- manifests.chart: ./chart pointer
- depends: [] (foundational components have no Blueprint dependencies; control-plane services depend on each other implicitly via bootstrap order, not via Blueprint depends)

.github/workflows/blueprint-release.yaml:
- New CI workflow per BLUEPRINT-AUTHORING §11 (path-matrix per Blueprint folder)
- Triggers on push to main touching platform/*/chart/** or products/*/chart/**
- detect job: emits matrix of changed Blueprint folders via git diff
- build job (per chart): helm dependency build → helm package → helm push to GHCR → cosign keyless sign (GitHub OIDC) → Syft SBOM attestation
- Output: ghcr.io/openova-io/bp-<name>:<semver> with SLSA-3-style supply-chain provenance

Closes [F] tickets: 11 G2 charts (cilium, cert-manager, flux, crossplane, sealed-secrets, spire, nats-jetstream, openbao, keycloak, gitea, plus the umbrella products/catalyst/chart already exists from Pass 105). blueprint.yaml CRDs added across 11 entries. CI fan-out workflow live.

After this commit lands, the bootstrap-kit installer in commit 07b4bcf has real OCI artifacts to install. The first push to main will trigger 10 build matrix jobs (cilium was created in a separate commit earlier in this session) which produce 10 cosigned bp-<name>:<semver> artifacts on GHCR.

Component-count anchor update follows: 53 → 55 (added spire + nats-jetstream + sealed-secrets — but sealed-secrets was already conceptually counted under "supporting services"). Per AUDIT-PROCEDURE the count needs updating in CLAUDE.md, BUSINESS-STRATEGY, TECHNOLOGY-FORECAST L11. Tracked as separate ticket [K] docs.
2026-04-28 12:51:06 +02:00