Skip to content

fix(build): honour PUSH and LOAD from the environment and in image-talos - #4654

Merged
Aleksei Sviridkin (lexfrei) merged 4 commits into
mainfrom
fix/build-load-push-env
Oct 5, 2026
Merged

Aleksei Sviridkin (lexfrei) merged 4 commits into
mainfrom
fix/build-load-push-env

Conversation

@lexfrei

@lexfrei Aleksei Sviridkin (lexfrei) commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

What this PR does

A local build that asks to load images into docker no longer pushes them. hack/common-envs.mk set PUSH and LOAD with plain :=, and a makefile assignment beats the environment, so LOAD=1 PUSH=0 make image quietly pushed a multi-arch build. Both now take the environment value, and an empty one falls back to the default. I also made PUSH default to 0 when LOAD=1, so LOAD=1 alone only loads. Before this, make image LOAD=1 pushed and loaded at once. An explicit PUSH from the environment or the command line still wins, and OCI_EXPORT_DIR still forces both off. Every buildx target gets the values through BUILDX_ARGS, so the fix lives in that one file.

The Talos installer was the one image that ignored PUSH. It is published with skopeo, not buildx, so it never saw --push=$(PUSH). Its registry copies now run only when PUSH=1.

A build that pushes nothing no longer writes PUSHED_TAGS_LOG. That log tells the multi-arch stitch which tags to move, so it must hold only tags that were really pushed.

The cache helper lost an argument nobody used. No caller passes the second argument of cache-args, and an explicit tag there would bypass CACHE_TAG, so the amd64 and arm64 builds of that image would share one cache ref.

CI sets neither PUSH nor LOAD, so CI builds do the same thing as before. Each fix has a make --dry-run test in hack/common-envs_test.bats.

Closes #4499

Closes #4504

Closes #4551

Screenshots

Not a UI change.

Downstream repositories

The ccp skills pass PUSH=1 explicitly, which still works. The website docs do not mention PUSH, LOAD or cache-args.

Release note

fix(build): `LOAD` and `PUSH` set in the environment are now honoured, `LOAD=1` no longer pushes unless `PUSH=1` is also set, and the Talos installer is no longer published when `PUSH=0`.

@github-actions github-actions Bot added size/M This PR changes 30-99 lines, ignoring generated files area/build Issues or PRs related to image build infrastructure, multi-arch support kind/bug Categorizes issue or PR as related to a bug labels Oct 1, 2026
@coderabbitai

coderabbitai Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

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

Important

Review skipped

Review was skipped as selected files did not have any reviewable changes.

⚙️ Run configuration

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

Review profile: CHILL

Plan: Advanced

Run ID: f82d133e-3c9e-44aa-8dd3-87c530f60dfb

📥 Commits

Reviewing files that changed from the base of the PR and between 236640f and c603327.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 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: 8c02e77f-b3f8-4cca-8127-c36b70fad150

📥 Commits

Reviewing files that changed from the base of the PR and between 889bb79 and 236640f.

📒 Files selected for processing (4)
  • hack/common-envs.mk
  • hack/common-envs_test.bats
  • hack/stitch-multiarch.sh
  • packages/core/talos/Makefile

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

Build settings now use nonempty environment or command-line values, with LOAD and PUSH defaults based on local build mode. Pushed-tag logging and Talos registry copies require PUSH=1. Cache reads and writes use CACHE_TAG.

Changes

Build controls

Layer / File(s) Summary
Build mode and tag logging
hack/common-envs.mk, hack/common-envs_test.bats, hack/stitch-multiarch.sh
LOAD and PUSH use the updated defaults. Pushed-tag logging requires PUSH=1 and no OCI export. Tests cover these conditions, and the documentation clarifies which tags the log identifies.
Cache reference selection
hack/common-envs.mk, hack/common-envs_test.bats
cache-args no longer accepts a per-call cache tag. Cache reads and writes use CACHE_TAG, as covered by the updated test.
Talos registry publishing
packages/core/talos/Makefile, hack/common-envs_test.bats
Talos registry copies of the image, versioned, and latest tags require PUSH=1. The dry-run test checks that PUSH=0 leaves registry pushes disabled.

Priority: ➖ Normal

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

Change: Bug fix · Severity of issue fixed: Medium

Merge Risk: ⚪ Minimal · up to 23664

The changes align image publishing with the requested build mode without an established regression. Mergeable subject to normal checks, including the make dry-run tests.

Security Architecture Review

Security architecture risk: 🔵 Low · up to 23664

The changes reduce unintended image publication and do not demonstrate expanded credentials or privileges. Residual risk lies in existing independent cache writes and partially completed registry publication; their behavior outside the inspected release path remains unverified.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The affected write scope is image and cache references under the caller-configured REGISTRY and CACHE_REGISTRY, bounded by the credentials available to buildx and skopeo. PUSH=0 suppresses the inspected image-publication paths but is not a blanket registry-write prohibition because WRITE_CACHE is independently controlled. Effective credential scope was not established.

