Fix custom package checksum verification for Mac and Linux arm64 #6

Merged
JMR-dev merged 1 commits from claude/custom-packages-checksum-yf1cS into main 2026-05-22 17:52:08 +00:00
2 changed files with 39 additions and 8 deletions
+29 -6
View File
@@ -47,7 +47,7 @@ import urllib.error
import urllib.request import urllib.request
from dataclasses import dataclass from dataclasses import dataclass
from pathlib import Path from pathlib import Path
from typing import Optional from typing import Optional, Union
import formatted_packages import formatted_packages
@@ -890,7 +890,8 @@ class CustomPackage:
name: str name: str
version: Optional[str] = None # pinned fallback version version: Optional[str] = None # pinned fallback version
url_template: Optional[str] = None # uses {version}, {arch}, {arch_go} url_template: Optional[str] = None # uses {version}, {arch}, {arch_go}
sha256: Optional[str] = None # hex digest of the pinned archive sha256: Optional[str] = None # single-arch hex digest (set by _resolve_latest)
sha256_map: Optional[dict] = None # per-platform pinned digests: {"os-arch": hex}
sha256_url_template: Optional[str] = None # template for a .minisig URL sha256_url_template: Optional[str] = None # template for a .minisig URL
minisign_key: Optional[str] = None # base64 public key for minisign verification minisign_key: Optional[str] = None # base64 public key for minisign verification
fetch_latest: Optional[str] = None # latest-version resolver hint fetch_latest: Optional[str] = None # latest-version resolver hint
@@ -907,6 +908,22 @@ class CustomPackage:
if self.sha256_url_template else None if self.sha256_url_template else None
) )
@property
def resolved_sha256(self) -> Optional[str]:
"""Return the SHA256 hex for the current OS+arch, lowercased.
sha256 (set dynamically by _resolve_latest) takes priority over sha256_map
so that a freshly fetched checksum always wins over the pinned fallback.
"""
if self.sha256:
return self.sha256.lower()
if self.sha256_map:
key = f"{OS}-{ARCH}"
val = self.sha256_map.get(key)
if val:
return val.lower()
return None
@property @property
def display_name(self) -> str: def display_name(self) -> str:
return f"{self.name}-{self.version}" if self.version else self.name return f"{self.name}-{self.version}" if self.version else self.name
@@ -974,10 +991,11 @@ def _sha256_of(path: Path) -> str:
def _verify(archive: Path, pkg: CustomPackage) -> bool: def _verify(archive: Path, pkg: CustomPackage) -> bool:
"""Returns True if verification passed (or nothing to verify), False on failure.""" """Returns True if verification passed (or nothing to verify), False on failure."""
if pkg.sha256: expected = pkg.resolved_sha256
if expected:
actual = _sha256_of(archive) actual = _sha256_of(archive)
if actual != pkg.sha256: if actual != expected:
err(f"SHA256 mismatch for {pkg.name}: expected {pkg.sha256}, got {actual}") err(f"SHA256 mismatch for {pkg.name}: expected {expected}, got {actual}")
return False return False
print(" SHA256 OK") print(" SHA256 OK")
elif pkg.sha256_url: elif pkg.sha256_url:
@@ -1469,7 +1487,7 @@ def _resolve_latest(pkg: CustomPackage) -> None:
return return
print(f" Latest is {latest_version} (pinned was {pkg.version}); using latest.") print(f" Latest is {latest_version} (pinned was {pkg.version}); using latest.")
pkg.version = latest_version pkg.version = latest_version
pkg.sha256 = latest_sha pkg.sha256 = latest_sha.lower()
pkg.sha256_url_template = None # prefer the freshly resolved sha256 pkg.sha256_url_template = None # prefer the freshly resolved sha256
@@ -1483,6 +1501,11 @@ def install_custom_packages(to_install: list[CustomPackage]) -> None:
if check_path is None and name_lower != "pip": if check_path is None and name_lower != "pip":
warn(f"{pkg.name}: no known install path — script will not detect future installs") warn(f"{pkg.name}: no known install path — script will not detect future installs")
# Packages that are OS-specific
if name_lower == "firecracker" and IS_MACOS:
warn(f"{pkg.name}: Linux-only — skipping on macOS")
continue
# Handlers that manage their own download/install # Handlers that manage their own download/install
if name_lower == "nvm": if name_lower == "nvm":
_install_nvm() _install_nvm()
+10 -2
View File
@@ -94,7 +94,12 @@ CUSTOM_PACKAGES: list[dict] = [
"name": "go", "name": "go",
"version": "1.26.3", "version": "1.26.3",
"url_template": "https://go.dev/dl/go{version}.{os_go}-{arch_go}.tar.gz", "url_template": "https://go.dev/dl/go{version}.{os_go}-{arch_go}.tar.gz",
"sha256": "2b2cfc7148493da5e73981bffbf3353af381d5f93e789c82c79aff64962eb556", "sha256_map": {
"linux-x86_64": "2b2cfc7148493da5e73981bffbf3353af381d5f93e789c82c79aff64962eb556",
"linux-aarch64": "9d89a3ea57d141c2b22d70083f2c8459ba3890f2d9e818e7e933b75614936565",
"macos-x86_64": "278d580b32e299fe4a9c990fcf2d02acfe538c7e551a6ee18f9c7164573d2c63",
"macos-aarch64": "875cf54a15311eee2c99b9dd67c68c4a49351d489ab622bf2cfd28c8f2078d3c",
},
"fetch_latest": "go", "fetch_latest": "go",
}, },
{"name": "neovim"}, {"name": "neovim"},
@@ -105,7 +110,10 @@ CUSTOM_PACKAGES: list[dict] = [
"https://github.com/firecracker-microvm/firecracker/releases/download/" "https://github.com/firecracker-microvm/firecracker/releases/download/"
"v{version}/firecracker-v{version}-{arch}.tgz" "v{version}/firecracker-v{version}-{arch}.tgz"
), ),
"sha256": "d4a32ab2322d887ca1bc4a4e7afa9cc35393e6362dfc2b3becb389d362e4275a", "sha256_map": {
"linux-x86_64": "d4a32ab2322d887ca1bc4a4e7afa9cc35393e6362dfc2b3becb389d362e4275a",
"linux-aarch64": "00654ac1e702a22744121ea9f10a4f792ebd7c3a744cba587dfac9fcb79b41a5",
},
"fetch_latest": "firecracker", "fetch_latest": "firecracker",
}, },
{ {