Derive OCI publish mode from trigger to stop twin-publish race #44

Merged
David merged 1 commit from fix/GOV-15-twin-trigger-publish-mode into main 2026-06-26 18:10:31 +02:00
Owner

What

Ports the GOV-13 twin-trigger publish-mode fix into this repo's OCI build workflow. Part of the GOV-15 per-repo rollout.

The bug

build-oci-image.yml triggers on push to BOTH branches: [main] and tags: [v*], and resolved its tag set from git describe via oci-build/get-tags.nu --joined, which returned [vX.Y.Z, latest] on a tagged commit. A release commit is simultaneously a main push and a v* tag push, so both events fire, both build the same image, and both race to overwrite the mutable :latest tag while colliding on immutable artifacts.

The fix

The publish mode is now derived from the workflow trigger instead of git describe. A tag ref resolves to the release train and publishes only the immutable vX.Y.Z; a push to main resolves to the latest train and publishes only the rolling latest; a workflow_dispatch resolves to dry-run, building locally (--load) and mutating nothing. The two real triggers now emit disjoint tag sets, so the runs never race for the same destination.

oci-build/get-tags.nu is replaced with the canonical --mode version (release / latest / dry-run, with --simulate-tag to exercise the release path from a manual run). The workflow gains a workflow_dispatch trigger with dry_run (default true) and simulate_tag inputs, a resolve step that maps the trigger to a single tag, a dry-run-aware build-and-push step, and a single-tag print step.

Preserved

The matrix (image rus / rus-saas, build_mode standalone / saas), build-args, inline cache strategy, registry auth wiring, and oci-build/Dockerfile path are unchanged. The resolve step runs once per matrix job and produces the same trigger-derived tag, which is correct. A dry-run exports no cache.

Verification

YAML parses, nu-check passes on the helper, all four functional modes return the expected tag (release v9.9.9, latest, dry-run+simulate release v9.9.9, dry-run latest), and both error paths (unknown mode, release with no version) exit non-zero. The pre-commit hook passed (fmt, clippy, 111 tests).

## What Ports the GOV-13 twin-trigger publish-mode fix into this repo's OCI build workflow. Part of the GOV-15 per-repo rollout. ## The bug `build-oci-image.yml` triggers on push to BOTH `branches: [main]` and `tags: [v*]`, and resolved its tag set from `git describe` via `oci-build/get-tags.nu --joined`, which returned `[vX.Y.Z, latest]` on a tagged commit. A release commit is simultaneously a main push and a `v*` tag push, so both events fire, both build the same image, and both race to overwrite the mutable `:latest` tag while colliding on immutable artifacts. ## The fix The publish mode is now derived from the workflow trigger instead of `git describe`. A tag ref resolves to the `release` train and publishes only the immutable `vX.Y.Z`; a push to `main` resolves to the `latest` train and publishes only the rolling `latest`; a `workflow_dispatch` resolves to `dry-run`, building locally (`--load`) and mutating nothing. The two real triggers now emit disjoint tag sets, so the runs never race for the same destination. `oci-build/get-tags.nu` is replaced with the canonical `--mode` version (release / latest / dry-run, with `--simulate-tag` to exercise the release path from a manual run). The workflow gains a `workflow_dispatch` trigger with `dry_run` (default true) and `simulate_tag` inputs, a resolve step that maps the trigger to a single tag, a dry-run-aware build-and-push step, and a single-tag print step. ## Preserved The matrix (`image` rus / rus-saas, `build_mode` standalone / saas), build-args, inline cache strategy, registry auth wiring, and `oci-build/Dockerfile` path are unchanged. The resolve step runs once per matrix job and produces the same trigger-derived tag, which is correct. A dry-run exports no cache. ## Verification YAML parses, `nu-check` passes on the helper, all four functional modes return the expected tag (release v9.9.9, latest, dry-run+simulate release v9.9.9, dry-run latest), and both error paths (unknown mode, release with no version) exit non-zero. The pre-commit hook passed (fmt, clippy, 111 tests).
fix(ci): derive OCI publish mode from trigger to stop twin-publish race
All checks were successful
Check / fmt + clippy + build + tests (pull_request) Successful in 57s
Create release / Create release from merged PR (pull_request) Has been skipped
bfb68908d6
The build-oci-image workflow triggers on push to BOTH main and v* tags and resolved its tag set from `git describe` via `oci-build/get-tags.nu --joined`, which returned `[vX.Y.Z, latest]` on a tagged commit. A release commit is simultaneously a main push and a v* tag push, so both events fire, both build the same image, and both race to overwrite the mutable `:latest` tag (and collide on immutable artifacts).

This ports the GOV-13 fix: the publish mode is now derived from the workflow trigger rather than from `git describe`. A tag ref resolves to the `release` train and publishes only the immutable `vX.Y.Z`; a main push resolves to the `latest` train and publishes only the rolling `latest`; a workflow_dispatch resolves to `dry-run`, building locally and mutating nothing. The two real triggers now write disjoint tag sets, so the runs never race for the same destination.

The matrix (image rus / rus-saas, build_mode standalone / saas), build-args, inline cache, and Dockerfile path are unchanged. The resolve step runs once per matrix job and produces the same trigger-derived tag, which is correct. A workflow_dispatch input gates dry-run, building with --load and exporting no cache.

#GOV-15
#GOV-13
David merged commit 83a2538cf2 into main 2026-06-26 18:10:31 +02:00
David deleted branch fix/GOV-15-twin-trigger-publish-mode 2026-06-26 18:10:32 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
a8n-tools/rus!44
No description provided.