fix(oci): derive publish mode from trigger to end twin-publish race (GOV-15) #457

Merged
David merged 2 commits from fix/GOV-15-twin-trigger-publish-mode into main 2026-06-26 18:21:14 +02:00
Owner

Ports the GOV-13 twin-trigger publish-mode fix into this repo's OCI build workflow as part of the GOV-15 rollout. A worked reference is auto-buyer (NiceGuyIT) PR #78.

The build-oci-image.yml workflow triggers on push to both branches: [main] and tags: [v*], and resolved its publish tags from git describe via ci-build/get-tags.nu --joined, which returns [vX.Y.Z, latest] on a tagged commit. Because a release commit is simultaneously a push to main and the v* tag push, both events fire, both build the same image, and both race to overwrite the mutable :latest tag (and 409 on immutable generic-package artifacts). The two runs resolved the identical tag set and wrote the same destinations.

The fix derives the publish MODE from the trigger rather than from git describe, so the two runs publish DISJOINT tags: the tag-push run publishes only vX.Y.Z (release train), the main-push run publishes only latest (latest train), and they never collide. The helper ci-build/get-tags.nu is replaced with the canonical --mode release|latest|dry-run version that returns a single { mode, train, tag, describe } record. A new workflow_dispatch trigger adds a dry-run path that builds and prints every registry action without pushing and without writing the build cache.

Repo-specific wiring is preserved unchanged: the lets-chat image name, the a8n-tools private org registry auth, the LC-214 build-arg provenance injection, the Dockerfile.web path, and the GOV-20 type=gha build cache plus its Actions-runtime export step. --cache-to now runs only on a real publish so a dry-run mutates neither the registry nor the cache.

Verification (all PASS): the workflow YAML parses, nu-check passes on the helper, the four functional modes resolve the correct tag (release -> v9.9.9, latest -> latest, dry-run+simulate -> release/v9.9.9, dry-run -> latest/latest), and both error paths (unknown mode, release with no version) exit non-zero.

Ports the GOV-13 twin-trigger publish-mode fix into this repo's OCI build workflow as part of the GOV-15 rollout. A worked reference is auto-buyer (NiceGuyIT) PR #78. The `build-oci-image.yml` workflow triggers on push to both `branches: [main]` and `tags: [v*]`, and resolved its publish tags from `git describe` via `ci-build/get-tags.nu --joined`, which returns `[vX.Y.Z, latest]` on a tagged commit. Because a release commit is simultaneously a push to main and the `v*` tag push, both events fire, both build the same image, and both race to overwrite the mutable `:latest` tag (and 409 on immutable generic-package artifacts). The two runs resolved the identical tag set and wrote the same destinations. The fix derives the publish MODE from the trigger rather than from `git describe`, so the two runs publish DISJOINT tags: the tag-push run publishes only `vX.Y.Z` (release train), the main-push run publishes only `latest` (latest train), and they never collide. The helper `ci-build/get-tags.nu` is replaced with the canonical `--mode release|latest|dry-run` version that returns a single `{ mode, train, tag, describe }` record. A new `workflow_dispatch` trigger adds a dry-run path that builds and prints every registry action without pushing and without writing the build cache. Repo-specific wiring is preserved unchanged: the `lets-chat` image name, the `a8n-tools` private org registry auth, the LC-214 build-arg provenance injection, the `Dockerfile.web` path, and the GOV-20 `type=gha` build cache plus its Actions-runtime export step. `--cache-to` now runs only on a real publish so a dry-run mutates neither the registry nor the cache. Verification (all PASS): the workflow YAML parses, `nu-check` passes on the helper, the four functional modes resolve the correct tag (release -> v9.9.9, latest -> latest, dry-run+simulate -> release/v9.9.9, dry-run -> latest/latest), and both error paths (unknown mode, release with no version) exit non-zero.
fix(oci): derive publish mode from trigger to end twin-publish race
Some checks failed
check-secrets / Nosey parker (push) Successful in 5s
check-secrets / TruffleHog (push) Successful in 5s
check-secrets / Kingfisher (push) Failing after 15s
check-secrets / Nosey parker (pull_request) Successful in 4s
check-secrets / Kingfisher (pull_request) Failing after 5s
check-secrets / TruffleHog (pull_request) Successful in 6s
Check / clippy + fmt + tests (pull_request) Successful in 4m14s
e0344975db
The OCI build workflow triggers on push to both `branches: [main]` and `tags: [v*]`, and resolved its tag set from `git describe` via `ci-build/get-tags.nu --joined`, which returns `[vX.Y.Z, latest]` on a tagged commit. A release commit is simultaneously a push to main and a `v*` tag push, so both events fire, both build the same image, and both race to overwrite the mutable `:latest` tag (and 409 on immutable artifacts).

Fix: derive the publish MODE from the trigger, not from `git describe`, so the two runs publish DISJOINT tags. The helper is rewritten to take `--mode release|latest|dry-run` and return a single `{ mode, train, tag, describe }` record; the tag-push run publishes only `vX.Y.Z`, the main-push run publishes only `latest`, and they never write the same destination. A `workflow_dispatch` trigger adds a dry-run path that builds and prints without mutating the registry (and without writing the gha buildcache). The GOV-20 `type=gha` build cache and the Actions-runtime export step are preserved; `--cache-to` now only runs on a real publish.

#GOV-15
#GOV-13
Merge branch 'main' into fix/GOV-15-twin-trigger-publish-mode
Some checks failed
check-secrets / Kingfisher (pull_request) Failing after 4s
check-secrets / Nosey parker (pull_request) Successful in 4s
check-secrets / Kingfisher (push) Failing after 5s
check-secrets / TruffleHog (pull_request) Successful in 6s
check-secrets / Nosey parker (push) Successful in 5s
check-secrets / TruffleHog (push) Successful in 5s
Check / clippy + fmt + tests (pull_request) Successful in 2m44s
Create release / Create release from merged PR (pull_request) Has been skipped
e9aab5d55b
David merged commit 57f029e7cf into main 2026-06-26 18:21:14 +02:00
David deleted branch fix/GOV-15-twin-trigger-publish-mode 2026-06-26 18:21:14 +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
psa-systems/lets-chat!457
No description provided.