From ef7956b27722bc8eea7eb2d0c9f486b23a33e5be Mon Sep 17 00:00:00 2001 From: Zoltan Kochan Date: Sat, 7 Nov 2026 12:25:37 +0100 Subject: [PATCH] feat(release): build NetBSD x64 binaries natively in a VM (#17830) Build and publish the CLI for NetBSD x64. The cross images cannot link pnpm for x86_64-unknown-netbsd: their NetBSD 9 sysroot has no libexecinfo, which Rust's std links, and no getentropy, which aws-lc calls. NetBSD 9 is end-of-life, and a native build on NetBSD 10.2 needs no workaround. The NetBSD entry of the CLI release build matrix runs on a GitHub-hosted runner, which has KVM. A composite action installs NetBSD 10.2 with anita from the official release files and boots it, and .github/scripts/netbsd-vm/vm.sh builds inside it and copies the artifacts back to where the existing archive, attest, and upload steps expect them. The release files are checked against a committed SHA512 list, and anita and rustup-init against pinned SHA-256 hashes. A separate workflow runs the same build, plus an install, on changes to the VM files and weekly, since only a release tag runs the release jobs. --------- Co-authored-by: Alessio Attilio Co-authored-by: Claude Opus 5.5 --- .changeset/bright-dogs-netbsd.md | 6 + .github/actions/netbsd-vm/action.yml | 26 ++++ .github/scripts/netbsd-vm/enable-ssh.py | 39 +++++ .github/scripts/netbsd-vm/release.sha512 | 12 ++ .github/scripts/netbsd-vm/vm.sh | 142 +++++++++++++++++++ .github/workflows/netbsd-vm.yml | 57 ++++++++ .github/workflows/release.yml | 25 ++++ pnpm/docs/installation.md | 3 +- pnpm/npm/get-pnpm/src/platformPackageName.ts | 1 + pnpm/npm/get-pnpm/test/unit.test.ts | 3 + pnpm/npm/pnpm/native-binary.mjs | 3 + pnpm/npm/pnpm/scripts/generate-packages.mjs | 1 + pnpm/npm/pnpm/test/install.test.mjs | 7 + 13 files changed, 324 insertions(+), 1 deletion(-) create mode 100644 .changeset/bright-dogs-netbsd.md create mode 100644 .github/actions/netbsd-vm/action.yml create mode 100644 .github/scripts/netbsd-vm/enable-ssh.py create mode 100644 .github/scripts/netbsd-vm/release.sha512 create mode 100755 .github/scripts/netbsd-vm/vm.sh create mode 100644 .github/workflows/netbsd-vm.yml diff --git a/.changeset/bright-dogs-netbsd.md b/.changeset/bright-dogs-netbsd.md new file mode 100644 index 0000000000..6eb20534ce --- /dev/null +++ b/.changeset/bright-dogs-netbsd.md @@ -0,0 +1,6 @@ +--- +"pacquet": minor +"get-pnpm": minor +--- + +pnpm now provides a prebuilt binary for NetBSD 10 on x64 [#17803](https://github.com/pnpm/pnpm/issues/17803). diff --git a/.github/actions/netbsd-vm/action.yml b/.github/actions/netbsd-vm/action.yml new file mode 100644 index 0000000000..456932bf2b --- /dev/null +++ b/.github/actions/netbsd-vm/action.yml @@ -0,0 +1,26 @@ +name: NetBSD VM + +description: Boot a NetBSD VM with this checkout attached and Rust installed, for .github/scripts/netbsd-vm/vm.sh + +runs: + using: composite + + steps: + # GitHub-hosted Linux runners have KVM, but the runner user cannot open + # /dev/kvm until the device is made accessible. + - name: Enable KVM + shell: bash + run: | + echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules + sudo udevadm control --reload-rules + sudo udevadm trigger --name-match=kvm + + - name: Install qemu + shell: bash + run: | + sudo apt-get update + sudo apt-get install -y qemu-system-x86 python3-pexpect genisoimage + + - name: Install NetBSD and boot it + shell: bash + run: .github/scripts/netbsd-vm/vm.sh start diff --git a/.github/scripts/netbsd-vm/enable-ssh.py b/.github/scripts/netbsd-vm/enable-ssh.py new file mode 100644 index 0000000000..df6a737756 --- /dev/null +++ b/.github/scripts/netbsd-vm/enable-ssh.py @@ -0,0 +1,39 @@ +"""Log in on a fresh anita-installed NetBSD VM's serial console and start sshd. + +Usage: enable-ssh.py +""" + +import socket +import sys +import time + +import pexpect.fdpexpect + +port = int(sys.argv[1]) +with open(sys.argv[2], encoding='utf-8') as key_file: + authorized_key = key_file.read().strip() + +deadline = time.monotonic() + 120 +while True: + try: + console = socket.create_connection(('127.0.0.1', port)) + break + except OSError: + if time.monotonic() > deadline: + raise + time.sleep(1) + +session = pexpect.fdpexpect.fdspawn(console.fileno(), timeout=600, encoding='utf-8', logfile=sys.stdout) +session.send('\r') +session.expect('login:') +session.sendline('root') +session.expect('# ') +for command in [ + 'echo sshd=YES >> /etc/rc.conf && echo dhcpcd=YES >> /etc/rc.conf', + 'echo "PermitRootLogin prohibit-password" >> /etc/ssh/sshd_config', + f'mkdir -p /root/.ssh && echo "{authorized_key}" > /root/.ssh/authorized_keys && chmod -R go= /root/.ssh', + # The quotes keep the console's echo of this line from matching the marker. + '/etc/rc.d/dhcpcd start && /etc/rc.d/sshd start && echo "SSH-""READY"', +]: + session.sendline(command) +session.expect('SSH-READY') diff --git a/.github/scripts/netbsd-vm/release.sha512 b/.github/scripts/netbsd-vm/release.sha512 new file mode 100644 index 0000000000..3625543947 --- /dev/null +++ b/.github/scripts/netbsd-vm/release.sha512 @@ -0,0 +1,12 @@ +03e0876550f050776349cf487f73f313c9bad634bec1bcbf22ef0b297d1af61db587a3f08693adad2936adfa3663c6510e7d12a46fb806652cf904eb33c490be amd64/binary/sets/base.tar.xz +9163f96f57e98e8de219034a5c74f5e3502385a8168f4da667408f98921f8bf4e4919775ccd06e3ea33ed93149c62b01f724f2d81bcf7e057ac0d8bfc5a4d51b amd64/binary/sets/comp.tar.xz +1dd44ea51b3e98162d089ea3edaf7719b4243c717c3d132bdd361c233156ec5c72d0efc36448175210bd0e2fc269a54773c8769cd3859cfdb7eb4112827dda27 amd64/binary/sets/etc.tar.xz +6a237a8afe29b19ea896d2eaf7c8a066e2f8350e1dd44d56fce9c5b086a27e0f56f341a7b39678442bb35bc680385f688940c8bde3b2010fbdf6a6ecba9a2150 amd64/binary/sets/gpufw.tar.xz +2d526a976ef34bc152d6cbe2020dc6a54ada98e599337623616bae52d22828f1b9ef9d10533b05232dba3dc41af2810b1b2ead8eecb1455575068f8124579e1e amd64/binary/sets/kern-GENERIC.tar.xz +025a2cb4807fa1d0985015accecfff7d640a52d0f9a0c1bad8be549fe0da11279a3b9d3bf51781a5a1101bc0c6557c2ae2ea2cfc8f2983788e70e5f94fd1d706 amd64/binary/sets/misc.tar.xz +8a447f4ccceec4bc16e2b0c6b940801d9a37397df3af1b977c22dedae4fd071f277f98929b8b549885fc2d91bf145550264b83bb41b59876b80f7602d8298825 amd64/binary/sets/modules.tar.xz +5553ac509ad08d5c4f6eecf143459110109dfc85242ebf38942b95350e938e1f6e39c886b2d99ffe7ea57b878b8d2a4b177da271c4d3cf143fff2952e99e1475 amd64/binary/sets/rescue.tar.xz +f16997d2340ce115960bb694f35118b237afdf3e548eabd8028e93f36f4fbb658bfcd201cb7fb029e3a2117b5485c029084ad818d36d27e0168e8adfeaf6327a amd64/binary/sets/tests.tar.xz +0cf9b3e0a0464ab994cb1430439cbde4de42baffcd613312ebf0cd058815841a3f7073cac9578dadc8646e286a3d3cec886bdcabbb50ee3f3651ccd591e73f96 amd64/binary/kernel/netbsd-INSTALL.gz +ec87ab091d0b562c841234f17040190192d533479c707a51e65bf31914a5634233276f23027fd0a6f98dfbabfb8744196e2c23872209c123d29af8abfbd7cff5 amd64/installation/cdrom/boot-com.iso +9af9403e4aa64649be3a8902bf043556ab3097e146a9ac92bab59d51eb3a529d91e8089cc1b7207266a4d9dafe52877e67947fe5c6661d70d17d86a9f7119585 amd64/installation/misc/pxeboot_ia32.bin diff --git a/.github/scripts/netbsd-vm/vm.sh b/.github/scripts/netbsd-vm/vm.sh new file mode 100755 index 0000000000..c8013cf7ac --- /dev/null +++ b/.github/scripts/netbsd-vm/vm.sh @@ -0,0 +1,142 @@ +#!/usr/bin/env bash +# Builds release artifacts natively in a NetBSD VM that qemu runs with KVM. +# +# The `cross` NetBSD images cannot link pnpm: their NetBSD 9 sysroot has no +# libexecinfo (which Rust's std links) and no getentropy (which aws-lc calls). +# A native build on NetBSD 10 needs neither workaround. +# +# Every download is checked against a hash committed here: the NetBSD release +# files against release.sha512, anita and rustup-init against the constants +# below. The binaries built in the VM are attested and published. +# +# Usage: +# vm.sh start install NetBSD, boot it with this checkout attached, install Rust +# vm.sh build run `cargo build ` in the VM and copy the +# top-level files of target// back here +# vm.sh run run a shell command in the VM + +set -euo pipefail + +NETBSD_RELEASE=10.2 +ANITA_VERSION=2.18 +ANITA_SHA256=fa5ac3a8b3e30a3a35df9254bbee213b28210a396544592c3e604a1e53a294ce +RUSTUP_VERSION=1.29.3 +RUSTUP_SHA256=b3b81e3e737bc9465acfa5872c9c0afee7c6430bceaa52c038fbd9f3c327b51d + +script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +repo_root=$(git -C "$script_dir" rev-parse --show-toplevel) +vm_dir=${RUNNER_TEMP:-/tmp}/netbsd-vm +ssh_port=2222 +serial_port=4444 + +# The VM only listens on the runner's loopback and is created fresh by `start`, +# so there is no host key worth pinning. +vm_ssh() { + ssh -i "$vm_dir/key" -p "$ssh_port" \ + -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \ + -o LogLevel=ERROR -o ServerAliveInterval=30 \ + root@127.0.0.1 "$@" +} + +download() { + curl --fail --silent --show-error --location --retry 3 --output "$2" "$1" +} + +install_netbsd() { + local release_dir="$vm_dir/release" + local path + while read -r _ path; do + mkdir -p "$release_dir/$(dirname "$path")" + download "https://cdn.netbsd.org/pub/NetBSD/NetBSD-$NETBSD_RELEASE/$path" "$release_dir/$path" + done < "$script_dir/release.sha512" + (cd "$release_dir" && sha512sum --check --quiet "$script_dir/release.sha512") + + download "https://www.gson.org/netbsd/anita/download/anita-$ANITA_VERSION.tar.gz" "$vm_dir/anita.tar.gz" + echo "$ANITA_SHA256 $vm_dir/anita.tar.gz" | sha256sum --check --quiet + tar xzf "$vm_dir/anita.tar.gz" -C "$vm_dir" + + PYTHONPATH="$vm_dir/anita-$ANITA_VERSION" python3 "$vm_dir/anita-$ANITA_VERSION/anita" \ + --workdir "$vm_dir/work" --disk-size 40G --memory-size 4G \ + --vmm-args "-enable-kvm -cpu host" \ + install "$release_dir/amd64/" +} + +pack_source() { + # `.pnpm/crates` links into the pnpm store, so it is packed with the links + # followed: the VM builds offline from it. + git -C "$repo_root" ls-files -z | tar -C "$repo_root" --null -T - -cf "$vm_dir/source.tar" + tar -C "$repo_root" -rhf "$vm_dir/source.tar" .pnpm/crates +} + +boot() { + local memory_mb + memory_mb=$(( $(awk '/^MemTotal:/ { print $2 }' /proc/meminfo) * 3 / 4 / 1024 )) + # The source travels as a raw second disk, which the VM reads with tar. + qemu-system-x86_64 -enable-kvm -cpu host -smp "$(nproc)" -m "${memory_mb}M" \ + -drive "file=$vm_dir/work/wd0.img,format=raw,media=disk" \ + -drive "file=$vm_dir/source.tar,format=raw,media=disk,snapshot=on" \ + -nic "user,model=e1000,hostfwd=tcp:127.0.0.1:$ssh_port-:22" \ + -display none -serial "tcp:127.0.0.1:$serial_port,server,nowait" -daemonize + + ssh-keygen -q -t ed25519 -N '' -f "$vm_dir/key" + python3 "$script_dir/enable-ssh.py" "$serial_port" "$vm_dir/key.pub" + for _ in $(seq 1 30); do + vm_ssh true && return 0 + sleep 2 + done + echo "::error::the NetBSD VM did not accept SSH connections" >&2 + return 1 +} + +install_rust() { + download "https://static.rust-lang.org/rustup/archive/$RUSTUP_VERSION/x86_64-unknown-netbsd/rustup-init" "$vm_dir/rustup-init" + echo "$RUSTUP_SHA256 $vm_dir/rustup-init" | sha256sum --check --quiet + vm_ssh 'cat > /tmp/rustup-init && chmod +x /tmp/rustup-init' < "$vm_dir/rustup-init" + + local channel + channel=$(sed -n 's/^channel = "\(.*\)"$/\1/p' "$repo_root/rust-toolchain.toml") + vm_ssh "mkdir /build && cd /build && tar xf /dev/rwd1d && /tmp/rustup-init -y --profile minimal --default-toolchain $channel" +} + +build() { + local target='' profile=release + local arg previous='' + for arg in "$@"; do + case "$previous" in + --target) target=$arg ;; + --profile) profile=$arg ;; + esac + case "$arg" in + --target=*) target=${arg#--target=} ;; + --profile=*) profile=${arg#--profile=} ;; + esac + previous=$arg + done + if [ -z "$target" ]; then + echo "::error::vm.sh build needs --target, so the output lands where the release steps look for it" >&2 + return 1 + fi + + vm_ssh ". \$HOME/.cargo/env && cd /build && cargo build --offline $(printf '%q ' "$@")" + local output_dir="target/$target/$profile" + mkdir -p "$repo_root/$output_dir" + vm_ssh "cd /build/$output_dir && tar cf - \$(find . -maxdepth 1 -type f)" | tar xf - -C "$repo_root/$output_dir" +} + +command=${1:-} +shift || true +case "$command" in + start) + mkdir -p "$vm_dir" + install_netbsd + pack_source + boot + install_rust + ;; + build) build "$@" ;; + run) vm_ssh "$@" ;; + *) + echo "usage: vm.sh start | build | run " >&2 + exit 2 + ;; +esac diff --git a/.github/workflows/netbsd-vm.yml b/.github/workflows/netbsd-vm.yml new file mode 100644 index 0000000000..5f39cf4691 --- /dev/null +++ b/.github/workflows/netbsd-vm.yml @@ -0,0 +1,57 @@ +name: NetBSD VM build + +# The release builds NetBSD natively in a VM (see .github/scripts/netbsd-vm), +# and only a release tag runs that job. This builds and runs the CLI the same +# way, so a change that breaks the NetBSD build shows up before a release. +on: + pull_request: + paths: + - .github/actions/install-crates/** + - .github/actions/netbsd-vm/** + - .github/scripts/netbsd-vm/** + - .github/workflows/netbsd-vm.yml + - rust-toolchain.toml + schedule: + - cron: '0 4 * * 1' + workflow_dispatch: + +permissions: + contents: read # to fetch code (actions/checkout) + +concurrency: + group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.run_id }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +jobs: + build: + name: Build and run pnpm on NetBSD + # GitHub-hosted, for KVM. + runs-on: ubuntu-24.04 + timeout-minutes: 120 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - name: Install crates + uses: $/.github/actions/install-crates + with: + container-build: 'true' + + - name: Start the NetBSD VM + uses: $/.github/actions/netbsd-vm + + - name: Build and run pnpm + shell: bash + # Run outside the checkout: the repository's packageManager pin would + # otherwise make the new binary hand off to the pinned pnpm. + run: | + .github/scripts/netbsd-vm/vm.sh build --locked -p pnpm-cli --bin pnpm --release --target=x86_64-unknown-netbsd + .github/scripts/netbsd-vm/vm.sh run ' + set -e + mkdir /tmp/smoke && cd /tmp/smoke + echo "{\"name\":\"smoke\",\"version\":\"1.0.0\"}" > package.json + /build/target/x86_64-unknown-netbsd/release/pnpm --version + /build/target/x86_64-unknown-netbsd/release/pnpm add is-positive@3 + test -f node_modules/is-positive/package.json + ' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3090f5823a..1a72dbb553 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -688,6 +688,12 @@ jobs: target: x86_64-unknown-freebsd code-target: freebsd-x64 + # Built natively in a NetBSD VM, which needs KVM: see the VM build step. + - os: ubuntu-24.04 + target: x86_64-unknown-netbsd + code-target: netbsd-x64 + vm: netbsd + - os: blacksmith-8vcpu-ubuntu-2404 target: aarch64-linux-android code-target: android-arm64 @@ -723,6 +729,7 @@ jobs: container-build: 'true' - name: Build with cross + if: matrix.vm != 'netbsd' # windows-msvc links VCRUNTIME140.dll dynamically by default, and a # clean Windows install does not ship it, so pnpm.exe would exit # 0xC0000135 before main. Only the CLI links the CRT statically: the @@ -746,6 +753,24 @@ jobs: fi .github/scripts/cross-build.sh --locked -p pnpm-cli --bin pnpm --release --target="$TARGET" + - name: Start the NetBSD VM + if: matrix.vm == 'netbsd' + uses: $/.github/actions/netbsd-vm + + - name: Build and smoke-test in the NetBSD VM + if: matrix.vm == 'netbsd' + shell: bash + env: + TARGET: ${{ matrix.target }} + VERSION: ${{ needs.plan.outputs.rust_version }} + # Run outside the checkout: the repository's packageManager pin would + # otherwise make the new binary hand off to the pinned pnpm. + run: | + .github/scripts/netbsd-vm/vm.sh build --locked -p pnpm-cli --bin pnpm --release --target="$TARGET" + actual=$(.github/scripts/netbsd-vm/vm.sh run "cd /tmp && /build/target/$TARGET/release/pnpm --version") + echo "$actual" + test "$actual" = "$VERSION" + - name: Smoke-test Linux ppc64le startup if: matrix.target == 'powerpc64le-unknown-linux-gnu' shell: bash diff --git a/pnpm/docs/installation.md b/pnpm/docs/installation.md index 3dc8266d78..5e9d8942a3 100644 --- a/pnpm/docs/installation.md +++ b/pnpm/docs/installation.md @@ -20,9 +20,10 @@ pnpm 12 ships a prebuilt binary for each of these targets: | macOS | arm64, x64 | | Windows | x64, arm64 | | FreeBSD | x64 | +| NetBSD | x64 | | Android | arm64, x64 | -FreeBSD, ppc64le, s390x, RISC-V, and Android were added in v12.4.0. On a target with no binary, install the JavaScript [pnpm 11](https://www.npmjs.com/package/pnpm/v/11) instead. +FreeBSD, ppc64le, s390x, RISC-V, and Android were added in v12.4.0. The NetBSD binary is built and tested on NetBSD 10. On a target with no binary, install the JavaScript [pnpm 11](https://www.npmjs.com/package/pnpm/v/11) instead. For StackBlitz WebContainers, see the experimental [WebAssembly distribution](./webcontainers.md). diff --git a/pnpm/npm/get-pnpm/src/platformPackageName.ts b/pnpm/npm/get-pnpm/src/platformPackageName.ts index 7afd3c99d6..ab1cc1eb65 100644 --- a/pnpm/npm/get-pnpm/src/platformPackageName.ts +++ b/pnpm/npm/get-pnpm/src/platformPackageName.ts @@ -16,6 +16,7 @@ const V12_ONLY_TARGETS = new Set([ 'linux-ppc64', 'linux-riscv64', 'linux-s390x', + 'netbsd-x64', ]) /** diff --git a/pnpm/npm/get-pnpm/test/unit.test.ts b/pnpm/npm/get-pnpm/test/unit.test.ts index 30227c38b0..ffe36ba242 100644 --- a/pnpm/npm/get-pnpm/test/unit.test.ts +++ b/pnpm/npm/get-pnpm/test/unit.test.ts @@ -82,6 +82,7 @@ describe('platformPackageName', () => { test('v12 builds for hosts outside the x64/arm64 matrix', () => { assert.equal(platformPackageName(target({ major: 12, platform: 'freebsd' })), '@pnpm/exe.freebsd-x64') + assert.equal(platformPackageName(target({ major: 12, platform: 'netbsd' })), '@pnpm/exe.netbsd-x64') assert.equal(platformPackageName(target({ major: 12, arch: 'ppc64' })), '@pnpm/exe.linux-ppc64') assert.equal(platformPackageName(target({ major: 12, arch: 'riscv64' })), '@pnpm/exe.linux-riscv64') assert.equal(platformPackageName(target({ major: 12, arch: 's390x' })), '@pnpm/exe.linux-s390x') @@ -91,6 +92,7 @@ describe('platformPackageName', () => { test('those hosts have no binary before v12, and are pointed at it', () => { assert.throws(() => platformPackageName(target({ platform: 'freebsd' })), /pnpm v11 does not.*npx get-pnpm 12/s) + assert.throws(() => platformPackageName(target({ platform: 'netbsd' })), /pnpm v11 does not.*npx get-pnpm 12/s) assert.throws(() => platformPackageName(target({ arch: 's390x' })), /npx get-pnpm 12/) }) @@ -105,6 +107,7 @@ describe('platformPackageName', () => { assert.throws(() => platformPackageName(target({ arch: 'ia32' })), /linux-ia32/) assert.throws(() => platformPackageName(target({ major: 12, arch: 'ia32' })), /linux-ia32/) assert.throws(() => platformPackageName(target({ major: 12, platform: 'openbsd' })), /openbsd-x64/) + assert.throws(() => platformPackageName(target({ major: 12, platform: 'netbsd', arch: 'arm64' })), /netbsd-arm64/) // riscv64 is built for Linux only, so it is not a free pass on any OS. assert.throws(() => platformPackageName(target({ major: 12, platform: 'openbsd', arch: 'riscv64' })), /openbsd-riscv64/) }) diff --git a/pnpm/npm/pnpm/native-binary.mjs b/pnpm/npm/pnpm/native-binary.mjs index 9e07661ca4..4425c2c38c 100644 --- a/pnpm/npm/pnpm/native-binary.mjs +++ b/pnpm/npm/pnpm/native-binary.mjs @@ -44,6 +44,9 @@ const PLATFORMS = { freebsd: { x64: '@pnpm/exe.freebsd-x64/pnpm', }, + netbsd: { + x64: '@pnpm/exe.netbsd-x64/pnpm', + }, // Android is bionic, which is neither of the two libcs the linux entries // above are keyed on, so it takes a bare specifier of its own. android: { diff --git a/pnpm/npm/pnpm/scripts/generate-packages.mjs b/pnpm/npm/pnpm/scripts/generate-packages.mjs index db3c415fee..9be78cbd50 100644 --- a/pnpm/npm/pnpm/scripts/generate-packages.mjs +++ b/pnpm/npm/pnpm/scripts/generate-packages.mjs @@ -192,6 +192,7 @@ const TARGETS = [ { platform: "linux", arch: "x64", libc: "musl", codeTarget: "linux-x64-musl", packageTarget: "linux-x64-musl" }, { platform: "linux", arch: "arm64", libc: "musl", codeTarget: "linux-arm64-musl", packageTarget: "linux-arm64-musl" }, { platform: "freebsd", arch: "x64", codeTarget: "freebsd-x64", packageTarget: "freebsd-x64" }, + { platform: "netbsd", arch: "x64", codeTarget: "netbsd-x64", packageTarget: "netbsd-x64" }, { platform: "android", arch: "arm64", codeTarget: "android-arm64", packageTarget: "android-arm64" }, { platform: "android", arch: "x64", codeTarget: "android-x64", packageTarget: "android-x64" }, ]; diff --git a/pnpm/npm/pnpm/test/install.test.mjs b/pnpm/npm/pnpm/test/install.test.mjs index c456244e8b..a3fec8a104 100644 --- a/pnpm/npm/pnpm/test/install.test.mjs +++ b/pnpm/npm/pnpm/test/install.test.mjs @@ -223,6 +223,13 @@ test('freebsd x64 resolves the native package', async (t) => { assert.deepEqual(candidates(), ['@pnpm/exe.freebsd-x64/pnpm']) }) +test('netbsd x64 resolves the native package', async (t) => { + fakeHost(t, 'netbsd', 'x64') + const { getBinCandidates: candidates } = await import('../native-binary.mjs?netbsd') + + assert.deepEqual(candidates(), ['@pnpm/exe.netbsd-x64/pnpm']) +}) + test('an architecture released for both libcs still offers the other as a fallback', async (t) => { const { setLibc } = fakeHost(t, 'linux', 'x64') const { getBinCandidates: candidates } = await import('../native-binary.mjs?x64')