diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a556257bebb..b116dd17bab 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -127,4 +127,12 @@ jobs: - name: Test Docker image run: | docker run --rm ${{ github.sha }}:latest ./run.sh --version + + # Regression test for https://github.com/actions/runner/issues/4591. + # Node.js 25+ links against libatomic.so.1, which the dotnet/runtime-deps base image does not ship, + # so actions/setup-node with a modern Node version breaks unless the image installs libatomic1. + - name: Test Docker image provides Node.js 25+ runtime dependencies + run: | + docker run --rm ${{ github.sha }}:latest \ + bash -c 'set -euo pipefail; "$(command -v ldconfig || echo /sbin/ldconfig)" -p | grep -F -- "libatomic.so.1"' diff --git a/docs/start/envlinux.md b/docs/start/envlinux.md index 86f1416118f..360a69fe621 100644 --- a/docs/start/envlinux.md +++ b/docs/start/envlinux.md @@ -30,6 +30,7 @@ Debian based OS (Debian, Ubuntu, Linux Mint) - zlib1g - libssl3t64, libssl3, libssl1.1, libssl1.0.2 or libssl1.0.0 - libicu80, libicu79, ..., libicu66, libicu65, libicu63, libicu60, libicu57, libicu55, or libicu52 +- libatomic1 (see [Node.js dependencies](#nodejs-dependencies)) Fedora based OS (Fedora, Red Hat Enterprise Linux, CentOS, Oracle Linux 7) @@ -38,6 +39,7 @@ Fedora based OS (Fedora, Red Hat Enterprise Linux, CentOS, Oracle Linux 7) - krb5-libs - zlib - libicu +- libatomic (see [Node.js dependencies](#nodejs-dependencies)) SUSE based OS (OpenSUSE, SUSE Enterprise) @@ -46,5 +48,23 @@ SUSE based OS (OpenSUSE, SUSE Enterprise) - krb5 - zlib - libicu60_2 +- libatomic1 (see [Node.js dependencies](#nodejs-dependencies)) + +## Node.js dependencies + +The runner ships its own Node.js under `/externals/`, and workflows commonly install additional +Node.js versions into the tool cache with [actions/setup-node](https://github.com/actions/setup-node). + +The official Node.js binaries link against `libatomic.so.1` starting with **Node.js 25**. If that library is +missing, Node.js exits before running anything: + +``` +node: error while loading shared libraries: libatomic.so.1: cannot open shared object file: No such file or directory +``` + +`installdependencies.sh` installs this library on a best-effort basis (`libatomic1` on Debian/SUSE based +distributions, `libatomic` on Fedora based ones). It is treated as best effort rather than a hard requirement +because the runner itself starts fine without it — only Node.js 25+ needs it — so a distribution that does not +package it still configures successfully, with a warning. ## [More .Net Core Prerequisites Information](https://docs.microsoft.com/en-us/dotnet/core/linux-prerequisites?tabs=netcore2x) diff --git a/images/Dockerfile b/images/Dockerfile index 0abdf3e052b..5493440eba1 100644 --- a/images/Dockerfile +++ b/images/Dockerfile @@ -43,9 +43,21 @@ ENV RUNNER_MANUALLY_TRAP_SIG=1 ENV ACTIONS_RUNNER_PRINT_LOG_TO_STDOUT=1 ENV ImageOS=ubuntu24 -# 'gpg-agent' and 'software-properties-common' are needed for the 'add-apt-repository' command that follows +# 'gpg-agent' and 'software-properties-common' are needed for the 'add-apt-repository' command that follows. +# +# 'libatomic1' provides libatomic.so.1, which the official Node.js binaries link against starting with +# Node.js 25 (verified with `readelf -d bin/node`: absent in v24.x, present in v25.x and v26.x on both +# linux-x64 and linux-arm64). It is not part of the dotnet/runtime-deps base image, so a job that +# provisions Node with actions/setup-node fails at exec time with +# node: error while loading shared libraries: libatomic.so.1: cannot open shared object file +# See https://github.com/actions/runner/issues/4591. +# +# It is installed from Ubuntu 'main' (source package gcc-14) in the same apt transaction as the packages +# above, so it introduces no new repository or trust anchor, adds no executables to the image, and costs +# ~50 kB installed. Installing a compiler toolchain (build-essential/gcc) to obtain the same library would +# be a far larger attack surface and is deliberately avoided. RUN apt update -y \ - && apt install -y --no-install-recommends sudo lsb-release gpg-agent software-properties-common curl jq unzip \ + && apt install -y --no-install-recommends sudo lsb-release gpg-agent software-properties-common curl jq unzip libatomic1 \ && rm -rf /var/lib/apt/lists/* # Configure git-core/ppa based on guidance here: https://git-scm.com/download/linux diff --git a/src/Misc/layoutbin/installdependencies.sh b/src/Misc/layoutbin/installdependencies.sh index b58efe3482a..4b64d8f2227 100755 --- a/src/Misc/layoutbin/installdependencies.sh +++ b/src/Misc/layoutbin/installdependencies.sh @@ -19,7 +19,16 @@ function print_errormessage() echo "https://docs.microsoft.com/en-us/dotnet/core/linux-prerequisites?tabs=netcore2x" } -function print_rhel6message() +function print_libatomic_warningmessage() +{ + echo "Warning: couldn't install '$1'." + echo "The runner will still work, but Node.js 25 and newer won't start without libatomic.so.1," + echo "so actions that provision Node (for example actions/setup-node) may fail with" + echo "'error while loading shared libraries: libatomic.so.1'." + echo "Please install '$1' manually using your distribution's package manager." +} + +function print_rhel6message() { echo "We did our best effort to install dotnet core dependencies" echo "However, there are some dependencies which require manual installation" @@ -117,6 +126,13 @@ then print_errormessage exit 1 fi + + # libatomic.so.1 is a runtime dependency of the official Node.js binaries starting with Node.js 25. + # The Node.js versions bundled with the runner (externals/node20, externals/node24) do not need it, + # but toolchain actions such as actions/setup-node install Node into the tool cache, where it fails + # to start without this library. See https://github.com/actions/runner/issues/4591. + # Installed best-effort: a distribution without the package must not block runner configuration. + $apt_get install -y libatomic1 || print_libatomic_warningmessage libatomic1 elif [ -e /etc/redhat-release ] then echo "The current OS is Fedora based" @@ -137,7 +153,10 @@ then echo "'dnf' failed with exit code '$?'" print_errormessage exit 1 - fi + fi + + # See the libatomic comment in the Debian branch above. + dnf install -y libatomic || print_libatomic_warningmessage libatomic else echo "Can not find 'dnf'" print_errormessage @@ -149,11 +168,14 @@ then then yum install -y lttng-ust openssl-libs krb5-libs zlib libicu if [ $? -ne 0 ] - then + then echo "'yum' failed with exit code '$?'" print_errormessage exit 1 fi + + # See the libatomic comment in the Debian branch above. + yum install -y libatomic || print_libatomic_warningmessage libatomic else echo "Can not find 'yum'" print_errormessage @@ -178,6 +200,9 @@ then print_errormessage exit 1 fi + + # See the libatomic comment in the Debian branch above. + zypper -n install libatomic1 || print_libatomic_warningmessage libatomic1 else echo "Can not find 'zypper'" print_errormessage