fix(#557): preflight port 6550 on Windows so a conflict fails clearly - #622
Merged
Conversation
divyasinghds
added a commit
that referenced
this pull request
Aug 6, 2026
…gated) Address PR #622 review on the Windows port-6550 preflight: - Get-PfPortListening no longer fails open: -ErrorAction SilentlyContinue swallowed real CIM/access errors into the same empty result as a free port, so a busy port green-OK'd. Switch to -ErrorAction Stop and, in the catch, treat only Get-NetTCPConnection's ObjectNotFound (no listener) as "free"; every other error returns $null ("can't tell"). (Bugbot Med) - Port-ownership check now reuses Test-ClusterRunning instead of a bare `k3d cluster list -o json`: it wraps the call in the same ~15s job deadline, so a wedged Docker engine can't hang preflight (Bugbot High), and it gates on serversRunning >= 1, so a STOPPED leftover cluster no longer masks a foreign listener on 6550 (Bugbot Med). - Regenerate scripts/manifest.sha256 for the changed install-k8s.ps1. - Add Pester coverage: probe error -> $null, ObjectNotFound -> free, stopped-leftover + foreign listener -> fail, running-owned -> ok. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
divyasinghds
added a commit
that referenced
this pull request
Aug 6, 2026
…gated) Address PR #622 review on the Windows port-6550 preflight: - Get-PfPortListening no longer fails open: -ErrorAction SilentlyContinue swallowed real CIM/access errors into the same empty result as a free port, so a busy port green-OK'd. Switch to -ErrorAction Stop and, in the catch, treat only Get-NetTCPConnection's ObjectNotFound (no listener) as "free"; every other error returns $null ("can't tell"). (Bugbot Med) - Port-ownership check now reuses Test-ClusterRunning instead of a bare `k3d cluster list -o json`: it wraps the call in the same ~15s job deadline, so a wedged Docker engine can't hang preflight (Bugbot High), and it gates on serversRunning >= 1, so a STOPPED leftover cluster no longer masks a foreign listener on 6550 (Bugbot Med). - Regenerate scripts/manifest.sha256 for the changed install-k8s.ps1. - Add Pester coverage: probe error -> $null, ObjectNotFound -> free, stopped-leftover + foreign listener -> fail, running-owned -> ok. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
divyasinghds
force-pushed
the
fix/557-win-port-6550-preflight
branch
from
August 6, 2026 11:15
22dd6df to
02013a5
Compare
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 b2caa60. Configure here.
New-K3dCluster binds the cluster API server to 127.0.0.1:6550, but Test-Preflight never checked whether 6550 was already in use. On a machine where a leftover/other k3d cluster or an unrelated service owns 6550, `k3d cluster create` failed and the installer surfaced k3d's raw stderr instead of a clear "port already in use" cause. Add Get-PfPortListening (Get-NetTCPConnection based; $null when undeterminable) and a port-6550 check to Test-Preflight. A port owned by THIS installer's own already-running cluster is fine (that run reuses it), so the check only hard-fails when the listener is NOT our cluster, with actionable guidance to find and stop the owner. Adds Pester coverage. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…gated) Address PR #622 review on the Windows port-6550 preflight: - Get-PfPortListening no longer fails open: -ErrorAction SilentlyContinue swallowed real CIM/access errors into the same empty result as a free port, so a busy port green-OK'd. Switch to -ErrorAction Stop and, in the catch, treat only Get-NetTCPConnection's ObjectNotFound (no listener) as "free"; every other error returns $null ("can't tell"). (Bugbot Med) - Port-ownership check now reuses Test-ClusterRunning instead of a bare `k3d cluster list -o json`: it wraps the call in the same ~15s job deadline, so a wedged Docker engine can't hang preflight (Bugbot High), and it gates on serversRunning >= 1, so a STOPPED leftover cluster no longer masks a foreign listener on 6550 (Bugbot Med). - Regenerate scripts/manifest.sha256 for the changed install-k8s.ps1. - Add Pester coverage: probe error -> $null, ObjectNotFound -> free, stopped-leftover + foreign listener -> fail, running-owned -> ok. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
After the rebase merged our port-6550 Pester tests with #612, Test-Preflight's network-reachability block calls Has for kubectl/helm/k3d. The "port 6550 in use by our running cluster -> ok" case passes ownership, so it now continues into that block, where a k3d-only -ParameterFilter left those later Has calls with no matching mock ("No mock for command 'Has' matched"). Use a plain default mock (k3d + tools present -> only always-critical hosts probed) so every Has call is covered and the case does not throw. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…d-fail reuse (Bugbot 3728340365)
The port-6550 ownership check decided ownership solely from Test-ClusterRunning,
whose bounded `k3d cluster list` maps BOTH a timeout AND a parse failure to
$false. The ownership block treated that $false as "foreign listener" and
HARD-FAILED preflight with stop/delete hints, so a slow/wedged Docker on a
normal re-run wrongly blocked the install and pointed the operator at their own
cluster -- conflating "can't determine" with "definitely not ours".
Make cluster run-state tri-state:
- Get-ClusterRunStateFromList (pure) and Get-ClusterRunState (bounded) return
'running' | 'down' | 'unknown'. Get-ClusterRunState reports 'unknown' only
when the list times out or its output is unparseable.
- Test-ClusterRunningInList / Test-ClusterRunning become thin boolean wrappers
(=='running'), preserving their existing contracts and callers.
The ownership block now only hard-fails when CONFIDENT the listener is foreign
('down': enumerated and ours is absent/stopped, or no k3d installed). An
'unknown' read downgrades to a warning and proceeds, letting New-K3dCluster's
start/repair path settle it instead of blocking the install.
Tests: existing 3 cases updated to mock Get-ClusterRunState; added an
indeterminate case (list timed out -> warns, does NOT hard-fail). Manifest
regenerated. Pester not run locally (pwsh unavailable); validated by source
analysis. Source-of-truth guards for Test-ClusterRunning still hold.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…t High 3728714531) Get-ClusterRunState ran `k3d cluster list <name> -o json`, which fatals with empty stdout when the named cluster is absent. The classifier read that empty output as 'unknown' -> warn-and-proceed, so a genuinely-absent cluster with a FOREIGN listener on 6550 escaped the hard-fail -- exactly the "re-run after the first create failed on the busy port" case #557's preflight must catch. List ALL clusters instead (`k3d cluster list -o json`, no name) and look for $CLUSTER_NAME in the parsed array. A successful full list always emits at least `[]`, so absent-vs-error stays separable: - completed list without a running $CLUSTER_NAME (absent, stopped, or empty []) -> 'down' (confidently not ours -> hard-fail on a busy port) - only a TIMED-OUT or unparseable/failed list -> 'unknown' (warn-and-proceed) Tests: added a Get-ClusterRunState tri-state Describe -- pure classifier cases (absent/empty-list -> 'down'; empty/garbage -> 'unknown') plus bounded cases (timeout -> 'unknown'; completed-but-absent -> 'down'). Manifest regenerated. Pester not run locally (pwsh unavailable); validated by source analysis. Source-of-truth guards for Test-ClusterRunning still hold. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…rRunState (CI Pester) The two bounded-wrapper cases mocked Start-Job/Wait-JobWithProgress/Receive-Job, which is environment-fragile and fails under CI Pester. Coverage is retained via the pure Get-ClusterRunStateFromList tests + the Test-ClusterRunning source-guard (bounded-job regex). No product-code change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
divyasinghds
force-pushed
the
fix/557-win-port-6550-preflight
branch
from
August 6, 2026 13:46
f47d879 to
c583a35
Compare
shujaatTracebloc
approved these changes
Aug 6, 2026
shujaatTracebloc
left a comment
Contributor
There was a problem hiding this comment.
Reviewed the code and all checks: LGTM.
- Tri-state
Get-ClusterRunState/Get-ClusterRunStateFromListcleanly separates 'confidently not ours' (down) from 'can't tell' (unknown), keyed on a FULLk3d cluster list(always emits[]on success) so an absent cluster is a definite 'down' — correctly resolves the earlier Bugbot findings 3728340365 / 3728714531. Only a HARD-fails on a confidently-foreign listener; timeout/unreadable warns-and-proceeds. Get-PfPortListeningno longer fails open:-ErrorAction Stoproutes every error to the catch, ObjectNotFound → free ($false), any other error → $null (skip), so a busy-but-unreadable port is never green-OK'd.Test-ClusterRunningrefactored onto the shared bounded helper (no logic duplication); good Pester coverage of the pure classifier + all four preflight ownership branches; manifest.sha256 restamped.
The E2E auth-proxy (squid) red was the flaky egress test noted in the PR — re-ran and it's green; it exercises Linux egress proxying and is untouched by this Windows-PowerShell-only change. No unresolved Bugbot/review threads. Satisfies #557.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Closes #557.
Fix
Add
Get-PfPortListening+ a port-6550 check toTest-Preflight, hard-failing with a clear message only when the listener is not our own cluster (avoids the cryptic downstream k3d error).Files
scripts/install-k8s.ps1,scripts/tests/install-k8s.Tests.ps1Validation
Pester tests added; regex-verified against source.
pwshunavailable in this env — please run the Pester suite on a Windows runner before merge.🤖 Generated with Claude Code
Note
Medium Risk
Changes installer preflight and cluster detection logic on Windows; incorrect tri-state classification could block valid re-runs or miss real conflicts, though unknown states are explicitly warn-only.
Overview
Adds a Windows preflight check for API port 6550 (where k3d binds the cluster API) so installs fail early with actionable hints instead of opaque k3d errors at cluster create.
Get-PfPortListeningprobes whether something is listening on the port, treatingObjectNotFoundas free but returning$nullon real probe failures so a busy port is never green-lit when the check could not run.When 6550 is busy, ownership uses a new tri-state
Get-ClusterRunState/Get-ClusterRunStateFromList: fullk3d cluster list -o json(not name-filtered) inside the existing ~15s job deadline. Running tracebloc cluster → OK to reuse; down (absent/stopped/other clusters) → hard fail; unknown (timeout/unparseable list) → warn and continue.Test-ClusterRunningis refactored to delegate to this classifier.Pester coverage for the classifier, port probe behavior, and
Test-Preflightport scenarios;manifest.sha256updated forinstall-k8s.ps1.Reviewed by Cursor Bugbot for commit c583a35. Bugbot is set up for automated code reviews on this repo. Configure here.