Skip to content

ci(workflows): pin flux version across CI toolchain steps - #4442

Merged
Aleksei Sviridkin (lexfrei) merged 5 commits into
mainfrom
ci/pin-flux-in-build-toolchain
Sep 26, 2026
Merged

Aleksei Sviridkin (lexfrei) merged 5 commits into
mainfrom
ci/pin-flux-in-build-toolchain

Conversation

@IvanHunters

@IvanHunters IvanHunters commented Sep 24, 2026 •

Copy link
Copy Markdown
Collaborator

What this PR does

The flux CLI was installed across the build, PR, tag, nightly and e2e-fork workflows and in the e2e-sandbox image through the vendor install.sh with no version pin, so each install resolved the installer's floating latest. latest had advanced to v2.9.5, and a matrix job on #4429 failed when that release's checksums transiently 4xx'd during install. Pinning does not stop the checksum host from returning a transient error, so it is not a fix for that flake; what it fixes is the uncontrolled version. This sets FLUX_VERSION to 2.8.6 and guards each flux install on the installed client version (workflows, with a fixed-string match) or passes it to install.sh (the e2e-sandbox image), matching the already-pinned "Set up promotion toolchain" steps, so the flux CLI is fixed and reproducible across CI with no flux install resolving floating latest. This is scoped to the flux CLI only: other tools some of these steps install (yq, helm, mc) are not touched here, and the yq floating-latest is tracked separately in #3640.

Screenshots

Not applicable — CI and test-image change, no UI impact.

Downstream repositories

Release note

ci(workflows): pin the flux CLI version across CI toolchain steps and the e2e-sandbox image so the flux CLI is fixed and reproducible instead of following the installer's floating latest

Summary by CodeRabbit

  • Chores
    • Build, release, and end-to-end test environments now use Flux CLI version 2.8.6.
    • Flux is installed when it is missing or does not match version 2.8.6; an existing matching installation is reused.
    • The end-to-end sandbox image now installs Flux version 2.8.6 by default.

