Skip to content

Make controller-gen/kustomize/golangci-lint/envtest tool-binary caching reliable - #2367

Open
kaovilai wants to merge 2 commits into
openshift:oadp-devfrom
kaovilai:fix-tool-version-check-oadp-dev
Open

Make controller-gen/kustomize/golangci-lint/envtest tool-binary caching reliable#2367
kaovilai wants to merge 2 commits into
openshift:oadp-devfrom
kaovilai:fix-tool-version-check-oadp-dev

Conversation

@kaovilai

@kaovilai kaovilai commented Aug 10, 2026

Copy link
Copy Markdown
Member

Folds in #2152 (same author, same theme, reviewer bandwidth is thin — consolidating into one PR rather than two small ones).

Part 1: version-checking for controller-gen/kustomize/golangci-lint

go-install-tool-branch only installs a build tool (controller-gen, kustomize, golangci-lint) when the binary is missing, never verifying the pinned version against what's already on disk. Once a binary lands at bin/<branch>/<tool>, it's reused forever — even across branch switches in the same checkout, even after CONTROLLER_TOOLS_VERSION/KUSTOMIZE_VERSION/GOLANGCI_LINT_VERSION change — because bin/ is gitignored and nothing else resets it. The controller-gen/kustomize target help text even claims otherwise ("If wrong version is installed, it will be overwritten/removed"), but the recipes didn't actually do that.

kustomize/controller-gen targets also weren't fully .PHONY (only the wrapper name was, not the binary path), so Make's own mtime-based staleness check could skip the recipe entirely before any version-check logic even ran.

I hit this while investigating an unexpectedly large make manifests reformat diff on oadp-1.4 — traced it back to a stale cached controller-gen/kustomize binary in a long-lived local checkout.

