Skip to content

fix(opencode:pin): resolve ref from the tag instead of leaving it stale - #222

Merged
jack-champagne merged 1 commit into
mainfrom
jack/pin-resolve-ref
Jul 29, 2026
Merged

fix(opencode:pin): resolve ref from the tag instead of leaving it stale#222
jack-champagne merged 1 commit into
mainfrom
jack/pin-resolve-ref

Conversation

@jack-champagne

Copy link
Copy Markdown
Member

pnpm opencode:pin <tag> writes a lock that misreports its own provenance.

pinFromRelease only set ref when --ref was passed explicitly:

m.tag = tag;
if (ref) {  m.ref = ref; }     // no else — ref keeps the PREVIOUS value

So the ordinary invocation updates tag and both sha256s but leaves ref pointing at the previous release's commit.

Caught while bumping to v1.17.3-amicode.10 (#221) — the lock came out as:

"tag": "v1.17.3-amicode.10",
"ref": "bbe47b60bd7ffa0fabf96799fc134c57f69e0617",   ← amicode.9's commit

Does it matter?

Not for the shipped artifact. In source: "release" — the committed default — ref is never read: fetchFromRelease downloads by tag and verifies by sha256. A wrong ref cannot produce a wrong binary.

It matters in two other ways:

  1. source: "local" validates it. fetchFromLocal compares the clone HEAD against manifest.ref and throws:
    clone … is at <head> but the lock pins <ref> — checkout the pinned ref, update opencode.lock.json, or pass --any-ref
    With a stale ref that message names the wrong commit, so a fork developer following it checks out the previous release.
  2. Provenance. The lock is the record of which fork commit is vendored. Silently wrong on every bump.

Fix

Resolve the tag to its commit when --ref is omitted. amicode-release cuts annotated tags, so git/ref/tags/<tag> yields a tag object that needs dereferencing; lightweight tags point straight at the commit. Both handled.

Explicit --ref still wins. Resolution failure raises a pointed error instead of silently writing a stale value:

pin: could not resolve harmoniqs/opencode@<tag> to a commit (…). Pass --ref <40-hex> explicitly if the tag is not reachable via gh.

Verification

End-to-end, real tag, no --ref:

before:  "tag": "v1.17.3-amicode.9",  "ref": "bbe47b60bd7…"
$ pnpm --filter amicode opencode:pin v1.17.3-amicode.10
[opencode:pin] opencode.lock.json → v1.17.3-amicode.10 @ e0105cd4d0
after:   "tag": "v1.17.3-amicode.10", "ref": "e0105cd4d0d517354daaf47f5fd3d4776d708bf8"

e0105cd4d… is the commit v1.17.3-amicode.10 points at, confirmed by dereferencing the annotated tag.

Unit-level, against an injected resolver (resolveTagCommit is a seam on pinFromRelease, matching the existing download seam):

  • resolves ref from the tag when --ref is omitted
  • explicit --ref still wins
  • never silently leaves a stale ref
  • throws a helpful error when resolution fails
  • rejects a non-40-hex resolved ref

Stacked on nothing — independent of #221, which already carries the correctly-resolved ref because I passed --ref by hand there.

pinFromRelease only wrote `ref` when --ref was passed, so the ordinary
`pnpm opencode:pin <tag>` produced a lock claiming the new tag while `ref`
still pointed at the PREVIOUS release's commit.

Release mode ignores ref (tag drives the download, sha256 verifies it), so
this never shipped a wrong binary. But `source: "local"` validates ref
against the clone HEAD, so a stale ref tells a fork developer to check out
the wrong commit — and the lock misreports its own provenance either way.

Resolve the tag to its commit via gh, dereferencing annotated tags (what
amicode-release cuts). Explicit --ref still wins. Fails with a pointed error
rather than silently writing a stale value.

Caught bumping to v1.17.3-amicode.10: the lock read tag=.10 with
ref=bbe47b60 (.9's commit).
@jack-champagne
jack-champagne merged commit 1cff411 into main Jul 29, 2026
5 checks passed
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