Uh oh!
There was an error while loading. Please reload this page.
feat(#436): real Windows installer e2e on a self-hosted nested-virt runner (RFC D5) - #540
Conversation
…unner (RFC D5) GitHub's windows-latest runners can't nest virtualization, so install-k8s.ps1 had only mocked Pester while the bash installer gets a 9-distro prereq matrix + real-k3d e2e on every push. This adds the missing Windows e2e leg (RFC-CLIENT-0003 D5), on a self-hosted runner that DOES support nested virt. - .github/workflows/windows-e2e.yaml: schedule-only (nightly) + workflow_dispatch, NOT per-PR; runs-on [self-hosted, windows, nested-virt]; concurrency-guarded; 45-min cap; uploads the install log as an artifact on failure; tears the cluster down every run. - scripts/tests/e2e-windows.ps1: the credential-free driver, mirroring e2e-journey.sh — dot-sources install-k8s.ps1 with TB_PESTER=1 (main() does not run), verifies Docker/WSL are up (runner prereqs; it does NOT reinstall Docker Desktop per run), installs the tools, runs the installer's real New-K3dCluster, applies a credential-free stub the CLI discovery keys off (labels + the ingestor SA), asserts the discovery-shaped state, and checks the installer's cluster-create copy landed in the log. Stops before Invoke-ProvisionClient (Steps 5-6 mint a real backend credential — out of scope), exactly as e2e-journey stops before the CLI connects. - docs/WINDOWS-E2E.md: one-time runner setup (labels, WSL2 + Docker Desktop + nested virt, runner account rights) + what green/red means. - installer-tests.yaml: lint e2e-windows.ps1 with PSScriptAnalyzer on every push so a syntax/verb regression fails fast, not at the nightly run. Chose the self-hosted-runner route (Azure isn't available to us). Validated here: YAML parses, PSScriptAnalyzer clean (0 errors; the Write-Host/empty-catch/unicode warnings match install-k8s.ps1's own tolerated set), check-style clean. It CANNOT be validated off a nested-virt Windows host — the first scheduled run on the registered runner shakes it out, which is exactly the issue's acceptance (a broken installer commit turns it red with the install log attached). Closes#436
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
… the e2e driver (Bugbot) Three Bugbot findings on the Windows e2e driver: 1. (High) TB_PESTER=1 skips the installer's self-elevation gate, but Initialize-ToolDir creates %ProgramFiles%\tracebloc\bin and writes the Machine PATH — admin-only. The docs wrongly said a non-admin account suffices. Assert Administrator up front (fail fast with a pointer) and correct docs/WINDOWS-E2E.md: the runner MUST run elevated (the Windows installer is inherently admin). 2. (Medium) The install-log copy assertion was SKIPPED when LOG_FILE was missing, yet the script still printed PASS — a vacuous seal. Now a missing log fails (never report PASS on an unverified check). 3. (Medium) Several kubectl calls (wait/create/apply/get) had no --request-timeout, so a wedged API server would hang to the 45-min job cap. Added --request-timeout=30s to each (the PowerShell analog of the bash journey's watchdog). PSScriptAnalyzer: 0 errors (the remaining warnings match install-k8s.ps1's tolerated set); YAML valid; check-style clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
…y selector (Bugbot r2) Two more Bugbot findings on the e2e driver: 1. (High) `docker info` and the finally `k3d cluster delete` had no deadline, so a wedged Docker/WSL or a stuck delete would hang the shared runner to the 45-min job cap — undercutting the --request-timeout hardening already on every kubectl call. Added an Invoke-Bounded helper (Start-Process + the installer's killing Wait-ProcessWithDeadline) and ran both through it (30s / 120s). 2. (Medium) The discovery assertion only filtered app.kubernetes.io/name=client, so a stub missing managed-by=Helm or a non -jobs-manager name still reached PASS. Now it matches the FULL selector DiscoverParentRelease uses: name=client AND managed-by=Helm, AND the Deployment name ends in -jobs-manager. PSScriptAnalyzer 0 errors; warnings unchanged (match install-k8s.ps1's tolerated set). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
…ded safety-net (Bugbot r3) Three findings from the persistent-runner reality: 1. (High) A leftover tbe2ewin cluster sends New-K3dCluster down its reuse path (which still logs 'Creating k3d cluster'), so the copy check + PASS could succeed WITHOUT a real create. Pre-clean any stale cluster (bounded) before New-K3dCluster so every run genuinely creates one. 2. (High) The install-log upload was gated on failure() only, but a timeout-minutes hit CANCELS the job (failure() is false), and the always() teardown then wiped the log the acceptance criteria need. Upload on !success() (failed OR cancelled/timed out), before the teardown. 3. (Medium) The workflow safety-net k3d delete was unbounded. Bound it with Start-Process + Wait-Process -Timeout 120 (+ force-kill), matching the driver's Invoke-Bounded. YAML valid; PSScriptAnalyzer 0 errors; check-style clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit ff139c4. Configure here.
Uh oh!
There was an error while loading. Please reload this page.
…d resolves (Bugbot r4) (High) The always-on safety-net teardown runs bare `k3d` in a fresh step process, but Initialize-ToolDir writes the MACHINE PATH — which a subsequent step doesn't pick up mid-job — so k3d could be unresolved there and, when the driver was killed before its finally, the tbe2ewin cluster would leak on the shared runner. Prepend %ProgramFiles%\tracebloc\bin to GITHUB_PATH in the setup step so every later step resolves k3d (the driver's own calls already resolve via RefreshPath in-process). YAML valid. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
LukasWodka
commented
Aug 3, 2026
/fr-pass |

