From 58d0d478a0cfc4c15cf4163ccd4fb8f44dc395aa Mon Sep 17 00:00:00 2001 From: sneak Date: Fri, 2 Oct 2026 03:02:54 +0000 Subject: [PATCH] Send .git without its config; correct shallow-clone and version comments .dockerignore lists .git/config, which holds the clone's remote URL and any credential in it; the build stage is the final image, so it would otherwise ship. git describe does not need it. The build-context test asserts the entry, and the README says the image carries .git without its config. The README now says a shallow clone stamps a tag only when the cloned commit itself carries one, and otherwise the short commit. The comment in src/index.ts says a build reports the version script/build stamps into dist/package.json, and package.json's own version only from source. Model: opus-5-5 --- .dockerignore | 5 ++++- README.md | 16 +++++++++------- src/index.ts | 6 ++++-- test/packaging/build-context.test.ts | 6 ++++++ 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/.dockerignore b/.dockerignore index bafa27c..8db1dad 100644 --- a/.dockerignore +++ b/.dockerignore @@ -3,7 +3,10 @@ # and dropping it would change what the lint phase's prettier check sees. # # .git is deliberately NOT excluded: the build derives the version it stamps -# from it (script/version). +# from it (script/version). It is sent without its config, which holds the +# clone's remote URL and any credential in it, and which the build stage, the +# final image, would otherwise carry. git describe does not need it. +.git/config # OS .DS_Store diff --git a/README.md b/README.md index e8f77d9..28cb4bf 100644 --- a/README.md +++ b/README.md @@ -196,13 +196,15 @@ The build fails if the checkout has `.git` and the version still comes out empty, `dev` or `unknown`: such a build could not be traced back to its commit. `.dockerignore` therefore does not leave out `.git`, so any `docker build .` of -a clone stamps the commit it was built from; a shallow clone of one branch has -no tags and stamps the short commit. `script/docker` (and so `make docker`) and -`script/cibuild` pass the version they resolve on the host, with `--dirty`, as -the build arg, which takes precedence. The image's -`org.opencontainers.image.version` label carries that build arg only, so a build -given none leaves it empty. `make build-bin` bundles the built `dist/`, so the -single binary reports the stamped version too. +a clone stamps the commit it was built from; a shallow clone stamps a tag only +when the cloned commit itself carries one, and otherwise the short commit. It +leaves out `.git/config`, which holds the clone's remote URL and any credential +in it, so the image carries `.git` without its config; `git describe` does not +need that file. `script/docker` (and so `make docker`) and `script/cibuild` pass +the version they resolve on the host, with `--dirty`, as the build arg, which +takes precedence. The image's `org.opencontainers.image.version` label carries +that build arg only, so a build given none leaves it empty. `make build-bin` +bundles the built `dist/`, so the single binary reports the stamped version too. ## Rationale diff --git a/src/index.ts b/src/index.ts index 1e8b631..60d90ee 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,7 @@ -// package.json is the one place the version is written. tsc copies it to -// dist/package.json, so this path resolves from source and from dist/src/. +// A build reports the version script/build stamps into dist/package.json; +// package.json's own version is reported only when running from source. tsc +// copies package.json to dist/package.json, so this path resolves from source +// and from dist/src/. import pkg from "../package.json" with { type: "json" }; export const VERSION: string = pkg.version; diff --git a/test/packaging/build-context.test.ts b/test/packaging/build-context.test.ts index 13c381d..ea52581 100644 --- a/test/packaging/build-context.test.ts +++ b/test/packaging/build-context.test.ts @@ -54,6 +54,12 @@ describe(".dockerignore", () => { expect(dockerignore).not.toContain(".git/"); }); + // The build stage is the final image, so a .git/config sent in would + // ship the clone's remote URL and any credential in it. + it("sends .git without its config", () => { + expect(dockerignore).toContain(".git/config"); + }); + // BuildKit lets a `Dockerfile.dockerignore` shadow the root one; such a // file would silently give the build a different, unreviewed context — // and eslint's flat config does not ignore dot-directories, so a stray