Skip to content

🐛 fix(dev): select envtest assets by host OS/arch - #326

Merged
konih merged 1 commit into
mainfrom
lane/dev-envtest-01-r2
Aug 23, 2026
Merged

🐛 fix(dev): select envtest assets by host OS/arch#326
konih merged 1 commit into
mainfrom
lane/dev-envtest-01-r2

Conversation

@konih

@konih konih commented Aug 23, 2026

Copy link
Copy Markdown
Collaborator

Problem

Four envtest suites each carried their own copy of the kubebuilder scaffold's "first directory under bin/k8s" pattern for locating the control-plane binaries. os.ReadDir returns entries sorted, so a bin/k8s holding downloads for more than one platform — a checkout shared between machines, a stale download, a directory left behind by an earlier --bin-dir — resolves the lexically-first entry regardless of what host is running.

On Apple silicon with both platforms present, that picks 1.35.0-linux-amd64, and every suite dies in BeforeSuite with exec format error. The suites do not fail loudly — they run 0 specs and report ok.

Reproduced on main: 0 of 48 controller specs, 0 of 5 webhook specs. On this branch: 48 of 48 and 5 of 5.

Fix

One shared resolver, internal/envtestassets:

  • filters candidate directories by the -<goos>-<goarch> suffix, which also rules out non-asset directories;
  • picks the highest version numerically, field by field, so 1.36.10 outranks 1.36.2 (lexical order gets that backwards);
  • returns an absolute path so it survives a caller changing directory;
  • returns "" when there is no match, leaving BinaryAssetsDirectory unset so controller-runtime falls back to its own default.

Resolve prefers KUBEBUILDER_ASSETS when set, matching the order controller-runtime itself resolves in.

The four suites now call the shared resolver instead of duplicating the scaffold pattern.

Why linux CI cannot regress

hack/coverage.sh exports KUBEBUILDER_ASSETS from setup-envtest -p path, and controller-runtime's BinPathFinder prefers that environment variable over an envtest.Environment's BinaryAssetsDirectory — verified against the module source. CI's resolution is unchanged; this only affects a bare go test ./internal/... on a developer machine.

Verification

  • task coverage — 90.7% (floor 90)
  • task coverage:race — 90.7%, no data races
  • task lint — 0 issues; task arch-lint — no warnings; task verify — ok
  • envtest suites re-run with KUBEBUILDER_ASSETS unset against a bin/k8s containing 1.35.0-linux-amd64, 1.36.0-linux-amd64 and 1.36.2-darwin-arm64: 48/48 and 5/5

docs/development/setup.md documents the multi-platform bin/k8s case; .go-arch-lint.yml registers the new component.

Four envtest suites resolved their control-plane binaries by returning the
first directory under bin/k8s. os.ReadDir returns that listing sorted, so on
an Apple-silicon workstation whose bin/ also holds linux downloads the pick
was 1.35.0-linux-amd64 and every suite died in BeforeSuite with

    fork/exec bin/k8s/1.35.0-linux-amd64/etcd: exec format error

with the correct 1.36.2-darwin-arm64 assets sitting right next to it. This is
a selection bug, not a procurement one: local green on internal/collect,
internal/controller, internal/pipeline and internal/webhook/v1alpha1 has been
unobtainable on a non-linux host for as long as this has been true.

internal/envtestassets now resolves the assets once, for all four suites:
KUBEBUILDER_ASSETS first (the order controller-runtime itself uses, so an
exporting harness stays authoritative), then the bin/k8s entry whose name
carries the -<goos>-<goarch> suffix. Only suffix matches are considered, which
also skips non-asset directories such as the stray bin/k8s/k8s a --bin-dir
typo leaves behind, and among matches the highest version wins compared field
by numeric field so 1.36.10 outranks 1.36.2.

CI is unaffected: hack/coverage.sh and `make test` export KUBEBUILDER_ASSETS
from `setup-envtest ... -p path`, which resolves the host platform itself, and
controller-runtime's BinPathFinder consults that variable before any
BinaryAssetsDirectory. The linux-amd64 selection is pinned by its own table
case rather than left to CI to discover.

The helper joins internal/digest and internal/errors under the arch-lint
`shared` component because all four suites, in four different components, need
the same resolution; each still passes its own base paths, since the webhook
suite sits one directory deeper than the others.
@konih
konih merged commit 59f6bb4 into main Aug 23, 2026
35 checks passed
@konih
konih deleted the lane/dev-envtest-01-r2 branch August 23, 2026 15:53
@codecov

codecov Bot commented Aug 23, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.29730% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/envtestassets/assets.go 97.29% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@sonarqubecloud

Copy link
Copy Markdown

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