From 521271ebb768906115e9d3fb2830effe99b8ced4 Mon Sep 17 00:00:00 2001 From: Devin Foley Date: Fri, 31 Jul 2026 13:01:52 -0700 Subject: [PATCH] build: bake the build commit into published images (#10566) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Instances commonly run from published container images, and operators need to observe which build a container actually serves > - `/api/health` now reports the running build commit, and server-info already falls back to `PAPERCLIP_BUILD_COMMIT` when git is unavailable > - But published images carry no `.git` and never received `PAPERCLIP_BUILD_COMMIT`, so containers report `commit: null` — verified live against a current image > - That leaves the new deployment-verification field inert exactly where it matters most: containerized deploys > - This pull request bakes the exact build commit into both image variants at build time, mirroring how `PAPERCLIP_BUILD_VERSION` is already stamped > - The benefit is that containers report their true commit on `/api/health`, so deploy tooling can verify a rollout actually shipped ## Linked Issues or Issue Description Companion to #10563 (which exposed the `commit` field on `/api/health`). Inline description following the bug report template: **What happened?** A container from a published image responds to `GET /api/health` with `"commit": null`. The image has no `.git` directory and the `PAPERCLIP_BUILD_COMMIT` fallback that `server-info` supports is never provided at build time, so git metadata resolves as unavailable. **Expected behavior** A container reports the commit it was built from, the same way it already reports its build version via the baked `PAPERCLIP_BUILD_VERSION`. **Steps to reproduce** Run any published image (e.g. `ghcr.io/paperclipai/paperclip:sha-c4f6264-cloud`) and `curl /api/health` — `commit` is `null` even though the build commit is known at image-build time. **Paperclip version or commit** `sha-c4f6264-cloud` (first image containing #10563). ## What Changed - `Dockerfile`: new `PAPERCLIP_BUILD_COMMIT` build arg, exported as an ENV in the production stage (the `cloud` stage inherits it), directly parallel to `PAPERCLIP_BUILD_VERSION`. Empty for local `docker build`, which keeps the normal fallbacks. - `.github/workflows/docker.yml`: both build jobs pass `PAPERCLIP_BUILD_COMMIT=${{ github.sha }}`. ## Verification - Reviewed the plumbing end-to-end: `build-commit.ts` reads `PAPERCLIP_BUILD_COMMIT` (validated as a full SHA), `server-info.ts` `readGitInfo` falls back to it when the git CLI fails, producing `available: true, fullSha` — which `/api/health` surfaces as `commit`. - Verified live that a current published image reports `commit: null`; this change repairs that on the next build. Post-merge, the first master image should report its commit — I'll be verifying that as part of managed-deploy validation. - No test changes: the fallback path is already covered by existing server-info tests; this PR only supplies the env at image build. ## Risks - Low. Two build-time stamps; no runtime code changes. A wrong SHA would only mislabel the build (same failure mode `PAPERCLIP_BUILD_VERSION` already carries), and `${{ github.sha }}` is the exact commit the workflow builds. ## Model Used Claude Fable 5 (`claude-fable-5`, extended thinking, via Claude Code with tool use and code execution); diagnosis included live probes of a running container's `/api/health`. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass (no test-affecting changes; server suites unaffected) - [x] I have added or updated tests where applicable (n/a — build-time stamps only) - [x] I have updated relevant documentation to reflect my changes (Dockerfile comments document the arg) - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --- .github/workflows/docker.yml | 2 ++ Dockerfile | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index cb46bcbf2a..0703dfa924 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -148,6 +148,7 @@ jobs: target: production build-args: | PAPERCLIP_BUILD_VERSION=${{ steps.build-version.outputs.version }} + PAPERCLIP_BUILD_COMMIT=${{ github.sha }} platforms: linux/amd64,linux/arm64 push: true cache-from: type=gha @@ -295,6 +296,7 @@ jobs: build-args: | CLOUD_BUNDLED_PLUGINS=daytona PAPERCLIP_BUILD_VERSION=${{ steps.build-version.outputs.version }} + PAPERCLIP_BUILD_COMMIT=${{ github.sha }} platforms: linux/amd64,linux/arm64 push: true cache-from: type=gha diff --git a/Dockerfile b/Dockerfile index 7793c247fe..2dd12f5b9c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -63,6 +63,10 @@ ARG USER_GID=1000 # (the image has no .git, so the server cannot derive it at runtime). Empty for # local `docker build`, which just leaves the server on its normal fallbacks. ARG PAPERCLIP_BUILD_VERSION="" +# The exact commit this image was built from, for the same reason: server-info +# falls back to PAPERCLIP_BUILD_COMMIT when git is unavailable, which feeds the +# /api/health `commit` field that deploy tooling verifies. Empty locally. +ARG PAPERCLIP_BUILD_COMMIT="" WORKDIR /app COPY --chown=node:node --from=build /app /app RUN npm install --global --omit=dev @anthropic-ai/claude-code@latest @openai/codex@latest opencode-ai @google/gemini-cli@latest \ @@ -83,6 +87,7 @@ ENV NODE_ENV=production \ PAPERCLIP_HOME=/paperclip \ PAPERCLIP_INSTANCE_ID=default \ PAPERCLIP_BUILD_VERSION=${PAPERCLIP_BUILD_VERSION} \ + PAPERCLIP_BUILD_COMMIT=${PAPERCLIP_BUILD_COMMIT} \ USER_UID=${USER_UID} \ USER_GID=${USER_GID} \ PAPERCLIP_CONFIG=/paperclip/instances/default/config.json \