feat(admin): show the deployed commit and build time in the admin #233

Closed
opened 2026-08-29 15:23:03 -05:00 by bermudalamb · 0 comments
Owner

There is currently no way to tell which build a deployed environment is running. A redeploy either took effect or it did not, and nothing on the screen says which.

This is not hypothetical. On 2026-08-29, immediately after #232 merged, docker exec redefined-designs-qa-syn npm run backfill:images failed with tsx: not found. The container was still running the pre-merge image. The only thing that revealed it was npm echoing the old script line — had the change been anywhere other than a package.json script, the container would have looked healthy while running the wrong code.

What it shows

A muted line in the admin header: the short commit and when the image was built.

a5076cc · built 29 Aug 20:14

The commit answers "is this the code I expect". The build time answers "did my redeploy actually rebuild" — a distinct question, and the one that would have caught the case above.

Getting it into the image

A build stage copies .git and reads the SHA with a few lines of node, writing dist/buildInfo.json. No git binary is needed and no apt layer: node:20-bookworm-slim has no git, and installing one for this would be a poor trade. There is no .dockerignore, so .git is already in the build context, and Portainer clones the repository before building, so it is present there too.

Both .git/HEAD shapes are handled — a detached HEAD holds the SHA directly, a ref: line means reading refs/heads/<name> and falling back to packed-refs. Anything missing yields unknown rather than a build failure. A version stamp must never be the thing that stops a deploy.

Where it is served

A new GET /api/admin/version, on its own router behind requireAdminGate, reading the file once at startup.

Deliberately not on /api/config. That endpoint is public — the storefront fetches it — and publishing a commit SHA there tells anyone exactly which code is running, which is free help to someone matching known vulnerabilities against the repository. The request was for the admin side, and the admin side is also the correct side.

Testing

The .git parsing is the only part with branches, so it is pure and unit tested: detached HEAD, ref: form, packed-refs fallback, and everything missing yielding unknown. An integration test covers the endpoint being gated and returning the expected shape. The real proof is building the image and confirming the reported SHA matches git rev-parse --short HEAD.

Out of scope

Telling you the deployment is stale — comparing what is running against what is on main — is a bigger feature needing a source of truth about what should be deployed. This makes the running version visible; noticing it is out of date is still a person's job.

There is currently no way to tell which build a deployed environment is running. A redeploy either took effect or it did not, and nothing on the screen says which. This is not hypothetical. On 2026-08-29, immediately after #232 merged, `docker exec redefined-designs-qa-syn npm run backfill:images` failed with `tsx: not found`. The container was still running the pre-merge image. The only thing that revealed it was npm echoing the old script line — had the change been anywhere other than a `package.json` script, the container would have looked healthy while running the wrong code. ## What it shows A muted line in the admin header: the short commit and when the image was built. ``` a5076cc · built 29 Aug 20:14 ``` The commit answers "is this the code I expect". The build time answers "did my redeploy actually rebuild" — a distinct question, and the one that would have caught the case above. ## Getting it into the image A build stage copies `.git` and reads the SHA with a few lines of node, writing `dist/buildInfo.json`. No `git` binary is needed and no apt layer: `node:20-bookworm-slim` has no git, and installing one for this would be a poor trade. There is no `.dockerignore`, so `.git` is already in the build context, and Portainer clones the repository before building, so it is present there too. Both `.git/HEAD` shapes are handled — a detached HEAD holds the SHA directly, a `ref:` line means reading `refs/heads/<name>` and falling back to `packed-refs`. Anything missing yields `unknown` rather than a build failure. **A version stamp must never be the thing that stops a deploy.** ## Where it is served A new `GET /api/admin/version`, on its own router behind `requireAdminGate`, reading the file once at startup. Deliberately **not** on `/api/config`. That endpoint is public — the storefront fetches it — and publishing a commit SHA there tells anyone exactly which code is running, which is free help to someone matching known vulnerabilities against the repository. The request was for the admin side, and the admin side is also the correct side. ## Testing The `.git` parsing is the only part with branches, so it is pure and unit tested: detached HEAD, `ref:` form, packed-refs fallback, and everything missing yielding `unknown`. An integration test covers the endpoint being gated and returning the expected shape. The real proof is building the image and confirming the reported SHA matches `git rev-parse --short HEAD`. ## Out of scope Telling you the deployment is *stale* — comparing what is running against what is on `main` — is a bigger feature needing a source of truth about what should be deployed. This makes the running version visible; noticing it is out of date is still a person's job.
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: bermudalamb/redefined-designs#233