Fix: added go-install-tool-versioned, which compares a sidecar <binary>.version marker file against the pinned version instead of introspecting the binary's own --version output. Binary introspection isn't reliable for every tool installed this way — confirmed in practice: three bin/*/kustomize binaries on this machine, all installed the same way, reported (devel), a literal unexpanded $Format:%H$ git-archive placeholder, and a correct v5.2.1 respectively.

Part 2: envtest arch-check (folds in #2152)

Same root cause, different failure mode: setup-envtest isn't even branch-scoped (ENVTEST ?= $(LOCALBIN)/setup-envtest, no $(BRANCH_VERSION)), so it's shared across every branch checkout too. A containerized Make target (podman/docker build with a different GOARCH) can write a linux binary into bin/, replacing the native host binary make test needs.

#2152 proposed removing+reinstalling the binary when $(ENVTEST) --help fails — but I found that check unreliable the same way binary---version introspection was unreliable for kustomize: setup-envtest's own --help exits 2 by its own convention even on a perfectly working binary, so that check would trigger a reinstall on every single invocation, permanently defeating the cache (verified: it printed "Removing incompatible setup-envtest binary" immediately after a fresh, working install).

Fixed version checks specifically for exit code 126 (POSIX "found but cannot execute" / exec format error), not any nonzero exit — verified by cross-compiling a real linux/amd64 setup-envtest and running it on a darwin/arm64 host: the shell reports exit 126 distinctly from the tool's own exit codes. Also added $(ENVTEST) to .PHONY, matching the fix in Part 1 (same Make-recipe-skip issue).

How I tested (both parts)

  • rm -rf bin/oadp-dev then make controller-gen / make kustomize / make golangci-lint / make envtest individually — each installs fresh (writing a .version marker for the first three).
  • Re-running each immediately after → no reinstall, binary mtime unchanged, no network call.
  • Simulated a version mismatch (bogus .version marker) for controller-gen/kustomize/golangci-lint → correctly detected, removed, reinstalled, marker rewritten.
  • Simulated a wrong-arch binary for envtest (cross-compiled linux/amd64, copied over the native binary) → correctly detected via exit 126, removed, reinstalled with a valid native binary.
  • make generate manifests bundle → zero diff against a clean checkout.
  • make lint → 0 issues.
  • make test → exit 0, all packages pass, api is up to date, bundle is up to date.

Plan to cherry-pick this to oadp-1.4 (already have #2368 open there for Part 1; will fold Part 2 in as well).

Note

Responses generated with Claude

Summary by CodeRabbit

  • Chores
    • Improved developer tool installation and version validation.
    • Ensured pinned versions of GolangCI-Lint, Kustomize, and Controller-Gen are installed consistently.
    • Added version tracking and maintained convenient unversioned command links.
    • Automatically replaces mismatched tool versions when needed.
    • Removed environment-test binaries that cannot run on the current system architecture.

go-install-tool-branch only installs when the binary is missing, never
verifying the pinned version against what's already on disk. Once a
binary lands in bin/<branch>/, it's reused forever across branch
switches and version bumps since bin/ is gitignored and nothing else
resets it. kustomize and controller-gen's targets also weren't fully
.PHONY (only the wrapper name was, not the binary path), so Make's own
mtime-based staleness check could skip their recipe entirely before
any version check ran.

Introduce go-install-tool-versioned, which compares a sidecar
<binary>.version marker file against the pinned version instead of
introspecting the binary's own --version output. Binary introspection
isn't reliable for every tool installed this way: kustomize's `version`
command depends on ldflags its own release process sets, which `go
install` doesn't set, so identically-installed kustomize binaries were
observed reporting "(devel)", an unexpanded `$Format:%H$` git-archive
placeholder, or a correct version string depending on unrelated
build-time factors.

Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

The Makefile now installs pinned development tools with version-marker files. It replaces mismatched binaries, preserves unversioned symlinks, and removes setup-envtest binaries that cannot execute on the current architecture.

Changes

Tool installation and compatibility

Layer / File(s) Summary
Version-marker installer
Makefile
Adds go-install-tool-versioned. The helper reuses a binary only when its .version marker matches. Otherwise, it removes the binary and marker, installs the requested version, and records the marker.
Pinned tool targets
Makefile
Updates GolangCI-Lint, Kustomize, and Controller-Gen targets to use the version-aware installer and preserve unversioned symlinks.
envtest architecture handling
Makefile
Removes setup-envtest when execution returns status 126 for an incompatible executable format.

Estimated code review effort: 2 (Simple) | ~15 minutes

Suggested reviewers: mpryc, shubham-pampattiwar

🚥 Pre-merge checks | ✅ 15
✅ Passed checks (15 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Stable And Deterministic Test Names ✅ Passed The full PR diff changes only Makefile; it adds or modifies no Ginkgo test files or It, Describe, Context, or When titles.
Test Structure And Quality ✅ Passed The PR diff changes only Makefile (15 insertions, 1 deletion); it adds no Ginkgo test code or It blocks, so this check is not applicable.
Microshift Test Compatibility ✅ Passed The full PR range changes only Makefile; it adds no Ginkgo declarations and no test or e2e paths, so this MicroShift check is not applicable.
Single Node Openshift (Sno) Test Compatibility ✅ Passed The pull request changes only Makefile tool-installation recipes; it adds no Ginkgo e2e tests or multi-node assumptions requiring SNO review.
Topology-Aware Scheduling Compatibility ✅ Passed The PR changes only Makefile tool-installation targets; no deployment manifests, operator/controller code, or scheduling constraints were added or modified.
Ote Binary Stdout Contract ✅ Passed The pull request changes only Makefile tool-install recipes; it adds no OTE binary process code or stdout writes in main or suite setup.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed The PR changes only Makefile; the exact diff adds no Ginkgo, e2e, or test code, so this check is not applicable.
No-Weak-Crypto ✅ Passed The complete PR diff changes only Makefile tool installation and architecture handling; it introduces no weak crypto, custom crypto, or secret/token comparison.
Container-Privileges ✅ Passed The PR changes only Makefile. The added lines introduce no privileged:true, hostPID, hostNetwork, hostIPC, SYS_ADMIN, or allowPrivilegeEscalation:true settings.
No-Sensitive-Data-In-Logs ✅ Passed The PR adds only Makefile messages for fixed tool names, pinned versions, and architecture status; no passwords, tokens, API keys, PII, hostnames, or customer data are logged.
Title check ✅ Passed The title clearly summarizes the main change: reliable caching for the four affected tool binaries.
Description check ✅ Passed The description explains why the changes were made and provides detailed testing steps and results.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@openshift-ci

openshift-ci Bot commented Aug 10, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: kaovilai

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Aug 10, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Makefile`:
- Around line 530-550: Update the versions target to read the .version sidecar
for marker-managed tools such as KUSTOMIZE instead of invoking the binary’s
version command. Preserve existing binary introspection for tools without marker
files, and reuse the marker path established by go-install-tool-versioned.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: e93a7bca-24c0-4d5d-82da-82c240a84ce2

📥 Commits

Reviewing files that changed from the base of the PR and between 7a3c9b0 and 8802555.

📒 Files selected for processing (1)
  • Makefile

Comment thread Makefile
Comment on lines +530 to +550
# go-install-tool-versioned installs $2 to branch-specific path $1, but only if $1 is missing
# or $1.version doesn't match the pinned version $3. Uses a sidecar marker file instead of
# introspecting the binary's own --version output, because that output is unreliable for some
# tools when installed via `go install` (e.g. kustomize reports "(devel)" or an unexpanded
# `$$Format:%H$$` placeholder instead of its real version, depending on build-time factors).
define go-install-tool-versioned
@if [ -f $(1) ] && [ -f $(1).version ] && [ "$$(cat $(1).version)" = "$(3)" ]; then \
echo "$(notdir $(1)) $(3) is already installed" ;\
else \
set -e ;\
mkdir -p $(dir $(1)) ;\
rm -f $(1) $(1).version ;\
TMP_DIR=$$(mktemp -d) ;\
cd $$TMP_DIR ;\
go mod init tmp ;\
echo "Installing $(notdir $(1)) $(3)" ;\
GOBIN=$(dir $(1)) go install -a -mod=mod $(2) ;\
cd - >/dev/null ;\
rm -rf $$TMP_DIR ;\
echo "$(3)" > $(1).version ;\
fi

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use the sidecar marker in the versions target.

Lines 530-534 state that go install can make Kustomize report (devel). Line 167 still obtains the Kustomize version from $(KUSTOMIZE) version --short. A correct $(KUSTOMIZE).version marker can therefore coexist with a false version report from make versions.

Read the sidecar marker for marker-managed tools. Preserve binary introspection only for tools that do not use a marker.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Makefile` around lines 530 - 550, Update the versions target to read the
.version sidecar for marker-managed tools such as KUSTOMIZE instead of invoking
the binary’s version command. Preserve existing binary introspection for tools
without marker files, and reuse the marker path established by
go-install-tool-versioned.

Folds in the fix from openshift#2152 (same author, same theme: harden
Makefile tool-binary caching under bin/). A containerized Make target
(e.g. podman/docker build with a different GOARCH) can write a linux
binary into the shared bin/ directory, replacing the native host
binary `make test` needs — and since setup-envtest isn't
branch-scoped like the other three tools, that binary is shared
across every branch checkout too.

openshift#2152's own check used `$(ENVTEST) --help`'s exit code as the
"is this binary compatible" signal, but that's unreliable the same
way relying on kustomize's --version output was: setup-envtest's own
--help exits 2 by its own convention even on a perfectly good binary,
so that check would have triggered a reinstall on every single
invocation, permanently defeating the cache. Verified by
cross-compiling a real linux/amd64 setup-envtest and running it on
this darwin/arm64 host: the shell reports exit code 126 specifically
(POSIX "found but cannot execute" / exec format error) — check that
instead of any nonzero exit.

Also added $(ENVTEST) to the .PHONY line, matching the fix already
applied to controller-gen/kustomize in the previous commit: without
it, Make's own mtime-based staleness check can skip the recipe (and
therefore this check) entirely once the binary file exists.

Closes openshift#2152

Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
@kaovilai kaovilai changed the title Make controller-gen/kustomize/golangci-lint version checks reliable Make controller-gen/kustomize/golangci-lint/envtest tool-binary caching reliable Aug 12, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Makefile (1)

544-566: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Make marker-managed caches platform-specific.

go-install-tool-versioned checks only the version marker. The cache paths for Controller-Gen, Kustomize, and GolangCI-Lint omit GOOS and GOARCH. A same-version binary from another architecture can be reused and fail at execution. Include the platform in the cache key or validate the binary before reuse.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Makefile` around lines 544 - 566, The go-install-tool-versioned cache
currently reuses markers based only on tool version, allowing binaries from
another platform to be selected. Update go-install-tool-versioned and the
Controller-Gen, Kustomize, and GolangCI-Lint cache paths or marker validation to
include GOOS and GOARCH, ensuring reuse only occurs for the current platform
while preserving version checks.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@Makefile`:
- Around line 544-566: The go-install-tool-versioned cache currently reuses
markers based only on tool version, allowing binaries from another platform to
be selected. Update go-install-tool-versioned and the Controller-Gen, Kustomize,
and GolangCI-Lint cache paths or marker validation to include GOOS and GOARCH,
ensuring reuse only occurs for the current platform while preserving version
checks.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 5cedc214-40c1-438d-a936-5286a91d2bf1

📥 Commits

Reviewing files that changed from the base of the PR and between 8802555 and a70d9a8.

📒 Files selected for processing (1)
  • Makefile

@openshift-ci

openshift-ci Bot commented Aug 12, 2026

Copy link
Copy Markdown

@kaovilai: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/5.0-e2e-test-aws a70d9a8 link true /test 5.0-e2e-test-aws

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant