fix(docker): bake build-time git SHA into the image so hermes dump reports it#33655
Merged
Conversation
`hermes dump` and the startup banner both call `git rev-parse HEAD` to
report the running commit, but `.dockerignore` line 2 excludes `.git` —
so inside the published image `hermes dump` shows
`version: ... [(unknown)]` and the banner drops its `· upstream <sha>`
suffix entirely. That makes support triage from container bug reports
impossible: we can't tell which commit the user is actually running.
Fix: thread the build-time SHA through as a Docker build-arg, write it
to `/opt/hermes/.hermes_build_sha` in the image, and have a new
`hermes_cli/build_info.get_build_sha()` read it as a fallback after the
existing live-git lookup fails. Output format is unchanged in both
callsites — same 8-char short SHA whether resolved live or baked.
Wiring:
- Dockerfile: `ARG HERMES_GIT_SHA=` + write-file step after the source
copy. Empty/missing arg → no file written → callers fall through to
live git (so local `docker build` without --build-arg is unchanged).
- docker-publish.yml: passes `HERMES_GIT_SHA=${{ github.sha }}` on all
four build-push-action steps (amd64/arm64, smoke-test + final push).
- dump.py:_get_git_commit() / banner.py:get_git_banner_state(): try
live git first, fall back to baked SHA, then to legacy `(unknown)`
/ None. Banner returns `upstream == local, ahead=0` because a built
image is by definition pinned to one commit.
Coverage:
- Unit tests cover build_info (file present/absent/empty/error,
truncation, whitespace), dump (live-git wins, both fallbacks,
identical output-format regression guard), and banner (no-repo +
baked, no-repo + no-sha, shallow-clone fallback).
- tests/docker/test_dump_build_sha.py is an integration regression
guard that runs against the real image, reads
`/opt/hermes/.hermes_build_sha`, and asserts `hermes dump` surfaces
its content (or stays at `(unknown)` if no file).
- Verified end-to-end: `docker build --build-arg HERMES_GIT_SHA=abc...`
→ `docker run ... dump` reports `[abc12345]`; without the build-arg
it reports `[(unknown)]` as before.
Contributor
🔎 Lint report:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Users running
hermes dumpinside the Docker container see:The startup banner has the same issue — it drops its
· upstream <sha>suffix entirely inside the container. Root cause:.dockerignoreline 2 excludes.git, sogit rev-parse HEADalways fails inside the image. That makes support triage from container bug reports impossible — we can't tell which commit the user is actually running.Fix
Thread the build-time commit SHA through as a Docker build-arg, write it to
/opt/hermes/.hermes_build_shain the image, and have a newhermes_cli/build_info.get_build_sha()helper read it as a fallback after the existing live-git lookup fails.Output format is identical between live-git and baked-SHA paths — same 8-char short SHA whether resolved live or baked. No special-casing required in support tooling that parses
hermes dump.After the fix
CI-built images:
Source installs and local
docker buildwithout--build-argare unchanged: the helper returnsNonewhen the file is absent, and callers fall through to livegit rev-parse.Changes
DockerfileARG HERMES_GIT_SHA=+ conditional file write after the source copy. Empty/missing arg → no file → callers fall back to live git..github/workflows/docker-publish.ymlHERMES_GIT_SHA=${{ github.sha }}on all fourbuild-push-actionsteps (amd64/arm64 × smoke-test/push).hermes_cli/build_info.py(new)Noneon any IO error.hermes_cli/dump.py_get_git_commit()tries live git, then baked SHA, then(unknown).hermes_cli/banner.pyget_git_banner_state()falls back to baked SHA as{upstream==local, ahead=0}— a built image is pinned to one commit by definition.Test coverage
Unit (19 new tests):
tests/hermes_cli/test_build_info.py— file present/absent/empty/whitespace/error, truncation behaviortests/hermes_cli/test_dump_git_commit.py— live-git wins; both fallback paths; legacy(unknown)preserved; identical-output-format regression guard (per request to keep dump output unchanged)tests/hermes_cli/test_banner_git_state.py(extended) — no-repo + baked SHA, no-repo + no-SHA, shallow-clone fallbackIntegration:
tests/docker/test_dump_build_sha.py— runs against the real built image, reads/opt/hermes/.hermes_build_sha, assertshermes dumpsurfaces it (or stays at(unknown)if no build-arg was passed)Verified end-to-end locally:
docker build --build-arg HERMES_GIT_SHA=abc1234567890abc1234567890abc1234567890a .→docker run ... dumpreports[abc12345]✅docker build .(no arg) → reports[(unknown)](unchanged from main) ✅tests/hermes_cli/suite: 5576 tests pass, 0 failureshadolint DockerfilecleanLane
Pure area/docker — Dockerfile, docker workflow, and the tiny
build_info.pyhelper that reads a file baked at image build time. No changes to run_agent.py, model_tools.py, gateway, or any runtime code path Teknium owns.