Skip to content

test: tiered e2e suite (kubeadm-in-container) + per-PR CI job (ADR-13) - #15

Merged
wrkode merged 1 commit into
mainfrom
feat/e2e-tests
Jun 8, 2026
Merged

test: tiered e2e suite (kubeadm-in-container) + per-PR CI job (ADR-13)#15
wrkode merged 1 commit into
mainfrom
feat/e2e-tests

Conversation

@wrkode

@wrkode wrkode commented Jun 8, 2026

Copy link
Copy Markdown
Collaborator

What

Add a tiered end-to-end test suite that proves the implemented use cases against real kubeadm/kubelet/containerd on every PR, closing the gap between unit-level config-generation tests and "does a real cluster actually come up" (ADR-13).

Mechanism: a kind-style privileged systemd node container derived FROM the already-built kairos-kubeadm image (reuses the checksum-verified toolchain, no rebuild). The harness drives the real reconcile/reset subcommands against the real serialized-Cluster contract — no parallel code path. Go-native behind //go:build e2e, runnable locally via make e2e.

Tier-1 (per-PR; ci.yml matrix over 1.34 / 1.35 / 1.36)

  • single-node init converges: apiserver healthy, node registered, status.yaml phase=Converged, all provider-kubernetes.kairos.io/* annotations present
  • reset cleans kubeadm artifacts
  • init-clobber refusal (#4099-5) and upgrade-skew refusal fire (terminal, no clobber)
  • CA-pinned 2-container worker join (never UnsafeSkipCAVerification)

Heavyweight scenarios (full Kairos VM boot, HA failover, A/B upgrade) remain manual libvirt smokes — GitHub-hosted runners can't host them. That boundary is intentional and documented (E5 follow-up).

Supporting changes (reviewed)

  • internal/reconcile/budget.goDefaultBudget 2m/3/8m -> 6m/2/8m. A cold kubeadm init pulls control-plane images and waits for health (~3-5m), which 2m PerAttempt couldn't accommodate; Total stays 8m so the unreachable-endpoint case still surfaces fast. (ADR-14; per-action budgets are a tracked follow-up.)
  • main.go — a bounded reset subcommand (operator escape hatch + e2e entry) running the same validated reset.Run path as EventClusterReset.

Security (ADR-13 E3)

The privileged e2e job is pinned to read-only permissions and constrained to GitHub-hosted ephemeral runners, no secrets, pull_request trigger — the controls that contain a hostile PR. (Reviewed: image provenance from our own checksum-verified base, CA-pinned join, argv-only exec, bounded teardown all PASS.)

Validation

Unit gates + e2e compile/lint green; the single-node init scenario was run green locally. The full suite's authoritative venue is this job on GitHub-hosted CI (the local lab host is resource-contended) — so this PR's own e2e run is the proof.

Reviews: staff-engineer (E1/E2), security-architect (budget + privileged-CI), staff-architect (budget ADR-14).

🤖 Generated with Claude Code

…R-13)

Prove the implemented use cases against real kubeadm/kubelet/containerd on
every PR, not just unit-level config generation. Per ADR-13, e2e runs in a
kind-style privileged systemd node container derived FROM the already-built
kairos-kubeadm image, driving the REAL reconcile/reset subcommands against the
real serialized-Cluster contract (no parallel code path).

Tier-1 (per-PR; ci.yml matrix over 1.34/1.35/1.36):
- single-node init converges (API healthy, node registered, status.yaml
  phase=Converged + provider-kubernetes.kairos.io/* annotations)
- reset cleans kubeadm artifacts
- init-clobber refusal (#4099-5) and upgrade-skew refusal fire
- CA-pinned 2-container worker join (never UnsafeSkipCAVerification)

Harness is Go-native behind //go:build e2e, runnable locally via make e2e.

Supporting changes (reviewed):
- internal/reconcile/budget.go: DefaultBudget 2m/3/8m -> 6m/2/8m. A cold
  kubeadm init pulls control-plane images and waits for health (~3-5m), which
  2m PerAttempt could not accommodate; Total stays 8m so the unreachable-
  endpoint case still surfaces fast (ADR-14; per-action budgets are follow-up).
- main.go: add a bounded reset subcommand (operator escape hatch + e2e entry)
  running the same validated reset.Run path as EventClusterReset.

Security (ADR-13 E3): the privileged e2e job is pinned to read-only
permissions and constrained to GitHub-hosted ephemeral runners, no secrets,
pull_request trigger -- the controls that contain a hostile PR.

Validation: unit gates + e2e compile/lint green; single-node init scenario run
green locally. The full suite's authoritative venue is this job on
GitHub-hosted CI (the local lab host is resource-contended).

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: William Rizzo <william.rizzo@gmail.com>
@wrkode
wrkode merged commit bf43565 into main Jun 8, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant