diff --git a/hack/upgrade-prev-version.sh b/hack/upgrade-prev-version.sh index 2f7adfd10..3bc5bb4c8 100755 --- a/hack/upgrade-prev-version.sh +++ b/hack/upgrade-prev-version.sh @@ -53,7 +53,12 @@ fi ver="${target#v}" ver="${ver%%-*}" # strip the -rc.N / -beta.N suffix maj=$(printf '%s' "$ver" | cut -d. -f1) -min=$(printf '%s' "$ver" | cut -d. -f2) +# -s is load-bearing: without it `cut -f2` on a line carrying no delimiter +# prints the WHOLE line, so a single-component target like "v1" yielded min=1 +# and was silently resolved as if it were v1.1 — printing a plausible baseline +# with exit 0 instead of rejecting an unparseable target. -s suppresses the +# delimiter-less line, min comes back empty, and the guard below catches it. +min=$(printf '%s' "$ver" | cut -s -d. -f2) case "${maj}:${min}" in *[!0-9:]*|:*|*:) echo "ERROR: cannot parse target version '$target'" >&2; exit 1 ;; esac diff --git a/hack/upgrade-prev-version_test.bats b/hack/upgrade-prev-version_test.bats index 86b2d435d..1c7025cb5 100755 --- a/hack/upgrade-prev-version_test.bats +++ b/hack/upgrade-prev-version_test.bats @@ -125,3 +125,28 @@ EOF false fi } + +# A target naming only a major ("v1") is not a version this resolver can act on, +# and must be refused rather than guessed at. It used to resolve: `cut -f2` +# without -s prints the whole line when it carries no delimiter, so min came +# back as "1" and v1 was silently treated as v1.1 — emitting a real-looking +# baseline from the v1.0 line with exit 0. A wrong-but-plausible baseline is +# worse than an error here, because the lane would install it and report on an +# upgrade path nobody asked for. +@test "a target naming only a major version is an error, not a guess" { + tmp=$(mktemp -d) + trap 'rm -rf "$tmp"' EXIT + _fixture > "$tmp/tags" + + for bad in v1 1; do + if out=$(hack/upgrade-prev-version.sh "$bad" "$tmp/tags" 2>/dev/null); then + echo "FAIL: target '$bad' should be refused, got '$out'" >&2 + false + fi + done + + # The two-component form is legitimate and must keep resolving — the guard + # rejects a missing minor, not a missing patch. + out=$(hack/upgrade-prev-version.sh "v1.6" "$tmp/tags") + [ -n "$out" ] +}