Trust Boundaries and Controls

  • observed — The pushed-tag log is publication-authority input to stitching, not proof that each tag was successfully published. Logging during dry-runs or before a failed build already existed in the base. This PR narrows logging to PUSH=1 rather than introducing that provenance limitation; arbitrary shared-log callers remain outside the verified scope.

Resilience and Maintainability Implications

  • observed — The inspected release workflow writes the tag log beneath runner.temp, uploads it with the stamped tree after the build steps, and requires successful prerequisite build jobs before release preparation. These unchanged controls contain the normal failed-build path rather than allowing its log alone to authorize stitching.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR satisfies the coding requirements in [#4499], [#4504], and [#4551]. hack/common-envs.mk preserves non-empty environment and command-line LOAD and PUSH values, derives PUSH=0 for `LOAD=1…
Out of Scope Changes check ✅ Passed The changes stay within the linked build objectives. The PUSHED_TAGS_LOG guard and related stitch-multiarch.sh documentation prevent non-pushed or locally loaded builds from supplying tags to the …
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 2…
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main changes: honoring environment-provided PUSH and LOAD values and applying PUSH gating to image-talos.
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


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.

No caller passes the second argument any more, and an explicit tag
would bypass CACHE_TAG, so the amd64 and arm64 legs of such an image
would write the same mode=max cache ref and evict each other's layers.

Assisted-by: LLM
Signed-off-by: Aleksei Sviridkin <[email protected]>
A plain := assignment beats an environment variable, so
`LOAD=1 PUSH=0 make image` pushed a multi-arch build instead of
loading one. An empty value from the environment falls back to the
default rather than reaching buildx as `--push=`. PUSH now also
defaults to 0 under LOAD=1, so a local load never publishes unless
PUSH=1 is asked for. The OCI_EXPORT_DIR block still overrides an
environment PUSH or LOAD.

Assisted-by: LLM
Signed-off-by: Aleksei Sviridkin <[email protected]>
image-talos publishes with skopeo instead of buildx, so it never saw
--push=$(PUSH) and a local PUSH=0 build still overwrote talos tags in
REGISTRY.

Assisted-by: LLM
Signed-off-by: Aleksei Sviridkin <[email protected]>
PUSHED_TAGS_LOG fed every tag to hack/stitch-multiarch.sh whether or
not the build pushed it, so a PUSH=0 build, and now a plain LOAD=1
build, handed the stitch tags that were never published.

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

@IvanHunters IvanHunters left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM

Verified hermetically with make -n and the bats suite, no cluster.

This makes the build honour PUSH/LOAD from the environment and the command line, which it did not before. On the merge base both were pinned unconditionally (PUSH := 1, LOAD := 0), so an environment PUSH=0 was silently overridden by the makefile and the build pushed anyway. The default survives the change: with nothing set the build still resolves --push=1 --load=0, an empty env value falls back to that default, LOAD=1 derives PUSH=0 while an explicit PUSH=1 still wins, and OCI_EXPORT_DIR keeps forcing both off.

image-talos now gates each skopeo copy docker:// on [ "$PUSH" = "1" ], so it lines up with the buildx images: pushes under the default PUSH=1, publishes nothing with PUSH=0. Gating PUSHED_TAGS_LOG on PUSH=1 is right for the same reason, the stitch should only move tags a build actually pushed.

I also checked the blast radius. No workflow sets PUSH or LOAD in the environment, and CI invokes make build / make -C … image relying on the unchanged default, so the CI push path is untouched. Dropping the per-call cache tag from cache-args is safe dead-code removal: no Makefile in the tree passes a second argument, at head or at the merge base.

All 14 cases in hack/common-envs_test.bats pass, and still pass after merging current main into the head. The rewritten CACHE_TAG test holds the new contract (CACHE_TAG wins, no per-call bypass) and would redden if the second argument came back.

[NIT] LOAD=1 make -C packages/core/talos image-talos without OCI_EXPORT_DIR now builds the installer index and then discards it without pushing or loading, because the skopeo path has no docker-store load. That fits the "don't touch the registry" intent, and a multi-arch index can't be loaded locally anyway. CI never calls image-talos with LOAD=1. Flagging it only in case a local build flow expected a talos image to land there.

Aleksei Sviridkin (lexfrei) added a commit that referenced this pull request Oct 5, 2026
…#4663)

## What this PR does

A local build with `PUSH=0` no longer publishes the packages artifact.
Before this change, `make image-packages` in `packages/core/installer`
ran `flux push artifact` no matter what `PUSH` was set to, and then
wrote the pushed digest into `values.yaml`. The `chart` target in the
same Makefile already respects `PUSH`.

With `PUSH` set to anything other than 1, the target now skips both the
push and the digest stamp. It prints one line saying so and leaves the
committed `platformSourceUrl` and `platformSourceRef` as they are. It
still writes `packages/core/platform/.build-revision`, which is
gitignored.

I chose to skip the stamp instead of computing a local digest, because
every reader of that value needs a digest that exists in the registry.
The chart passes `platformSourceRef` to the operator as
`--platform-source-ref`, and Flux then pulls
`cozystack-packages@<digest>` from the registry. The release scripts
`verify-promoted-packages.sh`, `promote-packages-artifact.sh`,
`stitch-multiarch.sh` and `nightly-mirror.sh` also treat it as a
registry digest. A digest of an artifact that was never pushed points at
nothing. On main an unpushed run would not even get that far, since the
recipe dies at `test -n "$DIGEST"`.

The gate is a make-level `ifeq ($(PUSH),1)`, so it reads whatever `PUSH`
ends up as after `hack/common-envs.mk`. On main that means `PUSH=0` on
the command line. I also applied the `common-envs.mk` change from #4654
locally, which takes `PUSH` from the environment and makes `LOAD=1`
default it to 0. With that applied, a dry run shows no push and no stamp
for `PUSH=0` in the environment, for `LOAD=1`, and for `PUSH=0` on the
command line, while `LOAD=1 PUSH=1` and an empty `PUSH` still push.

CI is not affected, because no workflow sets `PUSH` or `LOAD` and `PUSH`
stays at 1. I dry-ran the three CI invocations of this Makefile before
and after the change, on main and again with #4654 applied:

- `tags.yaml`, release stitch step: `make -C packages/core/installer
image-packages chart` with `REGISTRY`, a release tag as `IMAGE_TAG`, and
`PUSHED_TAGS_LOG`
- `pull-requests.yaml`, installer step of a same-repo PR: `make -C
packages/core/installer image` with a `pr-N-sha` tag,
`PLATFORM=linux/amd64`, `BUILDER`, and an empty `OCI_EXPORT_DIR`
- `build-main.yaml` and `build-release.yaml`: `make build`, which runs
the installer `image` target with defaults

```text
$ diff --recursive before/ after/     # tags.txt pr.txt build.txt
$ echo $?
0
```

There is one side effect. `OCI_EXPORT_DIR` forces `PUSH := 0`, so
running `image-packages` with it set no longer pushes, where before it
would have tried an anonymous push. No CI path does that. The fork PR
build already runs only `pre-checks image-operator` for the installer,
and the `make -n ... image OCI_EXPORT_DIR=/oci` scan in `e2e-fork.yaml`
greps only the `.oci.tar` names, which this change does not touch.

The new test dry-runs the target in both modes. With `PUSH=0` there must
be no `flux push artifact` and no `platformSourceRef` stamp; with `PUSH`
at its default, both must be present. The first test fails on main. I
mutated the guard three ways, and each time only the matching test went
red:

- condition forced true: the `PUSH=0` test fails
- compared against 2: the default-path test fails
- `endif` moved up so only the push is gated: the `PUSH=0` test fails on
the stamp check

One limitation is left as a follow-up. The test's `env -u PUSH -u LOAD`
only isolates it once #4654 lands, because on main a file assignment
wins over the environment anyway. It does not cover `PUSH=0` coming in
through `MAKEFLAGS`, so `make bats-unit-tests PUSH=0` would fail the
default-path test here and the ordering check in
`hack/stitch-multiarch_test.bats`. Nothing runs the suite that way
today. If that changes, passing an explicit `PUSH=1` on the default-path
`make` lines, or unsetting `MAKEFLAGS` the way
`hack/bats-unit-keep-going.bats` does, would fix it.

### Screenshots

Not a UI change.

### 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 website's `development.md` tells developers to run `make
image-packages` with `REGISTRY` set to their own registry. That is the
default `PUSH=1` path, and it works as before. Neither the website nor
ccp mentions `PUSH=0` for this target.

Closes #4656

### Release note

```release-note
fix(installer): `make image-packages` no longer pushes the cozystack-packages artifact or stamps its digest into values.yaml when PUSH=0.
```


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

## Summary by CodeRabbit

* **New Features**
* You can run `image-packages` with `PUSH=0` to skip publishing the
artifact and keep the committed platform source reference unchanged.
* When pushing is enabled, the command publishes the artifact and
updates the platform source URL and digest-based reference.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
@lexfrei
Aleksei Sviridkin (lexfrei) merged commit 2ddd55c into main Oct 5, 2026
100 of 101 checks passed
@lexfrei
Aleksei Sviridkin (lexfrei) deleted the fix/build-load-push-env branch October 5, 2026 11:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/build Issues or PRs related to image build infrastructure, multi-arch support kind/bug Categorizes issue or PR as related to a bug size/M This PR changes 30-99 lines, ignoring generated files

Projects

None yet

2 participants