Skip to content

build: stamp the module version from git in the Docker build - #4496

Open
stevenvegt wants to merge 14 commits into
masterfrom
version-stamping
Open

build: stamp the module version from git in the Docker build#4496
stevenvegt wants to merge 14 commits into
masterfrom
version-stamping

Conversation

@stevenvegt

@stevenvegt stevenvegt commented Sep 9, 2026

Copy link
Copy Markdown
Member

Follow-up to #4490, split out per review feedback there. Stacked on the rename branch so the diff shows only these changes; to be retargeted to master once #4490 merges.

With the module path carrying its major version, go build can stamp the version into the binary's build info from the checked-out tag. Build info is the first thing every image scanner reads, ahead of any ldflags heuristics, so this makes the version visible without scanner-specific tricks. This PR makes the Docker build able to do that and tidies the build files around it.

Commits:

  • The Docker build installs git in the builder stage. golang:alpine does not ship it, and without git there is nothing to stamp from.
  • Build files take the module path from go list -m instead of hardcoding it, so the next major bump does not touch them; make bump-major wraps gomajor plus the .proto rewrite. .dockerignore excludes only untracked files: with tracked files excluded, git status inside the builder saw deletions and stamped the version as +dirty, which Syft and Trivy carried into the package URL.
  • The makefile no longer embeds literal quotes in the commit and branch values.
  • The images workflow fetches full history only for branch pushes: a tag build stamps correctly at depth 1, and pull request builds are not pushed, so only the :master image needs the history back to the nearest tag. Without it an untagged build is stamped v6.0.0-<time>-<rev>, which sorts below every release.
  • Documented hadolint DL3018 ignores on both apk add lines.
  • .dockerignore keeps the tracked .claude/commands directory and excludes only the local parts of .claude. Rule for the future: .dockerignore must never exclude a tracked file, otherwise git status inside the builder reports a deletion and the stamp gets a +dirty suffix. This is what the first local build on master showed.

Trade-offs, stated explicitly:

  • Including .git and the tracked files in the build context means every commit invalidates the COPY . . layer in local Docker builds, so a docs-only commit rebuilds the binary. CI is unaffected: runners start clean and the workflow configures no layer cache. Stamping from git cannot coexist with the old cache behaviour, because .git changes every commit.
  • Branch pushes fetch about 44 MB of history instead of 3 MB, a few seconds per master build.

Verified locally at a throwaway tag: a plain go build, a depth-1 clone and docker build all report github.com/nuts-foundation/nuts-node/v6 v6.2.99 in build info with vcs.modified=false, and Syft and Trivy read that version. zizmor and hadolint report nothing new.

Once this merges, #4486 (interim ldflags approach) should be closed: its -buildvcs=false would block the stamping. Backports of this PR to V6.2 and V5.4 follow after #4487 and #4491.

Rewritten with "gomajor path -version v6".

Refs #4485

Assisted-by: AI
Assisted-by: AI
(cherry picked from commit 35d3bcc)
The ldflags -X keys in the Dockerfile, makefile and binaries workflow
now take the module path from "go list -m" instead of hardcoding it, so
a major version bump only touches go.mod, the imports and the .proto
go_package options. "make bump-major" does all of those.

.dockerignore now excludes only untracked files. Excluding tracked files
made "git status" inside the builder report deletions, which stamped the
version as "+dirty".

Assisted-by: AI
(cherry picked from commit d87b2ba)
Assisted-by: AI
(cherry picked from commit c5f2cdd)
Assisted-by: AI
(cherry picked from commit d0091ac)
Review feedback: how the version reaches the binary (git stamping in the
Docker build, .dockerignore, checkout depth, makefile and workflow
changes) is a separate concern and moves to a follow-up PR. This commit
returns the branch to the rename only: gomajor rewrite, the module path
in the existing ldflags keys, and the .proto go_package options.

Assisted-by: AI
Assisted-by: AI
(cherry picked from commit 35d3bcc)
(cherry picked from commit f5d0584)
The ldflags -X keys in the Dockerfile, makefile and binaries workflow
now take the module path from "go list -m" instead of hardcoding it, so
a major version bump only touches go.mod, the imports and the .proto
go_package options. "make bump-major" does all of those.

.dockerignore now excludes only untracked files. Excluding tracked files
made "git status" inside the builder report deletions, which stamped the
version as "+dirty".

Assisted-by: AI
(cherry picked from commit d87b2ba)
(cherry picked from commit 6d36d6e)
Assisted-by: AI
(cherry picked from commit c5f2cdd)
(cherry picked from commit f2dd153)
Assisted-by: AI
(cherry picked from commit d0091ac)
(cherry picked from commit b68f307)
Assisted-by: AI
(cherry picked from commit d9d1a01)
(cherry picked from commit 335e811)
@qltysh

qltysh Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

1 new issue

Tool Category Rule Count
qlty Structure Function with many returns (count = 9): renderServerOptions 1

master tracks .claude/commands/sync-release-notes.md. Excluding the whole
.claude directory made git inside the builder report it as deleted, so
the stamped version got a "+dirty" suffix. Exclude only the local parts.

Assisted-by: AI
Base automatically changed from module-major-suffix to master September 9, 2026 09:18
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