Skip to content

feat(create-*): a pin is a commit SHA, not a name nobody moved yet - #14

Merged
y1o1 merged 1 commit into
developfrom
feat/source-exact-and-frozen-graph
Jul 27, 2026
Merged

feat(create-*): a pin is a commit SHA, not a name nobody moved yet#14
y1o1 merged 1 commit into
developfrom
feat/source-exact-and-frozen-graph

Conversation

@y1o1

@y1o1 y1o1 commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

The defect

--dplaax-module-ref rejected a denylist of six familiar branch names and
accepted everything else:

const KNOWN_MOVING_REFS = new Set(["main","master","develop","dev","head","trunk"]);

The comment above it claimed the CLI enforced "an exact tag". It did not.
release/2026-07, my-feature, HEAD~1 and every tag — all equally
movable — passed. release.pin.source-exact names this shape directly:

A denylist of known moving names is not a pin discipline — any branch is
movable. The generator accepts only what it can verify is immutable: a full
commit SHA.

The change

Inverted to the positive form — /^[0-9a-f]{40}$/, or nothing. Lowercase
because git resolves object ids in lowercase; accepting the other spelling
would give one commit two pin strings.

--allow-unpinned-ref is the mode boundary the rule implies by scoping its
requirement to a published-release mode. Iterating locally against a branch
is legitimate; publishing from one is not. The flag says in its own name what
it gives up, and a test pins that it is not also a bypass for a missing
value.

AUTH_REF loses its ARG AUTH_REF=poc default: a default here would have to be
a branch name — the very thing the requirement exists to keep out of a
published artifact. A POSIX-sh guard now fails the build early with a readable
message instead of failing deep inside the scaffold.

Blast radius

caller effect
publish-images.yml none — already passes github.sha
make instances none — already passes git rev-parse HEAD
local docker build must now pass an explicit SHA (no poc default)
a human running the CLI must pass a SHA, or --allow-unpinned-ref

Test plan

Both generators, 108 + 95 passing:

  • the six denylist names, still rejected — but now for the right reason;
  • the refs the denylist could never have caught (v0.1.0, release/2026-07,
    my-feature, HEAD~1, deadbeef);
  • both boundaries of the SHA shape — 39 hex chars, and 40 uppercase;
  • the escape actually scaffolds (--allow-unpinned-ref → exit 0), which a
    rejection-only suite would have missed;
  • the escape does not license a missing value.

Guard logic verified against all four input shapes in POSIX sh (the gen stage
is alpine, so bash-isms would not run).

Not in this PR

release.lock.frozen-graph — the builder stage still runs a bare
pnpm install, so the instance's transitive graph is resolved fresh at image
build time. Closing it properly means generating and testing the lockfile
before the image build, which restructures the publish path; raised separately
rather than half-done here.

🤖 Generated with Claude Code

--dplaax-module-ref rejected a denylist of six familiar branch names (main,
master, develop, dev, head, trunk) and accepted everything else. That is not a
pin discipline, and release.pin.source-exact says why in as many words: any
branch is movable. So were `release/2026-07`, `my-feature`, and every tag —
all of which sailed straight through a check whose comment claimed it enforced
"an exact tag".

Inverted to the positive form: a full 40-hex lowercase commit id, or nothing.
Lowercase because git resolves object ids in lowercase, and accepting the
other spelling would give one commit two pin strings.

--allow-unpinned-ref is the mode boundary the rule implies by scoping the
requirement to a "published-release mode". Iterating locally against a branch
is legitimate; publishing from one is not. The escape is explicit, names what
it gives up in its own text, and does not double as a bypass for a missing
value — a test pins that.

AUTH_REF loses its `poc` default in generated-instance.Dockerfile: a default
here would have to be a branch name, i.e. the very thing the requirement
exists to keep out of a published artifact. The build now fails early with a
readable message instead of deep inside the scaffold; the guard is POSIX sh
(verified against the four shapes it must classify) because the stage is
alpine.

Tests: both generators, the denylist cases plus the ones it could never have
caught, both length and case boundaries of the SHA, and — the part a
rejection-only suite would miss — that the escape actually scaffolds.
@y1o1
y1o1 merged commit 3f62b59 into develop Jul 27, 2026
3 checks passed
@y1o1
y1o1 deleted the feat/source-exact-and-frozen-graph branch July 27, 2026 05:56
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