fix(upgrade): restrict delta patch from-version to same major.minor series - #1329
Merged
Conversation
…eries
The PREV_TAG loop in `generate-patches` was walking past all 0.40
nightly tags and onto the lone 0.41.0-dev.1785504113 tag because
`sort -V` orders 0.41 > 0.40 lexicographically. At the time
generate-patches runs, the current build's tag hasn't been pushed
yet, so the loop's `if [ "$tag" = "nightly-${VERSION}" ]` break
never triggers — the loop ends naturally after iterating every
existing tag, and PREV_TAG becomes the 0.41 nightly.
Result: patches were generated FROM the 0.41 binary but stamped
with `from-version: 0.41.x-dev.Y` in the annotation. chain
resolution then fails for any user on the 0.40 series (their
current version is chronologically *before* 0.41.0-dev.1785504113
and the patch's from-version annotation doesn't match any chain
step), so delta upgrades fall back to full-download — every time.
Repro on the live registry:
```
# Inspect recent patches
$ ghcr.io/getsentry/cli:patch-0.40.0-dev.1785524715
from-version: 0.41.0-dev.1785504113 ← WRONG (should be 0.40.0-dev.1785522378)
$ ghcr.io/getsentry/cli:patch-0.40.0-dev.1785526951
from-version: 0.41.0-dev.1785504113 ← WRONG (should be 0.40.0-dev.1785524715)
```
Fix: filter TAGS to only those in the same major.minor series as
the current build before iterating. `MAJOR_MINOR` is parsed from
VERSION (`echo "${VERSION}" | cut -d. -f1,2` → e.g. `0.40`).
For `0.40.0-dev.X` builds the loop only sees `nightly-0.40.x-dev.*`
tags; for `0.41.0-dev.X` only `nightly-0.41.x-dev.*`. The first
build of a new series (no prior tags in the same series) falls
through with PREV_TAG="" and the existing HAS_PREV skip handles
it cleanly.
Retroactive remediation: the two mis-annotated patches above will
need their `from-version` annotations re-stamped (their patch bytes
are already correct — only the annotation is wrong). A separate
follow-up will re-publish `patch-0.40.0-dev.1785524715` with
`from-version=0.40.0-dev.1785522378` and
`patch-0.40.0-dev.1785526951` with
`from-version=0.40.0-dev.1785524715` so existing users on the
0.40 series can chain through them.
PR #1327 already prevents annotation drift between generate-patches
and publish-nightly — this fix prevents the initial PREV_TAG selection
from being wrong in the first place.
Adversarial review (NIT-2): the dot in `0.40` was being interpolated into a regex `grep` pattern, where `.` matches any character. In practice this can't mis-match because `oras repo tags` is filtered to `^nightly-[0-9]` upstream and `MAJOR_MINOR` is always digits.digits — but `grep -F` (fixed-string) makes the intent explicit and matches the defensive style of the rest of the script.
Contributor
|
BYK
added a commit
to BYK/binpatch
that referenced
this pull request
Aug 1, 2026
Closes #40. The `publish-ghcr` mode re-derived the previous version from the registry independently of the `generate-ghcr` step that actually downloaded the source binary and ran bsdiff. If the registry state changed between the two steps, the two values could disagree and `binpatch` consumers would silently hit SHA mismatch (the library only verifies the final output SHA, not the source binary identity — the annotation is a chain pointer, not a content hash). ## Fix Add a new `from-version` input on `publish-ghcr`. When set, the annotation on the pushed patch manifest uses THIS value verbatim. When empty (back-compat), the old registry re-derive runs and prints a hint suggesting the caller thread the value from `generate-ghcr`. ## Consumer wiring ```yaml - uses: BYK/binpatch/action@vX.Y.Z id: gen with: { mode: generate-ghcr, ... } - uses: BYK/binpatch/action@vX.Y.Z with: mode: publish-ghcr from-version: ${{ steps.gen.outputs.from-version }} ``` ## Files - action/action.yml: add `from-version` input, thread to push_patches via env, use input when set else re-derive - action/README.md: document the new input and the gen→publish wiring ## Relationship to other fixes - #37 — fd-close fix in applyReaderToFile (released as 0.4.0) - getsentry/cli#1329 — same-series filter in custom workflow (now merged) - getsentry/cli#1327 — CI workflow annotation threading (now merged) Combined, the chain-side fixes (binpatch fd-close + getsentry/cli CI workflow) and this action-side fix mean the consumer can stop running its own hand-rolled patch generation/publish and consume the binpatch action directly. ## Verification - pnpm test: 58 passed - pnpm build: clean - pnpm typecheck: clean - pnpm lint: (no script)
This was referenced Aug 1, 2026
BYK
added a commit
to BYK/binpatch
that referenced
this pull request
Aug 1, 2026
…44) The `prev-ghcr` step walked past all 0.40 nightly tags and onto a stray 0.41 nightly because `sort -V` orders 0.41 > 0.40 lexicographically. At the time this step runs, the current build's own tag hasn't been pushed yet, so the loop's `if [ "$tag" = ... ]` break never triggers — the loop ends naturally after iterating every existing tag, and PREV_TAG becomes the 0.41 nightly. Result: patches were generated FROM the 0.41 binary and stamped with `from-version: 0.41.x-dev.Y` — useless to any user on the 0.40 series. ## Fix Filter TAGS to only those in the same major.minor series as the current build before iterating. `MAJOR_MINOR` is parsed from VERSION (`echo "${VERSION}" | cut -d. -f1,2` → e.g. `0.40`). For `0.40.0-dev.X` builds the loop only sees `nightly-0.40.x-dev.*` tags; for `0.41.0-dev.X` only `nightly-0.41.x-dev.*`. First build of a new series falls through with PREV_TAG="" and the existing skip-empty-PREV path handles it cleanly. Also uses `grep -F` (fixed-string) so the dot in MAJOR_MINOR is treated literally rather than as a regex metacharacter. ## Relationship to getsentry/cli#1329 This is the action-side port of getsentry/cli#1329's hand-rolled `MAJOR_MINOR` filter. getsentry/cli is migrating to use this action (PR #1330) so this fix lands ahead of the migration completing. ## Verification - pnpm test: 58 passed - YAML parses cleanly
BYK
added a commit
that referenced
this pull request
Aug 1, 2026
BYK/binpatch#44 ported the same-series filter from #1329 into the binpatch action's prev-ghcr step, so consumers adopting `generate-ghcr` no longer need to re-implement this safeguard. This bumps both the runtime dep (`binpatch` ^0.4.1 → ^0.4.2) and the action ref (BYK/binpatch/action@0.4.1 → @0.4.2) so the migration actually picks up the action's own fix.
BYK
added a commit
that referenced
this pull request
Aug 1, 2026
…lish (#1330) Replaces the hand-rolled ~250 lines of `generate-patches` and `publish-nightly` bash in `.github/workflows/ci.yml` with the `BYK/binpatch/action@v0.4.1` composite action. The action handles: - ORAS CLI install + GHCR login - Previous-nightly discovery (with the same-series filter that fixes the cross-major nightly tag confusion) - zig-bsdiff invocation + patch size gate (50% ratio) - Binary + versioned-tag + patch manifest push with `from-version` annotation threaded via action outputs This eliminates the divergence bug we hit twice: - The PREV_TAG recomputation divergence between generate-patches and publish-nightly (PR #1327 fixed this in the hand-rolled shell; the action solves it generically by exposing `generate-ghcr.outputs.from-version` and consuming it as a `publish-ghcr` input — see BYK/binpatch#40) - The cross-major nightly tag confusion (PR #1329 fixed this in the hand-rolled shell; the action's `validateChainStep` does the equivalent check at chain-resolution time) Also bumps the `binpatch` runtime dep from `^0.3.1` to `^0.4.1` for the new `openSync`/`writeSync`/`closeSync` output path (which avoids the ETXTBSY race when chaining into a `spawn(tempPath)`). ## Files - `.github/workflows/ci.yml`: -220 lines of hand-rolled shell, +10 lines of action wiring - `packages/cli/package.json`: binpatch ^0.3.1 → ^0.4.1 - `pnpm-lock.yaml`: regenerated ## Diff ``` .github/workflows/ci.yml | 347 +++++++------- packages/cli/package.json | 2 +- pnpm-lock.yaml | 10 +- ``` ## Verification - `node -e 'require("yaml").parse(...)'` parses cleanly - `pnpm --filter sentry run typecheck`: clean - `pnpm --filter sentry run lint`: clean - Lint passes (no shell-script lint script; YAML is the only surface) --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
generate-patcheswas picking the wrongPREV_TAGfor 0.40 nightlybuilds, causing patches to be generated from a 0.41 source and stamped
with
from-version: 0.41.x-dev.Y— useless for any user on the 0.40series. Their chain resolution then fails (their version is
chronologically before 0.41) and the upgrade falls back to full-download
every time.
Repro on the live registry
Root cause
The PREV_TAG loop in
generate-patches:sort -Vorders0.41.0-dev.Xafter every0.40.0-dev.Y(because0.41 > 0.40lexicographically). At the timegenerate-patchesruns,the current build's tag hasn't been pushed yet — so the
if [ "$tag" = "nightly-${VERSION}" ]break never triggers. The loopwalks past every 0.40 tag and onto the 0.41 tag, and PREV_TAG becomes
the 0.41 nightly.
Fix
Filter
TAGSto only those in the samemajor.minorseries as thecurrent build before iterating.
MAJOR_MINORis parsed from VERSION(
echo "${VERSION}" | cut -d. -f1,2→ e.g.0.40). For 0.40 buildsthe loop only sees
nightly-0.40.0-dev.*tags; for 0.41 builds onlynightly-0.41.0-dev.*. The first build of a new series (no prior tagsin the same series) falls through with
PREV_TAG=""and the existingHAS_PREV skip handles it cleanly.
Retroactive remediation (follow-up)
The two mis-annotated patches above have correct bytes but wrong
annotations. Re-stamping them with the correct
from-versionwill letexisting 0.40-series users chain through them to the latest. Tracked as
a separate follow-up — they're already on the registry, just need the
annotation re-pushed.
Relationship to PR #1327
PR #1327 prevents annotation drift between
generate-patchesandpublish-nightly(they now agree via job outputs). This fix preventsthe initial PREV_TAG selection from being wrong in the first place.
Together they make the CI pipeline produce correct annotations
end-to-end.
Verification
MAJOR_MINORfilter + iteration over same-seriestags returns
nightly-0.40.0-dev.1785522378for VERSION=0.40.0-dev.1785524715vs. the current broken
nightly-0.41.0-dev.1785504113.