Skip to content

feat(#436): real Windows installer e2e on a self-hosted nested-virt runner (RFC D5) - #540

Merged
shujaatTracebloc merged 5 commits into
developfrom
fix/436-windows-e2e
Aug 3, 2026
Merged

feat(#436): real Windows installer e2e on a self-hosted nested-virt runner (RFC D5)#540
shujaatTracebloc merged 5 commits into
developfrom
fix/436-windows-e2e

Conversation

@shujaatTracebloc

@shujaatTraceblocshujaatTracebloc commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

#436 — real Windows installer e2e (self-hosted runner, RFC-CLIENT-0003 D5)

GitHub's windows-latest runners can't nest virtualization, so install-k8s.ps1 has 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.

Provisioning decision: self-hosted Windows runner (Azure isn't available to us).

What's here

  • .github/workflows/windows-e2e.yamlschedule (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, mirroring e2e-journey.sh: dot-sources install-k8s.ps1 with TB_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 real New-K3dCluster → applies a credential-free stub the CLI discovery keys off (labels + ingestor SA) → asserts the discovery-shaped state → checks the installer's cluster-create copy reached the log → tears down. 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, account rights) + what green/red means.
  • installer-tests.yamle2e-windows.ps1 added to the PSScriptAnalyzer step so a syntax/verb regression fails fast on every push, not at the nightly run.

Acceptance criteria

  • ✅ A deliberately broken installer commit turns the job red with the install log attached (windows-e2e-install-log artifact).
  • ✅ Covers whichever Windows path is current (the PS monolith today; if D2 lands a WSL adapter, point the driver at the new entrypoint — runner setup unchanged).

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 — see docs/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_dispatch workflow (.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 (bounded k3d delete + data-dir cleanup).

scripts/tests/e2e-windows.ps1 dot-sources install-k8s.ps1 with TB_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 like e2e-journey.sh.

docs/WINDOWS-E2E.md documents one-time runner setup (labels, WSL2/Docker, Administrator). installer-tests.yaml now PSScriptAnalyzes e2e-windows.ps1 on 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.

…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
@shujaatTraceblocshujaatTracebloc self-assigned this Aug 3, 2026
@shujaatTracebloc
shujaatTracebloc marked this pull request as ready for review August 3, 2026 07:51
Comment threadscripts/tests/e2e-windows.ps1
Comment threadscripts/tests/e2e-windows.ps1
Comment threadscripts/tests/e2e-windows.ps1
… 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>
Comment threadscripts/tests/e2e-windows.ps1
Comment threadscripts/tests/e2e-windows.ps1
…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>
Comment threadscripts/tests/e2e-windows.ps1
Comment thread.github/workflows/windows-e2e.yaml
Comment thread.github/workflows/windows-e2e.yaml Outdated
…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>

@cursorcursorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ 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.

Comment thread.github/workflows/windows-e2e.yaml
…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>
@shujaatTracebloc
shujaatTracebloc merged commit b0970b0 into developAug 3, 2026
37 checks passed
@shujaatTracebloc
shujaatTracebloc deleted the fix/436-windows-e2e branch August 3, 2026 08:32
@LukasWodka

Copy link
Copy Markdown
Contributor

/fr-pass

Sign up for freeto 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.

3 participants

@shujaatTracebloc@LukasWodka@saadqbal