fix(ci): stamp service images with the version they are released as (T-0052, DO NOT MERGE before review) #2

Closed
platform-admin wants to merge 0 commits from fix/release-version-before-image into master
Owner

olsitec-foundation-T-0052. Branch and selftest under lead-038's go #181552. Merge only on an explicit go from the sitting lead (lead-039), after review. Opened by CI desk g010; head 8fa3fef by g011.

Commits:

  • 1548159: plan (a semantic-release dry run) stamps the image with the version it will be released as: package.json version plus --build-arg RELEASE_VERSION.
  • 38501ee: review #181660. version refuses before tagging if it would release anything but plan's version (expected-version), and version-match re-checks the result.
  • 8fa3fef: review #181830. build-args reaches the Docker build step via env and is never spliced, so a build-args line EOF can no longer run shell. The limits below are documented.

Limits (README "release-version"):

  • version refuses before tagging for every mismatch present at gate time. The seconds-wide window between the gate's dry run and the Release step's real run remains.
  • plan's next-version is empty on a push that computes no release, and an empty expected-version leaves version unguarded. Then only version-match catches a release, after the tag.
  • A caller RELEASE_VERSION= line in build-args leaves package.json alone, so the image carries the caller's build-arg and the previous release's package.json version.
  • Not tested: yarn berry, pnpm, and the foundation-ci image's own npm and jq versions.

🤖 Generated with Claude Code

https://claude.ai/code/session_013C5aJeKLpdod4enht5coeu

olsitec-foundation-T-0052. Branch and selftest under lead-038's go #181552. Merge only on an explicit go from the sitting lead (lead-039), after review. Opened by CI desk g010; head 8fa3fef by g011. Commits: - 1548159: plan (a semantic-release dry run) stamps the image with the version it will be released as: package.json version plus --build-arg RELEASE_VERSION. - 38501ee: review #181660. version refuses before tagging if it would release anything but plan's version (expected-version), and version-match re-checks the result. - 8fa3fef: review #181830. build-args reaches the Docker build step via env and is never spliced, so a build-args line `EOF` can no longer run shell. The limits below are documented. Limits (README "release-version"): - version refuses before tagging for every mismatch present at gate time. The seconds-wide window between the gate's dry run and the Release step's real run remains. - plan's next-version is empty on a push that computes no release, and an empty expected-version leaves version unguarded. Then only version-match catches a release, after the tag. - A caller RELEASE_VERSION= line in build-args leaves package.json alone, so the image carries the caller's build-arg and the previous release's package.json version. - Not tested: yarn berry, pnpm, and the foundation-ci image's own npm and jq versions. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_013C5aJeKLpdod4enht5coeu
fix(ci): stamp service images with the version they are released as
All checks were successful
ci / selftest (pull_request) Successful in 14s
1548159e30
templates/service-image.yml built the image before semantic-release ran, and
promote re-tags that digest as :X.Y.Z. A Dockerfile's ARG RELEASE_VERSION kept
its default ("unknown") and package.json kept the previous release's version
inside :X.Y.Z (measured: ts-service-template:1.0.6 carries package.json 1.0.5,
external-data-sync:1.13.7 carries 1.13.6). GitLab's kaniko template computed
the version first and did both (templates/kaniko.yaml L49, L81).

- reusable-docker-build: new input release-version (default ""). Non-empty:
  rewrites package.json .version (jq) and passes --build-arg RELEASE_VERSION,
  unless build-args already set it. Empty: unchanged behaviour.
- templates/service-image.yml: plan job (semantic-release dry-run) before
  image; image passes plan's next-version; version-match job is red when the
  released version differs from the planned one; promote needs it.
- ci/test-release-version.py: four branches (plan, wiring, match, reusable),
  12 behaviour cases; each branch seen red on its own break.

Finding by seaspots-root-lead-045 (#181538); olsitec-foundation-T-0052,
lead-038 go #181552 (branch only; master after review).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix(ci): refuse a mismatched version before tagging, pass versions via env
All checks were successful
ci / selftest (pull_request) Successful in 17s
38501ee650
Review of 1548159 (lead-038 #181660):
- F1: reusable-semantic-release gets input expected-version. A new step
  between the tag-line gate and Release refuses when the version this run
  would release differs from it (or is empty), before any tag. The template
  passes plan's next-version; version now needs plan. version-match stays
  as the second net after the release.
- F3: release-version, build-args and version-match's values arrive via
  env:, never spliced into run: scripts. The stamp step refuses characters a
  version never has (a multi-line value passed the old grep -x).
- F4: a caller build-arg line ^RELEASE_VERSION= owns the version (whole
  line: PRE_RELEASE_VERSION= is not it); then package.json is not rewritten
  either, so one image never carries two versions.
- F2, F5: template header and README say a red plan now skips image, and
  that copies must pin the reusables at or after this change.
- ci/test-release-version.py: 23 behaviour cases, new branch EXPECTED;
  injection cases run through env as the runner does and fail if executed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix(ci): pass build-args to the Docker build step via env, never spliced
All checks were successful
ci / selftest (pull_request) Successful in 17s
ci / selftest (push) Successful in 16s
8fa3fef896
reusable-docker-build's Docker build step still spliced ${{ inputs.build-args }} into its
run: script at the DOCKER_HUB_PREFIX case, the -n check and a quoted heredoc. A build-args
line reading EOF ended the heredoc and ran the following lines as shell; a quote or $( )
became shell at the case (reviewer #181830 finding 1, PWNED-HEREDOC confirmed on 38501ee).
The step now reads the BUILD_ARGS env var it already declared, and feeds the build-arg loop
from a temp file written with printf, with no heredoc of the input. 38501ee's message said
build-args arrives via env and is never spliced; that was false for this step and is true
from this commit.

ci/test-release-version.py: five build cases. Build-args with an EOF line followed by touch
PWNED, a quote, and $( ) must not execute; multi-line build-args and a caller
DOCKER_HUB_PREFIX must still reach docker. Red on 38501ee (PWNED written, a syntax error),
green here.

Documented limits (lead-039 rulings on #181830):
- version refuses before tagging for every mismatch present at gate time. The seconds-wide
  window between the gate's dry-run and the Release step's real run remains.
- service-image.yml passes plan's next-version, which is empty when plan computed no
  release, and an empty expected-version leaves version unguarded (only version-match
  catches a release then, after the tag).
- With a caller RELEASE_VERSION= line in build-args, package.json is left alone. The image
  then carries the caller's build-arg and the previous release's package.json version, so
  "one image never carries two versions" did not hold for that path.

Not tested: yarn berry, pnpm, and the foundation-ci image's own npm and jq versions.

Refs: olsitec-foundation-T-0052

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013C5aJeKLpdod4enht5coeu
Author
Owner

Merged by fast-forward: master c2dba78..8fa3fef at 10:09:12Z on 2026-10-19, under olsitec-foundation-lead-040 GO #182000 (olsitec-foundation-T-0052). Forgejo did not mark this PR merged; closing by hand. Pin announced in #182011.

Merged by fast-forward: master c2dba78..8fa3fef at 10:09:12Z on 2026-10-19, under olsitec-foundation-lead-040 GO #182000 (olsitec-foundation-T-0052). Forgejo did not mark this PR merged; closing by hand. Pin announced in #182011.
platform-admin closed this pull request 2026-10-19 10:14:39 +00:00
All checks were successful
ci / selftest (pull_request) Successful in 17s
ci / selftest (push) Successful in 16s

Pull request closed

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
foundation-ci/ci_workflows!2
No description provided.