Skip to content

fix(release): stamp the tag being built into version.Version - #206

Open
mateeullahmalik wants to merge 1 commit into
masterfrom
fix/release-version-tag-resolution
Open

fix(release): stamp the tag being built into version.Version#206
mateeullahmalik wants to merge 1 commit into
masterfrom
fix/release-version-tag-resolution

Conversation

@mateeullahmalik

Copy link
Copy Markdown
Contributor

Behavior change

Release binaries stamp the tag they were actually built from into
version.Version. Previously a final release tag sharing a commit with a
prerelease tag could stamp the prerelease string.

v1.20.2 shipped with this bug:

$ lumerad version --long     # release/v1.20.2 artifact, downloaded from GitHub
version: 1.20.2-rc1          <-- wrong
commit:  aafc4a287d2ad78f5be873eb9ee24189fe6302fb   <-- correct

Live testnet reports the same, post-upgrade:

$ curl -s https://lcd.testnet.lumera.io/cosmos/base/tendermint/v1beta1/node_info
application_version.version    = 1.20.2-rc1
application_version.git_commit = aafc4a287d2a

Root cause

v1.20.2 and v1.20.2-rc1 both point at commit aafc4a28. VERSION_TAG
picked the newest tag by creatordate among tags reachable from HEAD:

tag_ref=$(git for-each-ref --merged HEAD --sort=-creatordate ... | head -n1)

For a lightweight tag, creatordate is the COMMIT date, not the tagging
date.
At build time v1.20.2 was still lightweight, so it sorted by the
commit date while the annotated v1.20.2-rc1 sorted by its tagger date:

v1.20.2-rc1   2026-08-07 19:57:40   (annotated -> tagger date)     <-- sorted first
v1.20.2       2026-08-07 19:55:24   (lightweight -> COMMIT date)

The rc1 tag won by 2m16s and its string was stamped onto the final binary.

The existing tag_commit = head_commit guard did not help: it only decides
whether to append a short SHA, and both tags point at the same commit, so it
passed while the wrong name had already been selected.

Reproduced from scratch (annotated rc + lightweight final on one commit):

$ make print-VERSION_TAG        # old logic, building v1.20.2
1.20.2-rc1                      # <-- bug
$ make print-VERSION_TAG        # this PR, same repo, same env
1.20.2

Note the repo state has since changed (v1.20.2 is annotated today), which is
itself the point: the old output depended on tag type and creation order, not
on which tag was being released.

Fix

Resolve VERSION_TAG in priority order:

  1. GITHUB_REF_NAME when the ref is a tag — the tag actually being released,
    authoritative in release CI and immune to any date heuristic.
  2. Tags pointing exactly at HEAD, preferring a final release over
    -rc/-beta/-alpha/-pre/-hotfix, ties broken with sort -V.
  3. Previous behavior: newest reachable tag + short SHA.

VERSION_TAG=... make overrides still win (the ?= is retained).

Verification

Every one of the 43 tags in the repo, old logic vs new, asserting each stamps
its own name:

TAG              OLD           NEW           VERDICT
v1.20.2          1.20.2        1.20.2        ok
v1.20.2-rc1      1.20.2        1.20.2-rc1    OLD-WAS-WRONG -> FIXED
v1.6.2-pre       1.6.2         1.6.2-pre     OLD-WAS-WRONG -> FIXED
... (40 more, all ok)
exit: 0

Both historical collisions (v1.20.2/v1.20.2-rc1, v1.6.2/v1.6.2-pre) are
fixed; no tag regressed. Also checked:

  • RELEASE_VERSION_TAG -> v1.20.2, so the artifact filename is unchanged
  • BUILD_LDFLAGS renders version.Version=1.20.2, commit unchanged
  • building the rc tag still stamps 1.20.2-rc1
  • VERSION_TAG=9.9.9 make still yields 9.9.9
  • on a branch with no tag at HEAD, the SHA-suffixed fallback still applies

Risks

Low. Build-time labelling only — no Go source, no state machine, no consensus
path, no upgrade handler, no store key touched. The binary's behavior is
identical; only the string in version --long and node_info changes.

Worst case is a mislabelled build, which is the status quo being fixed. The
?= override is preserved, so any pinned invocation keeps working.

Rollback

Revert this commit. No state implications, no coordination needed.

Migration

None.

Observability

This is the observability fix: version --long, /node_info, and
/abci_info become trustworthy for rollout audits. Until this lands, operators
verifying a fleet must compare git_commit, not versionv1.20.2 in the
wild reports 1.20.2-rc1.

Note this does not retroactively fix the published v1.20.2 artifact. That
binary is correct code (commit aafc4a28) with a wrong label. Options are to
leave it and communicate, or cut a v1.20.3 rebuild once this merges.

The v1.20.2 release artifact reports `version: 1.20.2-rc1` while carrying the
correct commit aafc4a2. Both v1.20.2 and v1.20.2-rc1 point at that same commit.

VERSION_TAG picked the newest tag by `creatordate` among tags reachable from
HEAD. For a LIGHTWEIGHT tag `creatordate` is the COMMIT date, not the tagging
date. At build time v1.20.2 was still lightweight, so it reported the commit
date (2026-08-07 19:55:24) while the annotated v1.20.2-rc1 reported its tagger
date (2026-08-07 19:57:40) and sorted first. The release build therefore stamped
the rc1 string onto the final binary.

Resolution now prefers, in order: the tag actually being pushed
(GITHUB_REF_NAME on a tag ref), then a non-prerelease tag pointing at HEAD,
then the previous newest-reachable-tag fallback with a short SHA suffix.

Binary-only labelling change: no state machine, consensus or upgrade-handler
behavior is touched. Verified against all 43 existing tags -- each now stamps
its own name, and prerelease tags still stamp their prerelease string.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant