Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
152 commits
Select commit Hold shift + click to select a range
3e172c2
docs(architecture): bootstrap v4 architecture docs + CLAUDE.md
jorgemoralespou Apr 29, 2026
e3ea99b
feat(installer): add educates-training-platform Helm chart (pre-phase)
jorgemoralespou Apr 29, 2026
6340430
chore(installer): drop accidental _debug.txt leftover from chart temp…
jorgemoralespou Apr 29, 2026
a91a34f
test(installer): add chart validation scenarios + e2e runner
jorgemoralespou Apr 29, 2026
cd2811e
docs(architecture): session-manager typed-values target + plan update
jorgemoralespou Apr 30, 2026
41fab46
feat(installer): typed session-manager values + JSON schema
jorgemoralespou Apr 30, 2026
2a14a50
test(installer): convert remaining scenarios to typed values
jorgemoralespou Apr 30, 2026
ea3c6ca
docs(architecture): supersede operator-driven values-shape decision
jorgemoralespou Apr 30, 2026
989f39d
fix(installer): decouple runtimeVersion from Chart.appVersion + ship …
jorgemoralespou Apr 30, 2026
57e7e18
refactor(installer): drive runtime image tags from Chart.appVersion; …
jorgemoralespou Apr 30, 2026
2e2e4eb
refactor(installer): drive image refs from imageRegistry across chart…
jorgemoralespou Apr 30, 2026
4faabb0
refactor(installer): promote imageRegistry, clusterIngress, clusterSe…
jorgemoralespou Apr 30, 2026
398952d
refactor(installer): align lookup-service with global clusterIngress;…
jorgemoralespou Apr 30, 2026
ac03558
feat(installer): render ca-trust-store init container in session-mana…
jorgemoralespou Apr 30, 2026
2420c2f
feat(installer): add minimal values.schema.json for remote-access sub…
jorgemoralespou Apr 30, 2026
ea00079
feat(installer): port node-ca-injector to its own subchart
jorgemoralespou Apr 30, 2026
eed0788
feat(installer): add umbrella values.schema.json focused on globals +…
jorgemoralespou May 3, 2026
08d436d
feat(installer): scenario 08 + per-scenario workshop support in runner
jorgemoralespou May 3, 2026
726d906
refactor(installer): move imageRegistry under development; publish-ti…
jorgemoralespou May 5, 2026
dba3d36
docs(architecture): add follow-up-issues.md for runtime cleanup post-v4
jorgemoralespou May 5, 2026
84a8afd
docs(operator): record Phase 0 layout, status policy, and image stance
jorgemoralespou May 6, 2026
e26ca87
feat(operator): bootstrap kubebuilder scaffold for v4 operator
jorgemoralespou May 6, 2026
6dd7001
feat(operator): EducatesClusterConfig spec from r3 + Phase 0 CEL rules
jorgemoralespou May 6, 2026
4411fa9
feat(operator): SecretsManager, LookupService, SessionManager types f…
jorgemoralespou May 6, 2026
a15080c
feat(installer): educates-installer chart skeleton + reconciler log l…
jorgemoralespou May 6, 2026
ed64a49
feat(operator): Phase 0 close-out — envtest, smoke test, CI
jorgemoralespou May 6, 2026
27c9ec5
feat(operator): mode-field exclusivity CEL + Phase 1 status surface
jorgemoralespou May 6, 2026
af3cc90
feat(operator): operator namespace plumbing + Secret cache scoping
jorgemoralespou May 6, 2026
46033d1
feat(operator): RBAC for Inline-mode referenced resources
jorgemoralespou May 6, 2026
c403747
feat(operator): Inline-mode validator + status writer + finalizer
jorgemoralespou May 6, 2026
a82df93
feat(operator): watches on Secrets + IngressClasses + drift envtest spec
jorgemoralespou May 6, 2026
89a44f6
docs(operator): close out Phase 1 — Inline-mode validator complete
jorgemoralespou May 6, 2026
d9f4770
docs(architecture): record Phase 2 cluster-services vendoring decisions
jorgemoralespou May 9, 2026
0df6213
feat(operator): typed cert-manager + Helm SDK v4 wrapper + ClusterIss…
jorgemoralespou May 9, 2026
e71acb0
feat(installer): vendor cert-manager v1.20.2 chart + make vendor-char…
jorgemoralespou May 9, 2026
7159875
docs: record Phase 2 Session 1 progress in plan + CLAUDE.md
jorgemoralespou May 9, 2026
09339e8
feat(operator): wire helm SDK install path for Managed-mode cert-manager
jorgemoralespou May 11, 2026
84c44e4
feat(operator): wildcard certificate end-to-end in Managed mode
jorgemoralespou May 11, 2026
f647d77
feat(operator): finalizer-driven reverse-order teardown for Managed mode
jorgemoralespou May 11, 2026
42750cc
fix(operator): harden Managed-mode reconciliation against real-cluste…
jorgemoralespou May 12, 2026
8777404
docs(architecture): file Phase 3 follow-ups (watch narrowing, CRD pre…
jorgemoralespou May 12, 2026
28b4dad
refactor(operator): remove cert-manager CRD operator-startup prerequi…
jorgemoralespou May 13, 2026
b7ceaee
refactor(operator): narrow watch events with per-kind mapping funcs
jorgemoralespou May 13, 2026
09988b2
feat(operator): defer cert-manager watches; no CRD prerequisite for o…
jorgemoralespou May 13, 2026
46091e9
refactor(operator): orchestrate Managed reconcile as per-phase pipeline
jorgemoralespou May 13, 2026
a03340e
feat(operator): install Contour ingress controller as the second clus…
jorgemoralespou May 13, 2026
f80922e
fix(operator): Contour readiness — workload names, envoyServiceType, …
jorgemoralespou May 14, 2026
361733d
feat(operator): install external-dns as the third cluster service
jorgemoralespou May 14, 2026
55e7f4e
feat(operator): install Kyverno as the fourth cluster service
jorgemoralespou May 14, 2026
572b2f6
feat(operator): ACME-DNS01 issuer support (Route53 IRSA + CloudDNS WI)
jorgemoralespou May 14, 2026
171cb72
fix(chart): stabilise training-portal credentials via Helm lookup
jorgemoralespou May 14, 2026
7a91279
docs(phase-3): mark Phase 3 done and add sample EducatesClusterConfig…
jorgemoralespou May 14, 2026
acf69f0
feat(operator): SecretsManagerReconciler — Phase 4 Session 1
jorgemoralespou May 14, 2026
966da45
feat(operator): LookupServiceReconciler — Phase 4 Session 2
jorgemoralespou May 14, 2026
1dfb7cf
feat(operator): SessionManagerReconciler — Phase 4 Session 3
jorgemoralespou May 14, 2026
01e1692
fix(operator): platform reconcilers create the educates namespace
jorgemoralespou May 14, 2026
fd39ef8
fix(operator): handle stale ResourceVersion on platform finalizer drain
jorgemoralespou May 14, 2026
4e07da4
feat(operator): SessionManager owns node-ca-injector + remote-access
jorgemoralespou May 14, 2026
e3c2081
fix(chart): drop rules:[] from session-manager aggregate ClusterRole
jorgemoralespou May 14, 2026
17a9ac2
fix(helm): surface helm SDK slog output to the operator log
jorgemoralespou May 14, 2026
d2c39a7
docs(samples): add Inline-mode EducatesClusterConfig example
jorgemoralespou May 15, 2026
1f8f248
fix(operator): gate LookupService install on SecretsManager.Ready
jorgemoralespou May 15, 2026
f9a18b2
fix(operator): harden ECC finalizer add/remove against stale cache
jorgemoralespou May 15, 2026
a0da7f9
refactor(crd): rename imageCache → imagePrePuller across CRD, chart, …
jorgemoralespou May 27, 2026
0211fa7
feat(cli): add EducatesLocalConfig v1alpha1 schema + loader (phase 5 …
jorgemoralespou Jun 5, 2026
23311a8
feat(cli): add EducatesConfig escape-hatch kind with CRD-derived sche…
jorgemoralespou Jun 5, 2026
e1da849
feat(cli): add translator (kind → operator chart values + 4 CRs) (pha…
jorgemoralespou Jun 5, 2026
5956a5a
fix(client-programs): pin crd-schema-checker to apimachinery-compatib…
jorgemoralespou Jun 6, 2026
1a01c79
feat(cli): add 'admin platform render' command (phase 5 step 4)
jorgemoralespou Jun 6, 2026
364e01c
fix(cli): correct %s arg in local_secrets_add error wraps
jorgemoralespou Jun 6, 2026
7197f35
feat(cli): friendly --local-config error when v4 config.yaml is missing
jorgemoralespou Jun 6, 2026
0f46968
feat(cli): add v4 deploy walking skeleton (phase 5 step 5)
jorgemoralespou Jun 6, 2026
bfb7006
fix(operator): build with package-level go path instead of single-file
jorgemoralespou Jun 6, 2026
d5ce7d8
feat(operator): allow namespace on CustomCA.caCertificateRef
jorgemoralespou Jun 6, 2026
7893c8e
feat(secrets): make local CA cache a full signing CA (tls.crt+tls.key)
jorgemoralespou Jun 6, 2026
d5d5fb4
feat(cli): align v4 deploy with v3 secrets cache convention (phase 5 …
jorgemoralespou Jun 6, 2026
76702b7
fix(cli): refresh embedded operator chart with caCertificateRef names…
jorgemoralespou Jun 6, 2026
2875ac6
fix(operator): use APIReader for cross-namespace CustomCA Secret reads
jorgemoralespou Jun 6, 2026
70dbde8
feat(cli): force conflicts on helm upgrade + expose operator.image.pu…
jorgemoralespou Jun 6, 2026
0d79afc
fix(cli): apply LookupService + SessionManager together to break Read…
jorgemoralespou Jun 6, 2026
d39721c
fix(cli): apply BundledKyverno invariant to EducatesLocalConfig
jorgemoralespou Jun 6, 2026
cc6cb00
test(cli): regression backstop for EducatesLocalConfig invariants
jorgemoralespou Jun 6, 2026
24b1198
feat(cli): add v4 delete walking skeleton (phase 5 step 6)
jorgemoralespou Jun 6, 2026
2593912
feat(cli): add v4 local config init/get/set commands (phase 5 step 7)
jorgemoralespou Jun 6, 2026
c95dadc
feat(cli): add v4 local cluster create-v4 walking skeleton (phase 5 s…
jorgemoralespou Jun 6, 2026
b53c533
refactor(cli): promote v4 admin platform commands (phase 5 step 9a)
jorgemoralespou Jun 6, 2026
761ace9
refactor(cli): promote local cluster create + focused kind helper (ph…
jorgemoralespou Jun 6, 2026
d13bcb9
refactor(cli): migrate local config view/edit + delete v3 backing typ…
jorgemoralespou Jun 6, 2026
5eb988f
chore: drop v3 install path: vendir, carvel-packages, Makefile, CLAUD…
jorgemoralespou Jun 6, 2026
618233d
feat(cli): first-run v3 → v4 schema migration shim (phase 5 step 10)
jorgemoralespou Jun 6, 2026
00db591
feat(cli): add EducatesInlineConfig scenario kind (phase 5 step 11a)
jorgemoralespou Jun 6, 2026
00489c2
feat(cli): add EducatesGKEConfig scenario kind (phase 5 step 11b)
jorgemoralespou Jun 6, 2026
d92d7ee
feat(cli): add EducatesEKSConfig scenario kind (phase 5 step 11c)
jorgemoralespou Jun 6, 2026
c4b59f1
fix(cli): cluster-lifecycle preflight: existence guard, fixed Cluster…
jorgemoralespou Jun 7, 2026
814e2ae
fix(cli): plumb VolumeMount.ReadOnly through KindBootstrapInput + kin…
jorgemoralespou Jun 7, 2026
e2c22bd
fix(cli): SyncLocalCachedSecretsToCluster error handling + v3 CA cach…
jorgemoralespou Jun 7, 2026
76f93ff
refactor(cli): factor translateAndDeploy + plumb --context through lo…
jorgemoralespou Jun 7, 2026
273f467
fix(operator): cross-namespace Secret watch + Inline CASecretReferenc…
jorgemoralespou Jun 7, 2026
170f30b
refactor(translator): collapse local + escape operator chart builders…
jorgemoralespou Jun 7, 2026
c5c9dac
refactor(config): single-pass YAML parse in loader
jorgemoralespou Jun 7, 2026
549ba23
feat(operator): boot-time discovery of cached Secret namespaces + cac…
jorgemoralespou Jun 7, 2026
1421672
feat(cli): own CRD lifecycle in deploy (no manual kubectl apply needed)
jorgemoralespou Jun 7, 2026
8909ff5
feat(cli): structured progress reporting in deploy + delete
jorgemoralespou Jun 7, 2026
4b4a174
feat(cli): --yes + --purge on admin platform delete
jorgemoralespou Jun 7, 2026
a9109bf
fix(cli): wait CRD Established + invalidate discovery before CR apply
jorgemoralespou Jun 8, 2026
395f8e4
feat(cli): default local cluster create to <data-home>/config.yaml
jorgemoralespou Jun 8, 2026
02fd759
docs(architecture): sync plan, decisions, follow-ups with Phase 4+5 r…
jorgemoralespou Jun 10, 2026
beb2a89
feat(operator): block ECC finalizer drain while platform CRs exist
jorgemoralespou Jun 10, 2026
c8d247c
feat(operator): wire SessionManager themes + imagePrePuller; reject r…
jorgemoralespou Jun 10, 2026
77212cb
fix(cli): emit CRD-shaped themes list from translator
jorgemoralespou Jun 10, 2026
e6d41b4
ci(cli): client-programs workflow with embedded-chart + schema drift …
jorgemoralespou Jun 10, 2026
eb8708b
chore(ci): drop broken v3 carvel installer bundle publish
jorgemoralespou Jun 10, 2026
ababda5
chore: require Go 1.26 across all modules and builder images
jorgemoralespou Jun 10, 2026
ace9ca3
refactor(operator): clear golangci-lint debt to zero findings
jorgemoralespou Jun 10, 2026
a6ea824
feat(chart): resolve operator image from publish-time registry annota…
jorgemoralespou Jun 11, 2026
cb6fe7d
feat(release): stamp versions in CI and publish helm charts to OCI
jorgemoralespou Jun 11, 2026
9a89b10
ci(installer): add chart version/annotation sync lint
jorgemoralespou Jun 11, 2026
43b8c0c
docs(release): rewrite release procedures for the v4 publish pipeline
jorgemoralespou Jun 11, 2026
b3c4733
feat(release): publish digest-pinned image list for air-gapped reloca…
jorgemoralespou Jun 11, 2026
fe796f2
feat(cli): publish config JSON schemas via GitHub Pages
jorgemoralespou Jun 11, 2026
23468fc
docs(install): rewrite installation guides for v4
jorgemoralespou Jun 11, 2026
454eb0c
docs(architecture): expand protocol follow-up into externalLoadBalanc…
jorgemoralespou Jun 11, 2026
aa31bc6
docs(install): add v3 to v4 migration guide
jorgemoralespou Jun 11, 2026
c42c94d
feat(operator): SessionManager ingressOverrides.protocol assertion
jorgemoralespou Jun 11, 2026
4380200
feat(cli): externalTLSTermination on GKE/EKS/Inline config kinds
jorgemoralespou Jun 11, 2026
bbb7213
docs: ingress protocol override — guides, decisions, follow-up status
jorgemoralespou Jun 11, 2026
774b064
feat(crd): trim operational blocks to BundledContour only
jorgemoralespou Jun 11, 2026
455c738
docs(samples): add full-field operator CR reference samples
jorgemoralespou Jun 11, 2026
615d90a
test(cli): add full-config testdata for the GKE/EKS/Inline kinds
jorgemoralespou Jun 11, 2026
eb23540
test(chart): add 09-kind-all-options kitchen-sink scenario
jorgemoralespou Jun 11, 2026
ec2a61d
docs(install): add installation architecture guide
jorgemoralespou Jun 11, 2026
9088f43
Merge branch 'develop' into feature/4.0/helm-installer
jorgemoralespou Jun 12, 2026
72076f1
chore(build): drop educates-client-programs imgpkg bundle
jorgemoralespou Jun 12, 2026
30cae54
docs: update configuration examples to the v4 format
jorgemoralespou Jun 12, 2026
830fc74
docs(release-notes): cover the v4 installer work in 4.0.0
jorgemoralespou Jun 12, 2026
36ff663
docs(claude): add release-notes completeness rule to working norms
jorgemoralespou Jun 12, 2026
75fca55
feat(cli): PEM export + trust-store guidance for the local CA
jorgemoralespou Jun 12, 2026
f5cdc26
feat(operator): bump contour to 0.6.0 and kyverno to 3.8.1
jorgemoralespou Jun 12, 2026
c370541
feat(operator): route session-manager, pause and node-ca-injector ima…
jorgemoralespou Jun 12, 2026
036c06e
feat(cli): dev-built CLI defaults all core images to its compiled-in …
jorgemoralespou Jun 12, 2026
e7e914e
feat(cli): route component imageVersions entries to their own CRs
jorgemoralespou Jun 12, 2026
08bacc6
feat(build): one-command local build via 'make'
jorgemoralespou Jun 12, 2026
52e3519
docs: document the one-command local build flow
jorgemoralespou Jun 12, 2026
fa2e4f2
fix(cli): buffer the hugo cleanup signal channel
jorgemoralespou Jun 12, 2026
743fcfa
Merge remote-tracking branch 'origin/develop' into feature/4.0/helm-i…
jorgemoralespou Jun 13, 2026
07e515e
feat(kyverno): migrate bundled policies to ValidatingPolicy; deprecat…
jorgemoralespou Jun 13, 2026
e38c2c2
fix(operator): bind Envoy host ports for kind (ClusterIP topology)
jorgemoralespou Jun 13, 2026
b88edcc
Merge remote-tracking branch 'origin/develop' into feature/4.0/helm-i…
jorgemoralespou Jun 14, 2026
76c1c8f
docs(skills): add educates-upgrade-theme-libraries skill
jorgemoralespou Jun 14, 2026
24e93e3
fix(build): cross-compile Go builds for multiarch (operator, base-env…
jorgemoralespou Jun 14, 2026
0fca60b
docs(skills): add cluster-services upgrade skill; refresh go + releas…
jorgemoralespou Jun 14, 2026
2fd33cc
ci: drive gating workflows through the Makefile; fix latent failures
jorgemoralespou Jun 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
151 changes: 151 additions & 0 deletions .claude/skills/educates-release-notes/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
---
name: educates-release-notes
description: Create release notes for an Educates version. Invoke when asked to "create release notes", "prepare for a release", "generate release notes", or "document changes for version X.Y.Z". Creates a versioned markdown file in project-docs/release-notes/ and updates project-docs/index.rst.
argument-hint: "<version> (e.g. 4.1.0)"
allowed-tools: "Read, Glob, Bash"
---

# Educates Release Notes Creation

Create release notes for version `$ARGUMENTS` of the educates-training-platform.

If no version is specified in `$ARGUMENTS`, check `project-docs/release-notes/` for the latest `version-*.md` file and increment the patch version.

## Step 1: Determine the Version

Use the version from `$ARGUMENTS` (e.g. `4.1.0`). If not provided:

```bash
ls project-docs/release-notes/version-*.md | sort -V | tail -1
```

Increment the patch version (or minor/major as appropriate).

## Step 2: Find the Previous Release

```bash
ls project-docs/release-notes/version-*.md | sort -V
```

Identify the version immediately before the target version. Then find its git tag or the commit where it was merged. Educates release tags are plain `X.Y.Z` (and `X.Y.Z-alpha.N`/`-beta.N`/`-rc.N` pre-releases) with **no `v` prefix**:

```bash
git tag --sort=-version:refname | grep -E '^[0-9]' | head
git log --oneline --grep="version-<previous>" -- project-docs/release-notes/
```

## Step 3: Analyze Git Changes

Get all commits since the previous release:

```bash
git log --oneline <previous-tag-or-commit>..HEAD
```

Get changed files:

```bash
git diff --name-only <previous-tag-or-commit>..HEAD
git diff --stat <previous-tag-or-commit>..HEAD
```

Get commit messages formatted for analysis:

```bash
git log --pretty=format:"%s" <previous-tag-or-commit>..HEAD
```

Check for merge commits (feature branches):

```bash
git log --merges <previous-tag-or-commit>..HEAD
```

## Step 4: Categorize Changes

Map changes to sections by scanning commits and file diffs:

| Category | What to look for |
|---|---|
| **New Features** | New files, new commands, new config options; commit keywords: "add", "new", "feature", "support for" |
| **Features Changed** | Modified existing files, version bumps, config changes; keywords: "update", "change", "modify", "improve", "refactor" |
| **Bugs Fixed** | Error handling, corrections; keywords: "fix", "bug", "error", "issue", "correct" |
| **Deprecations** | Things still supported but on the way out; keywords: "deprecate", "deprecated". Note the removal timeline (and any upstream timeline it tracks). |
| **Known Issues** | Manual entry — from issue tracker or known limitations |

A user-facing change is only "done" when it has a release-notes entry — this is a
project norm (see `CLAUDE.md`), so the running `version-*.md` may already carry
many entries. Treat your job as filling gaps and tidying, not writing from scratch.

Common patterns:
- `go.mod`/`go.sum` changes → dependency updates (Features Changed)
- `Dockerfile` changes → base image or tool version updates (Features Changed)
- New files in `project-docs/` → documentation (New Features or Features Changed)
- kubectl version blocks in `workshop-images/base-environment/Dockerfile` → Kubernetes version support change

## Step 5: Create the Release Notes File

Create `project-docs/release-notes/version-{x.y.z}.md` using this exact format:

```markdown
Version {x.y.z}
=============

New Features
------------

* Description of new feature.

Features Changed
----------------

* Description of changed feature.

Bugs Fixed
----------

* Description of bug fix.

Deprecations
------------

* Description of a feature that still works but is slated for removal, with the
removal timeline (if any).

Known Issues
------------

* Description of known issue (if any).
```

Formatting rules:
- Main heading uses `=` underline (same length as the heading text)
- Section headings use `-` underline
- Bullet points use `*`
- Omit sections that have no entries
- Write in third person, concise, specific
- Include version numbers for dependency updates
- Clearly flag breaking changes

## Step 6: Update `project-docs/index.rst`

Read `project-docs/index.rst` and find the `Release Notes:` toctree section (around line 80–82). Add the new entry at the **top** of the list (newest first):

```rst
.. toctree::
:maxdepth: 2
:caption: Release Notes:

release-notes/version-{x.y.z}
release-notes/version-{previous}
...
```

Maintain 2-space indentation and keep entries sorted newest first.

## Step 7: Review

- Verify version number is correct and consistent in filename and heading
- Confirm all major changes from git log are covered
- Check formatting matches existing release notes files (read one for comparison)
- Verify the `index.rst` entry was added correctly and the file renders as valid RST
211 changes: 211 additions & 0 deletions .claude/skills/educates-upgrade-cluster-services/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
---
name: educates-upgrade-cluster-services
description: Upgrade a vendored upstream cluster-service Helm chart the Educates operator installs for EducatesClusterConfig — cert-manager, Contour, Kyverno, or external-dns. Invoke when asked to "upgrade cert-manager / contour / kyverno / external-dns", "bump a vendored cluster-service chart", or "update the operator's bundled charts".
argument-hint: "[cert-manager|contour|kyverno|external-dns] (omit to check all four)"
allowed-tools: "Read, Edit, Bash, WebFetch, Glob"
---

# Educates Cluster-Service Chart Upgrade Protocol

The operator installs four upstream cluster services for `EducatesClusterConfig`
(Managed mode) from Helm chart tarballs vendored at
`installer/operator/vendored-charts/`: **cert-manager**, **Contour**,
**Kyverno**, **external-dns**. The bytes are checked into the repo and embedded
into the operator binary via `//go:embed`. This skill bumps one (or checks all)
to a new upstream version.

`installer/operator/vendored-charts/README.md` is the canonical reference for
this workflow — keep it and this skill in agreement.

If `$ARGUMENTS` names a service, upgrade only that one. With no argument, check
all four for newer upstream versions and report before changing anything.

> The same directory also holds the in-repo runtime subcharts (secrets-manager,
> lookup-service, session-manager, node-ca-injector, remote-access). Those are
> **not** in scope here — they are repackaged from source via
> `make package-local-charts`, not downloaded.

## Where each piece of version state lives

A version is pinned in **four** places that must stay in lockstep (a
consistency test enforces it — see Verification):

1. `installer/operator/Makefile` → `VENDORED_CHARTS` list: `name=version=url`.
2. `installer/operator/vendored-charts/SHA256SUMS`: `<sha256> <name>-<version>.tgz`.
3. `installer/operator/vendored-charts/embed.go`: the `//go:embed <name>-<version>.tgz`
directive, the `<X>ChartVersion` constant, and (Contour / external-dns /
Kyverno) the `<X>AppVersion` constant. cert-manager has a single
`CertManagerVersion` (its chart version equals its appVersion).
4. The tarball file itself on disk.

## Upstream sources and version semantics

| Service | Upstream releases | Chart URL pattern | App version |
|---|---|---|---|
| cert-manager | `https://github.com/cert-manager/cert-manager/releases` | `https://charts.jetstack.io/charts/cert-manager-v<VER>.tgz` | == chart version (`v<VER>`) |
| contour | `https://github.com/projectcontour/helm-charts/releases` | `https://github.com/projectcontour/helm-charts/releases/download/contour-<VER>/contour-<VER>.tgz` | Contour binary version (e.g. `1.33.5`) |
| external-dns | `https://github.com/kubernetes-sigs/external-dns/releases` | `https://github.com/kubernetes-sigs/external-dns/releases/download/external-dns-helm-chart-<VER>/external-dns-<VER>.tgz` | external-dns binary version |
| kyverno | `https://github.com/kyverno/kyverno/releases` | `https://kyverno.github.io/kyverno/kyverno-<VER>.tgz` | Kyverno binary version (e.g. `v1.18.1`) |

Use WebFetch on the releases page to find the latest stable chart version (not a
pre-release). The chart version and the bundled app version differ for Contour,
external-dns, and Kyverno — read the new app version from the tarball's
`Chart.yaml` (`appVersion:`) after downloading.

**Kyverno is the awkward one: its chart version and binary version are on
different numbering tracks and live in different places.** The
`github.com/kyverno/kyverno/releases` page lists the **binary** version
(`appVersion`, e.g. `v1.18.1`); the **chart** version (`<VER>` in the URL above,
e.g. `3.8.1`) only exists in the Helm repo's `index.yaml`. They are *not*
aligned and you cannot derive one from the other by inspection — you must resolve
the chart version that ships a given Kyverno binary from the repo index:

```bash
# What chart version ships Kyverno binary v1.18.1? (stable, non-rc rows only)
curl -sSfL https://kyverno.github.io/kyverno/index.yaml \
| yq -r '.entries.kyverno[]
| select(.appVersion | test("rc")|not)
| .version + " => " + .appVersion' \
| grep ' v1.18.1$' # → 3.8.1 => v1.18.1
```

To browse the newest stable charts and the binary each one bundles (the first
row is the latest stable chart), drop the `grep`:

```bash
curl -sSfL https://kyverno.github.io/kyverno/index.yaml \
| yq -r '.entries.kyverno[]
| select(.appVersion | test("rc")|not)
| .version + " => " + .appVersion' \
| head
```

Equivalently with the Helm CLI (`helm repo add kyverno
https://kyverno.github.io/kyverno/ && helm repo update kyverno && helm search
repo kyverno/kyverno --versions`), whose `CHART VERSION` / `APP VERSION` columns
are the same two fields. Either way, that chart version is what goes in
`<VER>` for the download URL, the Makefile, `SHA256SUMS`, and the `embed.go`
filename + `KyvernoChartVersion`; the matching `appVersion` is
`KyvernoAppVersion` (still confirm it from the downloaded tarball's `Chart.yaml`
per step 5).

Current versions: read them from the Makefile `VENDORED_CHARTS` line and the
`embed.go` constants.

## Update process (per chart)

Worked example: contour `0.6.0` → `<VER>`. Other charts are identical except
cert-manager has no separate `AppVersion` constant.

1. **Compute the new tarball's SHA256** from the upstream URL (the "I am
deliberately trusting these bytes" step — `make vendor-charts` refuses to
download anything whose hash isn't already recorded):
```bash
curl -sSfL "https://github.com/projectcontour/helm-charts/releases/download/contour-<VER>/contour-<VER>.tgz" | shasum -a 256
```

2. **`installer/operator/Makefile`** — update the chart's `VENDORED_CHARTS`
entry (version and URL).

3. **`SHA256SUMS`** — replace the chart's line with the new filename + hash.

4. **`make -C installer/operator vendor-charts`** — downloads, verifies against
SHA256SUMS, and writes the new tarball into place. Then `git rm` the old
tarball (nothing prunes it automatically).

5. **`embed.go`** — update the `//go:embed` filename, the `<X>ChartVersion`
constant, and the `<X>AppVersion` constant. Read the new appVersion from the
tarball:
```bash
tar -xzOf installer/operator/vendored-charts/contour-<VER>.tgz contour/Chart.yaml | grep -E '^(version|appVersion):'
```

6. **Re-verify reconciler assumptions** (the load-bearing step — see next
section). The per-service reconciler gates readiness on specific workload
names / webhook behaviour verified against a chart version.

7. **`installer/operator/vendored-charts/README.md`** — update the "Current
contents" version table.

8. **Kyverno only — also re-vendor the bundled policies.** See "Kyverno
special case" below.

## Re-verify reconciler assumptions

Each cluster service has a reconciler in `installer/operator/internal/controller/config/`
that gates readiness on workload names and, sometimes, CRD/webhook behaviour.
A chart bump can rename a Deployment, change a values key, or move a CRD API
version and silently break the gate. Render the new chart and confirm:

```bash
# extract + template the new chart with the operator's values shape
helm template <name> <path-to-extracted-chart> [--set ...] | grep -E 'kind: (Deployment|DaemonSet)' -A2
```

| Service | Reconciler | What it asserts (verify still true) |
|---|---|---|
| cert-manager | `certmanager.go` | `cert-manager`, `cert-manager-cainjector`, `cert-manager-webhook` Deployments ready; `cert-manager.io` API discovery responds; CRDs present (deferred watch) |
| contour | `contour.go` | `contour-contour` Deployment + `contour-envoy` DaemonSet (names from the chart fullname helper); no admission webhook; `envoy.useHostPort` / `envoy.service.type` values still honoured |
| external-dns | `externaldns.go` | the external-dns Deployment is ready; provider value keys (Route53 / CloudDNS) unchanged |
| kyverno | `kyverno.go` | the four controller Deployments (`kyverno-{admission,background,cleanup,reports}-controller`) ready; `validatingpolicies.policies.kyverno.io` CRD still installed; RBAC role names unchanged |

If a name or values key changed, update the reconciler constant and its
"verified against <version>" comment in the same change.

## Kyverno special case

Bumping the Kyverno **chart** usually means bumping the Kyverno **binary**
(`KyvernoAppVersion`), and the bundled Kyverno security policies are pinned to a
matching `kyverno/policies` release branch. When `KyvernoAppVersion` changes
(e.g. `v1.18.x` → `v1.19.x`):

1. Re-vendor the policies from the matching `release-1.NN` branch — follow
`installer/charts/educates-training-platform/charts/session-manager/files/kyverno-policies/README.md`.
2. Repackage the session-manager subchart so the operator ships the refreshed
policies:
```bash
make -C installer/operator package-local-charts
```
(then restore any subchart tarball that only changed by gzip timestamp).
3. Re-check that `kyverno.go`'s RBAC / CRD assumptions and the session-manager
`validatingpolicies` ClusterRole still match the new Kyverno.

## Verification

```bash
make -C installer/operator verify-vendored-charts # SHA256 of every on-disk tarball
make -C installer/operator test # runs the consistency + load tests
```

`make test` includes:
- `TestVendoredCharts_DirectoryConsistent` — ties the Makefile `VENDORED_CHARTS`
list, `SHA256SUMS`, `embed.go` constants, and the on-disk tarballs together; a
half-finished bump (or a leftover old tarball) fails here.
- `Test<Service>_Embedded` — asserts each embedded chart's name/version/appVersion
match the `embed.go` constants.

The operator image `//go:embed`s these tarballs, so to test on a cluster rebuild
the operator (`make image-operator`) and redeploy. For a real upgrade, also
deploy `EducatesClusterConfig` in Managed mode and confirm the service reaches
Ready and its reconciler condition flips (`CertificatesReady`, `IngressReady`,
`DNSReady`, `PolicyEnforcementReady`).

## Notes

- Never edit a vendored tarball or unpack-and-repack it — ship the upstream
chart unmodified. Configuration is applied through the operator's Helm values
(the per-service `render<Service>Values` in the reconcilers), not by patching
the bytes.
- Major-version bumps: read the upstream chart's changelog for renamed values,
workload names, or CRD API-version moves, and flag breaking changes.

## Post-upgrade checklist

- [ ] `VENDORED_CHARTS` (Makefile), `SHA256SUMS`, and `embed.go` all updated to the new version
- [ ] New tarball downloaded via `make vendor-charts` (hash-verified); old tarball `git rm`'d
- [ ] `embed.go` `<X>AppVersion` read from the new tarball's `Chart.yaml`
- [ ] Reconciler workload-name / values / CRD assumptions re-verified; constants + comments updated if changed
- [ ] Kyverno: bundled policies re-vendored + session-manager subchart repackaged (if appVersion changed)
- [ ] README "Current contents" table updated
- [ ] `make verify-vendored-charts` and `make test` pass
- [ ] Major-version bumps: changelog reviewed for breaking changes and flagged
Loading