Fix hash calculations

This commit is contained in:
2025-12-25 22:11:27 -04:00
parent e44400305c
commit bd7bbfca26
3 changed files with 78 additions and 14 deletions
+1 -1
View File
@@ -3,7 +3,7 @@
# #
# Notes: # Notes:
# - `sha256` values are Nix base32 hashes (as used by `fetchurl { sha256 = "..."; }`). # - `sha256` values are Nix base32 hashes (as used by `fetchurl { sha256 = "..."; }`).
version = "2.2.44"; version = "2.2.43";
sha256 = { sha256 = {
x86_64-linux = "1bgifjyscqymbz0srw8np9pc88gwcccic3z4cnydyfskxhnyj0sr"; x86_64-linux = "1bgifjyscqymbz0srw8np9pc88gwcccic3z4cnydyfskxhnyj0sr";
+6 -1
View File
@@ -116,7 +116,12 @@
pkgs = pkgsFor system; pkgs = pkgsFor system;
version = cursorRelease.version; version = cursorRelease.version;
channel = channelForSystem.${system} or (throw "Unsupported system: ${system}"); channel = channelForSystem.${system} or (throw "Unsupported system: ${system}");
url = "https://api2.cursor.sh/updates/download/golden/${channel}/cursor/${version}"; # Prefer the stable resolved downloads.cursor.com URL stored by ./update-cursor.sh.
# Fallback to the API URL for older cursor-release.nix files.
url =
if cursorRelease ? url && cursorRelease.url ? ${system}
then cursorRelease.url.${system}
else "https://api2.cursor.sh/updates/download/golden/${channel}/cursor/${version}";
sha256 = cursorRelease.sha256.${system} or "0000000000000000000000000000000000000000000000000000"; sha256 = cursorRelease.sha256.${system} or "0000000000000000000000000000000000000000000000000000";
in in
{ {
+71 -12
View File
@@ -15,10 +15,17 @@ RELEASE_FILE="$SCRIPT_DIR/cursor-release.nix"
CHANNEL_FOR_SYSTEM_x86_64_linux="linux-x64" CHANNEL_FOR_SYSTEM_x86_64_linux="linux-x64"
CHANNEL_FOR_SYSTEM_aarch64_linux="linux-arm64" CHANNEL_FOR_SYSTEM_aarch64_linux="linux-arm64"
# Get a redirect URL for a given "track" pointer (e.g. latest, 2.2). # Extract Cursor semver from a resolved download URL (Location header).
extract_version_from_url() {
local url="${1:-}"
echo "$url" | grep -Eo 'Cursor-[0-9]+\.[0-9]+\.[0-9]+' | sed 's/Cursor-//' || true
}
# Get a redirect URL for a given pointer (e.g. latest, 2.2, 2.2.44) and channel.
get_redirect_url() { get_redirect_url() {
local track="${1:?track is required}" local channel="${1:?channel is required}"
local url="https://api2.cursor.sh/updates/download/golden/linux-x64/cursor/${track}" local pointer="${2:?pointer is required}"
local url="https://api2.cursor.sh/updates/download/golden/${channel}/cursor/${pointer}"
# Avoid stale CDN/proxy cache results for fast-moving pointers like "latest". # Avoid stale CDN/proxy cache results for fast-moving pointers like "latest".
curl -sS -I \ curl -sS -I \
@@ -29,12 +36,58 @@ get_redirect_url() {
| tr -d '\r\n' | tr -d '\r\n'
} }
# Resolve a track pointer (e.g. latest, 2.2) into an actual semver (e.g. 2.2.44). # Resolve an exact version to a stable downloads.cursor.com URL.
#
# Guardrail: Cursor's API has been observed to sometimes redirect an "exact version" URL
# (e.g. /cursor/2.2.44) to an older AppImage (e.g. 2.2.43). When that happens, we retry via
# the major.minor pointer (e.g. /cursor/2.2) and only proceed if it resolves to the requested
# version.
resolve_download_url_for_version() {
local channel="${1:?channel is required}"
local version="${2:?version is required}"
local redirect_url resolved_version
redirect_url="$(get_redirect_url "$channel" "$version")"
if [[ -z "$redirect_url" ]]; then
echo "Error: Could not resolve Location header for ${channel} ${version}" >&2
return 1
fi
resolved_version="$(extract_version_from_url "$redirect_url")"
if [[ "$resolved_version" == "$version" ]]; then
echo "$redirect_url"
return 0
fi
local minor_pointer fallback_redirect fallback_resolved
minor_pointer="$(get_track_from_version "$version")"
echo "Warning: ${channel} ${version} resolved to ${resolved_version:-unknown}; retrying via pointer ${minor_pointer}" >&2
fallback_redirect="$(get_redirect_url "$channel" "$minor_pointer")"
if [[ -z "$fallback_redirect" ]]; then
echo "Error: Could not resolve Location header for fallback ${channel} ${minor_pointer}" >&2
return 1
fi
fallback_resolved="$(extract_version_from_url "$fallback_redirect")"
if [[ "$fallback_resolved" != "$version" ]]; then
echo "Error: Could not resolve requested version $version for channel $channel." >&2
echo "Tried:" >&2
echo " - /cursor/${version} -> ${resolved_version:-unknown} ($redirect_url)" >&2
echo " - /cursor/${minor_pointer} -> ${fallback_resolved:-unknown} ($fallback_redirect)" >&2
echo "Upstream pointers/caches are inconsistent; try again later." >&2
return 1
fi
echo "$fallback_redirect"
}
# Resolve a pointer (e.g. latest, 2.2) into an actual semver (e.g. 2.2.44).
get_latest_version() { get_latest_version() {
local track="${1:-latest}" local track="${1:-latest}"
local redirect_url local redirect_url
redirect_url="$(get_redirect_url "$track")" # Version discovery can just use linux-x64; the resolved version is shared across architectures.
redirect_url="$(get_redirect_url "$CHANNEL_FOR_SYSTEM_x86_64_linux" "$track")"
if [[ -n "$redirect_url" ]]; then if [[ -n "$redirect_url" ]]; then
# Extract version from URL like: .../Cursor-2.2.44-x86_64.AppImage # Extract version from URL like: .../Cursor-2.2.44-x86_64.AppImage
@@ -75,7 +128,7 @@ semver_max() {
# Function to compute sha256 for a given system+version # Function to compute sha256 for a given system+version
prefetch_sha256() { prefetch_sha256() {
local system="$1" local system="$1"
local version="$2" local url="$2"
local channel="" local channel=""
case "$system" in case "$system" in
@@ -84,15 +137,13 @@ prefetch_sha256() {
*) echo "Error: Unsupported system: $system" >&2; return 1 ;; *) echo "Error: Unsupported system: $system" >&2; return 1 ;;
esac esac
local url="https://api2.cursor.sh/updates/download/golden/${channel}/cursor/${version}"
if ! command -v nix-prefetch-url >/dev/null 2>&1; then if ! command -v nix-prefetch-url >/dev/null 2>&1; then
echo "Error: nix-prefetch-url not found. Please install Nix (or nix-prefetch-url) and retry." >&2 echo "Error: nix-prefetch-url not found. Please install Nix (or nix-prefetch-url) and retry." >&2
return 1 return 1
fi fi
# IMPORTANT: this function is captured by command substitution. Keep stdout as the hash only. # IMPORTANT: this function is captured by command substitution. Keep stdout as the hash only.
echo "Prefetching ($system) from: $url" >&2 echo "Prefetching ($system) from resolved URL: $url" >&2
local out hash local out hash
out="$(nix-prefetch-url --type sha256 "$url" 2>&1)" out="$(nix-prefetch-url --type sha256 "$url" 2>&1)"
@@ -114,9 +165,12 @@ update_release() {
echo "Computing hashes for version: $version" echo "Computing hashes for version: $version"
local sha_x86 sha_aarch64 local url_x86 url_aarch64 sha_x86 sha_aarch64
sha_x86="$(prefetch_sha256 x86_64-linux "$version")" url_x86="$(resolve_download_url_for_version "$CHANNEL_FOR_SYSTEM_x86_64_linux" "$version")"
sha_aarch64="$(prefetch_sha256 aarch64-linux "$version")" url_aarch64="$(resolve_download_url_for_version "$CHANNEL_FOR_SYSTEM_aarch64_linux" "$version")"
sha_x86="$(prefetch_sha256 x86_64-linux "$url_x86")"
sha_aarch64="$(prefetch_sha256 aarch64-linux "$url_aarch64")"
echo "x86_64-linux sha256: $sha_x86" echo "x86_64-linux sha256: $sha_x86"
echo "aarch64-linux sha256: $sha_aarch64" echo "aarch64-linux sha256: $sha_aarch64"
@@ -132,6 +186,11 @@ update_release() {
# - \`sha256\` values are Nix base32 hashes (as used by \`fetchurl { sha256 = "..."; }\`). # - \`sha256\` values are Nix base32 hashes (as used by \`fetchurl { sha256 = "..."; }\`).
version = "$version"; version = "$version";
url = {
x86_64-linux = "$url_x86";
aarch64-linux = "$url_aarch64";
};
sha256 = { sha256 = {
x86_64-linux = "$sha_x86"; x86_64-linux = "$sha_x86";
aarch64-linux = "$sha_aarch64"; aarch64-linux = "$sha_aarch64";