@github-actions github-actions Bot added size/M This PR changes 30-99 lines, ignoring generated files area/uncategorized PR auto-labeler could not map title scope to a known area/*; please review labels Sep 24, 2026
@coderabbitai

coderabbitai Bot commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Advanced

Run ID: 641f6374-d57a-4a0c-a6eb-9132ebe7d674

📥 Commits

Reviewing files that changed from the base of the PR and between 626a107 and ba46b9f.

📒 Files selected for processing (1)
  • packages/core/testing/images/e2e-sandbox/Dockerfile

Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 6 remain after this review.


📝 Walkthrough

Walkthrough

CI workflows now check whether the Flux client reports version 2.8.6. If it does not, the workflows install that version. The e2e sandbox Dockerfile also sets and passes a default Flux version of 2.8.6 to the installer.

Changes

Flux version pinning

Layer / File(s) Summary
Align Flux setup across CI workflows
.github/workflows/build-main.yaml, .github/workflows/build-release.yaml, .github/workflows/e2e-fork.yaml, .github/workflows/nightly.yaml, .github/workflows/pull-requests.yaml, .github/workflows/tags.yaml
The toolchain setup checks for Flux 2.8.6 and installs that version when the client does not match. Several workflows download the installer to a temporary file, run it with the version configured, and remove the file.
Pin Flux in the e2e sandbox image
packages/core/testing/images/e2e-sandbox/Dockerfile
The Dockerfile adds a default FLUX_VERSION of 2.8.6 and passes it to the Flux installer.

Priority: ⬇️ Low

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

Change: Bug fix

Merge Risk: ⚪ Minimal · up to ba46b

The CI workflows and sandbox image use the intended Flux version, and no concrete merge-blocking regression is evident.

Architecture Summary

Architecture risk: 🔵 Low · up to ba46b

The change affects 1 system.

Changed systems: packages/core

Architecture concerns
No architecture-level concerns identified.

Review details

Systems and components

  • observed — packages/core (library) was modified; 1 changed file maps to changed impact.

Before / after behavior

  • observed — Modified behavior in packages/core/testing/images/e2e-sandbox/Dockerfile: Adds the FLUX_VERSION build argument with default 2.8.6.
  • observed — Modified behavior in packages/core/testing/images/e2e-sandbox/Dockerfile: Replaces the piped Flux installer with a curl -fsSL download to a temporary file, executes it with FLUX_VERSION set from the build argument, then removes the file.
  • observed — Modified behavior in .github/workflows/build-main.yaml: The setup step now documents and installs pinned Flux version 2.8.6 when the client output does not exactly match it. The comparison uses fixed-string matching; installation downloads the script to a temporary file, runs it with the version environment variable under sudo, and removes the file. This replaces the previous command-presence check and unpinned installer invocation.
  • observed — Modified behavior in .github/workflows/build-release.yaml: The Flux version check now uses grep -Fqx instead of grep -qx to compare the client version against FLUX_VERSION, so the comparison is a literal string match rather than a regex match.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: pinning the Flux version across CI workflow toolchain steps. It matches the changes in the workflows and e2e-sandbox image.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0…
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

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.

IvanHunters NOT LGTM, but only because of the text. The workflow change is correct: every flux install in .github/workflows now goes through the version gate with 2.8.6, and the gate works. What blocks is a missing sign-off on the first commit and two sentences in the PR body, which becomes the merge commit message.

I checked the gate against a fake flux with different outputs. flux: v2.8.6 skips the install. A newer or older version, v2.8.60, a version without the v, a CRLF line ending, and a missing binary all reinstall. Extra lines or stderr noise still match, since grep -x works per line. The real 2.8.6 binary prints exactly flux: v2.8.6. The installer takes FLUX_VERSION without the v and builds releases/tags/v${FLUX_VERSION} from it, so passing it through sudo env is the right form. On this head the changed steps ran and installed 2.8.6, both in Build packages/core/platform and in Finalize. actionlint finds nothing new in the six files.

Commit 783adc7 has no Signed-off-by: line. Its body ends with Assisted-by: LLM, and the DCO check on this head is in action_required. The sign-off on the second commit covers only that commit, and docs/agents/contributing.md treats a missing sign-off as a blocker. git rebase --signoff origin/main and a force-push fix it.

The PR body claims more than the pin does, in two places. First, "no CI step resolves latest anymore" is not true yet. packages/core/testing/images/e2e-sandbox/Dockerfile:22 still runs curl -sSL "https://fluxcd.io/install.sh" | bash with no version, and the Build packages/core/testing job builds that image. On this head the layer came from cache, but on a cache miss it resolves latest like the old steps did.

Second, the body and the release note read as if the pin removes the transient 4xx. It does not. The job on #4429 failed at Downloading hash https://github.com/fluxcd/flux2/releases/download/v2.9.5/flux_2.9.5_checksums.txt with curl exit 22. v2.9.5 was published on 2026-08-31, weeks before that run, so it was not a release with half-uploaded assets. With the pin, the build job on this head fetched https://github.com/fluxcd/flux2/releases/download/v2.8.6/flux_2.8.6_checksums.txt, which is the same host and the same kind of URL. A transient 4xx there fails the pinned install in the same way. The pin makes the version fixed and reproducible, and that is the benefit to describe. Please either pin the sandbox Dockerfile too (an ARG FLUX_VERSION next to the other tool versions) or say "no workflow step", and drop the claim that the flakiness is gone from both the body and the release note.

Two non-blocking notes:

  1. 2.8.6 is now a literal in eleven FLUX_VERSION: lines across eight workflow files, and hack/promote-packages-contract.bats pins only the three promotion steps. This matters because the build steps run flux push artifact, and hack/verify-promoted-packages.sh compares the result against an excludeOCI list tied to the flux version "pinned as FLUX_VERSION (2.8.6) in all three workflow steps". Push and verify agree now, but the next bump can touch only the three pinned steps and nothing will fail. Extending the contract test to every FLUX_VERSION: line would close that, and that comment could stop counting three.
  2. The e2e-fork comment this PR edits still points to "packages/system/fluxcd, 2.8.x". That directory does not exist. The shipped distro is internal/fluxinstall/manifests/fluxcd.yaml at v2.8.0. This is older than the PR, but the comment is already being edited. A 2.8.6 CLI with 2.8.0 controllers is fine here, since CI uses the CLI only to push and pull OCI artifacts.

@IvanHunters

Copy link
Copy Markdown
Collaborator Author

Thanks for the careful review — all three blocking points are addressed and the branch is force-pushed.

DCO / sign-off: both commits are rebuilt so every commit now carries Signed-off-by: IvanHunters <[email protected]> and stays GPG-signed. The earlier missing trailer came from an amend that replaced the message without re-adding it.

Unpinned flux in the sandbox image: packages/core/testing/images/e2e-sandbox/Dockerfile now declares ARG FLUX_VERSION=2.8.6 next to the other tool pins and passes it into the installer (... | FLUX_VERSION="${FLUX_VERSION}" bash), so the Build packages/core/testing job no longer resolves floating latest. Checked with docker build --check.

Overclaim in the PR text: you're right that pinning does not remove the transient 4xx — the checksums are fetched from the same host regardless of the version. I dropped every "removes flakiness / 4xx" claim from the PR body, the release note, and the commit messages, and restated the real benefit: the flux CLI version is now fixed and reproducible across all of CI, with no surprise version bump, and no step (workflows or the e2e-sandbox image) resolves floating latest anymore. That last statement now holds precisely because the Dockerfile is pinned too.

Comment path (non-blocking): fixed the e2e-fork comment to point at the distro actually shipped, internal/fluxinstall/manifests/fluxcd.yaml (v2.8.0); the CLI at 2.8.6 against those controllers is fine since it is only used for OCI push/pull.

Follow-up (accepted, separate PR): extending hack/promote-packages-contract.bats to assert all 11 FLUX_VERSION: lines — agreed, I'll do that on its own so this PR stays scoped.

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.

IvanHunters LGTM, thanks.

@sircthulhu Kirill Ilin (sircthulhu) 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.

Pinning the flux CLI is the right call, and the version guard plus the no-v value line up with how install.sh resolves tags. A few things block merge: the pin isn't protected by a contract test, the post-install result isn't verified, and the e2e-sandbox RUN can still pipe an error page into bash. Details inline.

Comment thread .github/workflows/build-main.yaml Outdated
run: |
command -v flux >/dev/null \
|| curl -fsSL https://fluxcd.io/install.sh | sudo bash
if ! flux version --client 2>/dev/null | grep -qx "flux: v${FLUX_VERSION}"; then

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.

This pin is now duplicated across the workflows and the e2e-sandbox Dockerfile, and nothing keeps the copies in sync or stops the old command -v flux || curl … | sudo bash idiom from coming back via copy-paste — hack/promote-packages-contract.bats already calls out that exact failure mode for the promotion steps. Please extend it (or add a sibling contract) so that CI fails when:

  • any fluxcd.io/install.sh call in .github/workflows/*.yaml or the e2e-sandbox Dockerfile has no FLUX_VERSION next to it;
  • FLUX_VERSION values differ between files.

Alternatively, a composite action (e.g. .github/actions/setup-flux) would collapse the repeated block into one place with a single version constant.

if ! flux version --client 2>/dev/null | grep -qx "flux: v${FLUX_VERSION}"; then
install_script="$(mktemp)"
curl -fsSL https://fluxcd.io/install.sh -o "$install_script"
sudo env "FLUX_VERSION=$FLUX_VERSION" bash "$install_script"

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.

The installed version is never checked after install.sh runs. install.sh writes to /usr/local/bin; if another flux earlier in PATH shadows it, the step succeeds and later steps silently use the unpinned binary. Suggest re-running the check after install (here and in the other copies):

flux version --client | grep -Fqx "flux: v${FLUX_VERSION}" \
  || { echo "::error::flux ${FLUX_VERSION} not effective on PATH"; exit 1; }

Nit: grep -Fqx instead of grep -qx, so the dots in the version aren't treated as regex wildcards.

Comment thread .github/workflows/build-main.yaml Outdated
@@ -63,9 +63,15 @@ jobs:
# Ephemeral runners lack the flux CLI the installer's image-packages step
# shells out to; install if absent (idempotent).

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.

The comment still says "install if absent (idempotent)", but the step now also reinstalls when the version differs. The same wording is in build-release.yaml:110, tags.yaml:144 and pull-requests.yaml:356.

RUN curl -sSL "https://github.com/mikefarah/yq/releases/download/v4.53.3/yq_${TARGETOS}_${TARGETARCH}" -o /usr/local/bin/yq \
&& chmod +x /usr/local/bin/yq
RUN curl -sSL "https://fluxcd.io/install.sh" | bash
RUN curl -sSL "https://fluxcd.io/install.sh" | FLUX_VERSION="${FLUX_VERSION}" bash

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.

curl -sSL without -f, under the default /bin/sh -c without pipefail: on a 4xx/5xx the error page is piped into bash and curl's exit code is lost — the same transient-installer failure class this PR is addressing. Please use curl -fsSL together with SHELL ["/bin/bash", "-o", "pipefail", "-c"], or download to a file first as the workflows do.

sudo env "FLUX_VERSION=$FLUX_VERSION" bash "$install_script"
rm -f "$install_script"
fi
command -v yq >/dev/null || { sudo curl -sSL -o /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 && sudo chmod +x /usr/local/bin/yq; }

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.

The same step still installs yq from releases/latest and helm via get-helm-3 without a version, and mc in the e2e-sandbox Dockerfile is unpinned too. The PR description says no step resolves a floating latest any more — please either pin these here or narrow the description and release note to the flux CLI.

# the OCIR token is loaded, where a pinned installer matters most;
# keep it in step with the flux distro cozystack ships
# (packages/system/fluxcd, 2.8.x).
# (internal/fluxinstall/manifests/fluxcd.yaml, v2.8.0).

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.

Non-blocking: "keep it in step with the flux distro" isn't enforced anywhere — the CLI is at 2.8.6 while the shipped distro is v2.8.0. If the two must stay in the same minor, the contract test from the comment on build-main.yaml could assert it.

@IvanHunters

Copy link
Copy Markdown
Collaborator Author

Thanks, this is a sharp review. Pushed fixes for the concrete correctness points and scoped the rest.

Literal version match: fixed. All the guards this PR adds now use grep -Fqx, so the dots in the version are matched literally and a flux: v2X8X6 can't satisfy the check. I left the three pre-existing promotion-toolchain guards (promote-rc.yaml, pull-requests-release.yaml, and the promotion step in pull-requests.yaml) untouched to keep this PR scoped; folding -Fqx into those belongs with the contract test below.

Sandbox installer piped into bash: fixed. The e2e-sandbox flux step now does curl -fsSL ... -o /tmp/flux-install.sh and runs the file, so a 4xx/5xx aborts the build instead of piping an error page into bash and losing curl's exit code.

Stale comments: fixed. The "install if absent (idempotent)" comments in build-main.yaml, build-release.yaml, tags.yaml and pull-requests.yaml now say the step installs when the pinned version is not the one present.

Overclaim in the description: narrowed. The body and release note now scope the "no floating latest" statement to the flux CLI and explicitly say yq, helm and mc are not touched here (yq's floating-latest is tracked in #3640).

On the two I did not change in this PR:

Contract test for the pin: agreed, and I'd like to do it right rather than minimally. A sibling contract that fails when any fluxcd.io/install.sh call under .github/workflows or the e2e-sandbox Dockerfile has no FLUX_VERSION beside it, and when the FLUX_VERSION values diverge across files (and optionally that the CLI minor tracks internal/fluxinstall/manifests/fluxcd.yaml), is more than a one-line addition to hack/promote-packages-contract.bats. lexfrei flagged the same thing as non-blocking, so I'd prefer it as a focused follow-up PR that also pulls -Fqx into the promotion guards. Happy to open it right after this lands.

Post-install verification: I judged this non-blocking rather than skipping it on purpose. install.sh writes /usr/local/bin, which is ahead of the runner's shipped tool paths, and there is no other flux on these images, so a shadowing binary isn't a case that occurs here. I'm fine adding the flux version --client | grep -Fqx ... || exit 1 re-check if you'd rather have it belt-and-braces; say the word and I'll fold it into the same follow-up.

One note on the red check: Build packages/core/testing is failing on the mc download, not on flux. https://dl.min.io/client/mc/release/linux-amd64/mc now returns 410 Gone (MinIO archived community mc), so the sandbox image can't build on a cache miss; flux itself installs fine in that same run. That's being fixed in #4447 (mc from its GitHub release with a pinned checksum), and this branch goes green once that lands.

@IvanHunters
IvanHunters force-pushed the ci/pin-flux-in-build-toolchain branch from e1d80c9 to 626a107 Compare September 24, 2026 18:27

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.

IvanHunters NOT LGTM, only because the branch conflicts with main. The two new commits are fine.

The conflict is a single line in the e2e-sandbox Dockerfile. Main added ARG MC_VERSION=... exactly where this branch adds ARG FLUX_VERSION=2.8.6, so keep both ARG lines. The rest merges cleanly, including your flux step next to the new mc block. The rebase also brings in the mc fix, and that is what makes Build packages/core/testing red on this head. The log shows curl: (22) ... 410 from dl.min.io, and the flux layer right before it installed 2.8.6 without problems.

The new commits do what they say. The guards match the version literally with grep -Fqx, and the sandbox image downloads the installer to a file with curl -f, so an HTTP error fails the layer. No flux install in the workflows, the sandbox image or hack/ resolves latest, and actionlint shows no new warnings on the six workflows.

One non-blocking note. The three promotion guards still use grep -qx, so the repo now has two spellings of the same check. That fits the contract-test follow-up you mentioned.

The "Set up build toolchain" steps installed flux with a bare
`curl https://fluxcd.io/install.sh | sudo bash`, letting the installer
resolve its floating "latest". latest had advanced to v2.9.5, and a
matrix job on PR #4429 failed when that release's checksums transiently
4xx'd during install.

Pin FLUX_VERSION to 2.8.6 and guard on the installed client version, the
same shape the "Set up promotion toolchain" steps already use, so the
flux CLI is fixed and reproducible across CI instead of following latest.
This does not remove the checksum host's transient errors; it removes the
uncontrolled version bump. Related to the yq floating-latest pin in #3640.

Assisted-by: LLM
Signed-off-by: IvanHunters <[email protected]>
The nightly toolchain steps still fetched flux through the installer's
floating "latest". Pin them to FLUX_VERSION 2.8.6 with the same
version-gated guard so nightly's flux push artifact step uses a fixed,
reproducible CLI rather than whatever latest resolves to.

Also switch e2e-fork's already-pinned step from a presence check to the
same version gate, so a runner with a pre-cached older flux is corrected
rather than left as is, and fix that step's comment to point at the flux
distro cozystack actually ships
(internal/fluxinstall/manifests/fluxcd.yaml, v2.8.0).

Assisted-by: LLM
Signed-off-by: IvanHunters <[email protected]>
The e2e-sandbox image fetched flux through `install.sh` with no version,
so the build resolved the installer's floating "latest". Add an
ARG FLUX_VERSION, matching the neighbouring COZYHR_VERSION and
CRUST_GATHER_VERSION pins, and pass it to install.sh so the sandbox's
flux CLI is fixed and reproducible like the rest of the image's tools.

Assisted-by: LLM
Signed-off-by: IvanHunters <[email protected]>
The guard ran `grep -qx "flux: v${FLUX_VERSION}"`, where the dots in the
version are regex metacharacters, so a client printing `flux: v2X8X6`
would satisfy it. Use `grep -Fqx` for a fixed-string match in the build
toolchain guards this change added.

Also correct the step comments that still read "install if absent
(idempotent)": the step now installs whenever the pinned version is not
the one present, not only when flux is missing.

Assisted-by: LLM
Signed-off-by: IvanHunters <[email protected]>
…ox image

The flux install piped `curl -sSL` into bash, so on a 4xx/5xx the error
page was piped into the shell and curl's exit code was lost. Download the
installer to a file with `curl -fsSL` first, then run it, so an HTTP error
fails the build step instead of feeding bash a bad script.

Assisted-by: LLM
Signed-off-by: IvanHunters <[email protected]>

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.

IvanHunters LGTM. I rebased the branch onto main myself. The one conflict was in the e2e-sandbox Dockerfile, where main added ARG MC_VERSION next to your ARG FLUX_VERSION; I kept both.

@lexfrei
Aleksei Sviridkin (lexfrei) merged commit 9a92537 into main Sep 26, 2026
49 of 51 checks passed
@lexfrei
Aleksei Sviridkin (lexfrei) deleted the ci/pin-flux-in-build-toolchain branch September 26, 2026 14:50
IvanHunters added a commit that referenced this pull request Oct 5, 2026
## What this PR does

Workflows no longer run the flux install script as root. Every step that
needed the flux CLI downloaded `https://fluxcd.io/install.sh` and ran it
with `sudo`, so whatever that host served at the moment ran on runners
that later get registry credentials. PR #4442 pinned the version, but
the script was still fetched and executed. All 12 of those steps now use
`fluxcd/flux2/action`, pinned to the v2.8.6 commit with `version:
"2.8.6"`. The action downloads the release tarball, checks it against
that release's checksums file, and adds the binary to `PATH`.

Two workflows still took yq from the floating latest release, nightly
and the fork e2e lane. They now use the same install the promotion steps
already have: yq v4.53.3 checked against a committed SHA-256. I verified
that hash against the release's `checksums` file and against the binary
itself.

The helm-unittest plugin was installed at whatever version was newest.
The plugin embeds its own Helm, so a plugin release could change chart
test results on a PR that touched no chart. It's pinned to v1.1.2 now,
the version CI already runs. A runner that carries a different version
gets it replaced.

A new contract test scans every workflow for these three tools, because
an unpinned install usually comes back by copying an older step. On main
it fails on the install script, the missing setup action, the
latest-release yq and the unpinned plugin. I ran one mutation per guard,
and each one failed only the test meant to catch it. The existing
contract tests that checked `FLUX_VERSION` inside the old steps now
check for the action step.

The e2e sandbox image still runs `install.sh` in its Dockerfile. That's
an image build, not a workflow step, so I left it for a separate change.

Closes #3619

Closes #3640

Closes #4510

### Screenshots

Not applicable, no UI changes.

### Downstream repositories

- [x] No downstream repository is affected by this change
- [ ] [cozystack/website](https://github.com/cozystack/website) -
follow-up:
- [ ]
[cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack)
- follow-up:
- [ ]
[cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack)
- follow-up:
- [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up:
- [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up:
- [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) -
follow-up:
- [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) -
follow-up:
- [ ]
[cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server)
- follow-up:
- [ ]
[cozystack/external-apps-example](https://github.com/cozystack/external-apps-example)
- follow-up:
- [ ] [cozystack/examples](https://github.com/cozystack/examples) -
follow-up:
- [ ] [cozystack/community](https://github.com/cozystack/community) -
follow-up:

The diff touches only workflow tool-install steps and `hack/*.bats`
contract tests. Nothing in the trigger map reaches them.

### Release note

```release-note
ci(workflows): install flux through the commit-pinned upstream setup action instead of running fluxcd.io/install.sh as root, pin yq with checksum verification in the nightly and fork e2e workflows, and pin the helm-unittest plugin version.
```


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Reliability**
* CI workflows now use a consistent, pinned Flux version. The yq and
Helm plugin setup also verifies or enforces specific versions.
* **Tests**
* Added checks to ensure workflow tool versions are pinned and
consistent, and that downloaded yq releases are checksum-verified.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/uncategorized PR auto-labeler could not map title scope to a known area/*; please review size/M This PR changes 30-99 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants