Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/update-versions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Audit versions.json (key == shipped version per rev)
run: ./scripts/fetch-node-versions.sh audit

- name: Commit changes if versions.json changed
id: commit
run: |
Expand Down
66 changes: 61 additions & 5 deletions scripts/fetch-node-versions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,26 @@ extract_version() {
echo "$msg" | grep -oP "${attr_re}.*?\K[0-9]+\.[0-9]+" | head -1 || true
}

# Confirm that pkgs/development/web/nodejs/v<major>.nix at $rev actually sets
# `version = "<major.minor>.x"`. A rev's commit message is a label, not a
# guarantee - this is the source of truth for what the rev actually builds.
verify_shipped_version() {
local -r major="$1" version="$2" rev="$3"
local -r url="https://raw.githubusercontent.com/${NIXPKGS_REPO}/${rev}/pkgs/development/web/nodejs/v${major}.nix"
local vfile attempt
# Retry the fetch: a transient network/CDN blip must not be mistaken for a
# real version mismatch (which would wrongly fail the audit / block an add).
for attempt in 1 2 3; do
if vfile=$(curl -sf "$url" 2>/dev/null); then
grep -qP "version\s*=\s*\"${version//./\\.}\.[0-9]+" <<<"$vfile"
return
fi
((attempt < 3)) && sleep "$attempt"
done
log warn "Could not fetch v${major}.nix for rev ${rev:0:7} after 3 attempts"
return 1
}

is_valid_version() {
local -r version="$1"
[[ "$version" =~ ^[0-9]+\.[0-9]+$ ]]
Expand Down Expand Up @@ -225,6 +245,11 @@ add_version() {
return 0
fi

verify_shipped_version "$major" "$version" "$rev" || {
log error "Rev ${rev:0:7} does not ship ${version}.x (checked v${major}.nix); refusing to add"
return 1
}

log info "Adding Node.js $version..."

local sha256
Expand Down Expand Up @@ -333,16 +358,45 @@ cmd_add() {
for entry in "${commits[@]}"; do
[[ -z "$entry" ]] && continue
local sha="${entry%%|*}" msg="${entry#*|}"
if echo "$msg" | grep -q "$version"; then
log info "Found commit: ${sha:0:7}"
add_version "$version" "$sha"
return 0
fi
local extracted
extracted=$(extract_version "$msg")
[[ "$extracted" == "$version" ]] || continue

log info "Found commit: ${sha:0:7} ($msg)"
add_version "$version" "$sha" && return 0
log warn "Commit ${sha:0:7} rejected, continuing search..."
done

die "Could not find Node.js $version in nixpkgs"
}

cmd_audit() {
[[ -f "$VERSIONS_FILE" ]] || die "versions.json not found"

log info "Auditing versions.json: key == shippedVersion(rev) for each entry..."

local -a entries
mapfile -t entries < <(jq -r '.versions | to_entries[] | "\(.key)|\(.value.rev)"' "$VERSIONS_FILE")

local fail=0
for entry in "${entries[@]}"; do
local key="${entry%%|*}" rev="${entry#*|}"
local major="${key%%.*}"
if verify_shipped_version "$major" "$key" "$rev"; then
log info "OK $key (rev ${rev:0:7})"
else
log error "FAIL $key (rev ${rev:0:7}) does not ship ${key}.x per v${major}.nix"
((fail++))
fi
done

if ((fail > 0)); then
die "$fail entr$([[ $fail -eq 1 ]] && echo y || echo ies) failed the shippedVersion audit"
fi

log info "Audit passed: all ${#entries[@]} entries match their pinned rev."
}

usage() {
cat <<EOF
Usage: $(basename "$0") [command] [options]
Expand All @@ -351,6 +405,7 @@ Commands:
(none) Discover and add new Node.js versions
list List current versions
add <version> Add specific version (e.g., 22.12)
audit Verify every entry's rev actually ships its key version
--dry-run Show what would be added without making changes

Options:
Expand Down Expand Up @@ -390,6 +445,7 @@ main() {
case "${1:-}" in
list) cmd_list ;;
add) cmd_add "${2:-}" ;;
audit) cmd_audit ;;
"") cmd_discover "$dry_run" ;;
*)
usage
Expand Down
44 changes: 22 additions & 22 deletions versions.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@
},
"22.0": {
"version": "22.0",
"rev": "8a9a1e6369d83265d9a21dc62ced894b3e08edb4",
"sha256": "181rvmx8zvf6jyjk4v8znyxksaclnq51bidpbnnpk2pg1wlgvczb",
"rev": "ba733f8000925e837e30765f273fec153426403d",
"sha256": "05d31rs43nfw1hkgnhqpplrr32s96bc8fll66g32f0g41gjby9wq",
"attr": "nodejs_22"
},
"22.4": {
Expand Down Expand Up @@ -182,20 +182,20 @@
},
"24.13": {
"version": "24.13",
"rev": "9c0e2056b3c16190aafe67e4d29e530fc1f8c7c7",
"sha256": "0pkjlvjpvhsm078v0qb9i0y1vx3rgdpvk8wikvbxn0wldm0xkwps",
"rev": "a2cd48be3ba60ff87ddb7b5533e4185959f9f511",
"sha256": "15qh6s98abj5n5776bfhqgpbwahqqn4dcalwy1822b7p21cbyqn1",
"attr": "nodejs_24"
},
"24.14": {
"version": "24.14",
"rev": "0968bb28e2dd918c3228895ef76ffda0fdf1b5f3",
"sha256": "19730d82hvl9s7l8brl3q5xl9qkhjnza1gi9666wgl87cwigq0x3",
"rev": "d0a406bf79d281e5bfbede3a7721b4d6115bcb2c",
"sha256": "17g4hqfvv3ljf2xlxl1rfyv7hqs81z1g97phc05xc6z65g867yzg",
"attr": "nodejs_24"
},
"24.15": {
"version": "24.15",
"rev": "0968bb28e2dd918c3228895ef76ffda0fdf1b5f3",
"sha256": "19730d82hvl9s7l8brl3q5xl9qkhjnza1gi9666wgl87cwigq0x3",
"rev": "227c82a6ca851558a552111bf51824088a2df980",
"sha256": "1z7a376s8nqbz35lf550l85rjyai4c0lkr0xn87k2w4104dwi4h4",
"attr": "nodejs_24"
},
"25.2": {
Expand All @@ -218,26 +218,26 @@
},
"25.5": {
"version": "25.5",
"rev": "0801ac780b7116dda2c7b396f7b49c01367853c4",
"sha256": "1w4yfkvkgf6a3l51s7nfq8ncjirc0brfbr62y05wzcmfxqq4vrrr",
"rev": "dd0dc3d7a766e9a2bb283be80f60e16cfdaabb90",
"sha256": "0si6553rd1c3m67q0vb8mi3cl4fycw754pjnlhcjc43xlvjsapqb",
"attr": "nodejs_25"
},
"25.6": {
"version": "25.6",
"rev": "699d7d142df2cfacc4837b6b8d9d051b1b508759",
"sha256": "0f94sywarrsk0gldfa92nkw3sdc5v3b1xanhwpq2qicv3navd9a9",
"rev": "20d148068e415c4a68f4c97ae1856bc000949d10",
"sha256": "19cx7f3ly9pifhnaykvpav0s8y5fvaa1ln0aadiqkwpy03n7rr9k",
"attr": "nodejs_25"
},
"25.7": {
"version": "25.7",
"rev": "0d60a07834d66731ade3c0368db89e29eb722f7d",
"sha256": "0jv21jn1iaf2h2na063r1q91xd2nxncrgjxdnbadr0i0b6gyzci3",
"rev": "699d7d142df2cfacc4837b6b8d9d051b1b508759",
"sha256": "0f94sywarrsk0gldfa92nkw3sdc5v3b1xanhwpq2qicv3navd9a9",
"attr": "nodejs_25"
},
"25.8": {
"version": "25.8",
"rev": "94d8af17424dfc818024d98a59a0a1e0013495e6",
"sha256": "1yymvjk5ibxf7j9331i85bdnkmb74hvlha1156znfgsv5h5v6k64",
"rev": "a867e4c950e0ef01887be00a97f8b07861f8670e",
"sha256": "1h5zs8lxdw082n6apvw9ij9ppks4c6n55f8s7fwlq059ckqlg7mn",
"attr": "nodejs_25"
},
"25.9": {
Expand All @@ -248,20 +248,20 @@
},
"26.0": {
"version": "26.0",
"rev": "2ebf37ab0d456633dc5c29df64e1f97739eb7e56",
"sha256": "0c86sbsasjjxqs86v829kbvq6jdgywrs00rnixn5r6ihh7qycdf5",
"rev": "f47430fef5df8a398780068cdd390bab32e64eab",
"sha256": "1d9z2y1i1fr6dckprwkrrxw345aischpqrrp7dvmcpl48bd124ak",
"attr": "nodejs_26"
},
"26.1": {
"version": "26.1",
"rev": "0f94bb0d8954e8368a8ef716135c89f3143de178",
"sha256": "18jjhvbhb7s2qlnpq4phd8jjxywxdymi5l8p3q5icc6dygw16p00",
"rev": "2ebf37ab0d456633dc5c29df64e1f97739eb7e56",
"sha256": "0c86sbsasjjxqs86v829kbvq6jdgywrs00rnixn5r6ihh7qycdf5",
"attr": "nodejs_26"
},
"26.2": {
"version": "26.2",
"rev": "302d9e77f10a189ad64227c5a0e474e4ff5fb9eb",
"sha256": "03y4gzn98ls2yrafq9hycx1j2zsbydc1cx6wqmrfyjz828njrg5f",
"rev": "0f94bb0d8954e8368a8ef716135c89f3143de178",
"sha256": "18jjhvbhb7s2qlnpq4phd8jjxywxdymi5l8p3q5icc6dygw16p00",
"attr": "nodejs_26"
},
"26.3": {
Expand Down
Loading