Summary
The version_gt() function removes the prerelease suffix from both versions before comparing them:
ver1="${ver1%%-*}"
ver2="${ver2%%-*}"
This causes prerelease and stable versions with the same major, minor, and patch numbers to be treated as equal.
For example:
Both are normalized internally to:
As a result, arcup does not recognize the stable release as newer than the release candidate.
Repository
circlefin/arc-node
Create issue:
https://github.com/circlefin/arc-node/issues/new
Affected file
arcup/arcup
|
version_gt() { |
|
[ "$1" = "$2" ] && return 1 |
|
|
|
# Remove 'v' prefix if present |
|
local ver1="${1#v}" |
|
local ver2="${2#v}" |
|
ver1="${ver1%%-*}" |
|
ver2="${ver2%%-*}" |
|
|
|
IFS=. read -r major1 minor1 patch1 <<EOF |
|
$ver1 |
|
EOF |
|
IFS=. read -r major2 minor2 patch2 <<EOF |
|
$ver2 |
|
EOF |
|
|
|
[ "$major1" -gt "$major2" ] && return 0 |
|
[ "$major1" -lt "$major2" ] && return 1 |
|
[ "$minor1" -gt "$minor2" ] && return 0 |
|
[ "$minor1" -lt "$minor2" ] && return 1 |
|
[ "$patch1" -gt "$patch2" ] && return 0 |
|
[ "$patch1" -lt "$patch2" ] && return 1 |
|
|
|
return 1 |
|
} |
|
|
The function is used by the installer update checks:
|
|
|
local response |
|
local remote_version |
|
response=$(curl_with_headers -fsSL "$ARCUP_BIN_URL" 2>/dev/null || true) |
|
remote_version=$(printf '%s\n' "$response" | awk -F'"' '/^ARCUP_INSTALLER_VERSION=/ {print $2; exit}') |
|
|
|
if [[ -z "$remote_version" ]]; then |
|
return |
|
fi |
|
|
|
if version_gt "$remote_version" "$ARCUP_INSTALLER_VERSION"; then |
|
echo "" |
|
warn "Your arcup version ($ARCUP_INSTALLER_VERSION) is outdated." |
|
warn "Latest version is $remote_version." |
|
warn "Run 'arcup --self-update' to update to the latest version." |
|
echo "" |
|
fi |
|
} |
|
exit 0 |
|
fi |
|
|
|
info "Updating from $ARCUP_INSTALLER_VERSION to $remote_version..." |
|
if cp "$_ARCUP_TMP_FILE" "$ARCUP_BIN_PATH" 2>/dev/null; then |
|
chmod 755 "$ARCUP_BIN_PATH" |
|
else |
|
error "Failed to update arcup at '$ARCUP_BIN_PATH' — ensure it is writable" |
|
fi |
Steps to reproduce
Source the script without running the main installation flow:
export ARCUP_SKIP_MAIN=1
source ./arcup/arcup
Compare a stable version with a release candidate:
version_gt "0.3.0" "0.3.0-rc.1"
echo $?
The function returns a non-zero status, meaning 0.3.0 is not considered greater.
The same issue can be demonstrated in the opposite direction:
version_gt "0.3.0-rc.2" "0.3.0-rc.1"
echo $?
Both prereleases are reduced to 0.3.0, so the newer release candidate is also not detected.
Expected behavior
The comparison should follow Semantic Versioning precedence:
0.3.0-rc.1 < 0.3.0-rc.2 < 0.3.0
Therefore:
version_gt "0.3.0" "0.3.0-rc.1"
should return success.
Likewise:
version_gt "0.3.0-rc.2" "0.3.0-rc.1"
should return success.
Actual behavior
All versions sharing the same major, minor, and patch numbers are treated as equal after their prerelease suffixes are removed.
Examples incorrectly treated as equivalent:
1.0.0-alpha
1.0.0-beta
1.0.0-rc.1
1.0.0
Impact
Users running a prerelease version of arcup may not be notified about or upgraded to the corresponding stable release.
Users may also fail to receive newer prerelease builds when only the prerelease identifier changes.
This can leave users on:
- release-candidate code after a stable release is available;
- older prerelease builds;
- installer versions containing bugs already fixed in a later prerelease or stable version.
Root cause
The implementation compares only numeric core components:
and intentionally discards everything following -, even though the accepted version format explicitly allows prerelease suffixes:
^v[0-9]+\.[0-9]+\.[0-9]+(-[A-Za-z0-9.+-]+)?$
The accepted input format and comparison behavior are therefore inconsistent.
Suggested fix
Use a SemVer-aware comparison implementation.
At minimum:
- Compare major, minor, and patch numerically.
- When the core versions are equal:
- a stable version is greater than a prerelease;
- compare dot-separated prerelease identifiers;
- compare numeric identifiers numerically;
- compare non-numeric identifiers lexically;
- numeric identifiers have lower precedence than non-numeric identifiers.
Alternatively, use a small dedicated SemVer utility already available on the target platforms or restrict installer versions to stable releases only.
Example expected comparisons:
1.0.0 > 1.0.0-rc.1
1.0.0-rc.2 > 1.0.0-rc.1
1.0.0-beta.11 > 1.0.0-beta.2
1.0.1 > 1.0.0
2.0.0 > 1.99.99
Tests
Add tests for:
version_gt "1.0.0" "1.0.0-rc.1"
version_gt "1.0.0-rc.2" "1.0.0-rc.1"
version_gt "1.0.0-beta.11" "1.0.0-beta.2"
version_gt "1.0.1" "1.0.0"
version_gt "2.0.0" "1.99.99"
Also verify the inverse cases return false:
version_gt "1.0.0-rc.1" "1.0.0"
version_gt "1.0.0-rc.1" "1.0.0-rc.2"
version_gt "1.0.0" "1.0.0"
Checklist
Summary
The
version_gt()function removes the prerelease suffix from both versions before comparing them:This causes prerelease and stable versions with the same major, minor, and patch numbers to be treated as equal.
For example:
Both are normalized internally to:
As a result,
arcupdoes not recognize the stable release as newer than the release candidate.Repository
circlefin/arc-nodeCreate issue:
https://github.com/circlefin/arc-node/issues/new
Affected file
arcup/arcuparc-node/arcup/arcup
Lines 261 to 286 in 745ba4e
The function is used by the installer update checks:
arc-node/arcup/arcup
Lines 413 to 430 in 745ba4e
arc-node/arcup/arcup
Lines 454 to 462 in 745ba4e
Steps to reproduce
Source the script without running the main installation flow:
Compare a stable version with a release candidate:
The function returns a non-zero status, meaning
0.3.0is not considered greater.The same issue can be demonstrated in the opposite direction:
Both prereleases are reduced to
0.3.0, so the newer release candidate is also not detected.Expected behavior
The comparison should follow Semantic Versioning precedence:
Therefore:
should return success.
Likewise:
should return success.
Actual behavior
All versions sharing the same major, minor, and patch numbers are treated as equal after their prerelease suffixes are removed.
Examples incorrectly treated as equivalent:
Impact
Users running a prerelease version of
arcupmay not be notified about or upgraded to the corresponding stable release.Users may also fail to receive newer prerelease builds when only the prerelease identifier changes.
This can leave users on:
Root cause
The implementation compares only numeric core components:
and intentionally discards everything following
-, even though the accepted version format explicitly allows prerelease suffixes:The accepted input format and comparison behavior are therefore inconsistent.
Suggested fix
Use a SemVer-aware comparison implementation.
At minimum:
Alternatively, use a small dedicated SemVer utility already available on the target platforms or restrict installer versions to stable releases only.
Example expected comparisons:
Tests
Add tests for:
Also verify the inverse cases return false:
Checklist