#436 — real Windows installer e2e (self-hosted runner, RFC-CLIENT-0003 D5)
GitHub's
windows-latestrunners can't nest virtualization, soinstall-k8s.ps1has only mocked Pester coverage — while the bash installer gets a 9-distro prereq matrix + real-k3d e2e on every push. Regressions and never-ported behaviors stay green on Windows. This adds the missing e2e leg on a self-hosted runner that supports nested virt.What's here
.github/workflows/windows-e2e.yaml—schedule(nightly) +workflow_dispatch, not per-PR;runs-on: [self-hosted, windows, nested-virt]; concurrency-guarded; 45-min cap; uploads the install log artifact on failure; tears the cluster down every run.scripts/tests/e2e-windows.ps1— the credential-free driver, mirroringe2e-journey.sh: dot-sourcesinstall-k8s.ps1withTB_PESTER=1(main() doesn't run) → verifies Docker/WSL up (runner prereqs; it does not reinstall Docker Desktop per run) → installs tools → runs the installer's realNew-K3dCluster→ applies a credential-free stub the CLI discovery keys off (labels +ingestorSA) → asserts the discovery-shaped state → checks the installer's cluster-create copy reached the log → tears down. Stops beforeInvoke-ProvisionClient(Steps 5–6 mint a real backend credential — out of scope), exactly ase2e-journeystops before the CLI connects.docs/WINDOWS-E2E.md— one-time runner setup (labels, WSL2 + Docker Desktop + nested virt, account rights) + what green/red means.installer-tests.yaml—e2e-windows.ps1added to the PSScriptAnalyzer step so a syntax/verb regression fails fast on every push, not at the nightly run.Acceptance criteria
windows-e2e-install-logartifact).Validation — please read
This is greenfield CI infra I cannot execute here (no Windows / WSL / nested-virt host). Validated locally: YAML parses; PSScriptAnalyzer clean (0 errors — the Write-Host / empty-catch / non-BOM-unicode warnings match
install-k8s.ps1's own tolerated set); check-style clean. The first scheduled run on the registered runner is what shakes it out — that's inherent to this issue, and it's the acceptance test.Before it can run (one-time, needs you/IT)
Register a self-hosted Windows runner with labels
self-hosted, windows, nested-virt, WSL2 + Docker Desktop (WSL2 backend) running, on a nested-virt-capable host — seedocs/WINDOWS-E2E.md.Closes#436
Note
Low Risk
CI and test infrastructure only; no production installer behavior changes, though the job mutates Machine PATH and k3d state on the dedicated self-hosted runner.
Overview
Adds real end-to-end coverage for the Windows PowerShell installer where GitHub-hosted runners cannot nest virtualization—parity with the bash installer’s real-k3d path, scoped to RFC D5 (#436).
A new nightly +
workflow_dispatchworkflow (.github/workflows/windows-e2e.yaml) runs on[self-hosted, windows, nested-virt], with concurrency limits, a 45-minute cap, install-log upload on any non-success (!success()), and an always teardown safety net (boundedk3ddelete + data-dir cleanup).scripts/tests/e2e-windows.ps1dot-sourcesinstall-k8s.ps1withTB_PESTER=1, then runs the credential-free path: admin + Docker checks, tool install, pre-clean +New-K3dCluster, discovery-shaped stub assertions, install-log copy smoke check, and bounded teardown—stopping before backend provisioning likee2e-journey.sh.docs/WINDOWS-E2E.mddocuments one-time runner setup (labels, WSL2/Docker, Administrator).installer-tests.yamlnow PSScriptAnalyzese2e-windows.ps1on every push so regressions fail fast before the nightly job.Reviewed by Cursor Bugbot for commit 37a6716. Bugbot is set up for automated code reviews on this repo. Configure here.