From dd7f27f7b8a9722be9a30ca1fc6e00fd07467f92 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 14 Aug 2026 14:26:10 +0000 Subject: [PATCH 1/2] Install libatomic1 in the runner container image The official Node.js binaries link against libatomic.so.1 starting with Node.js 25 (confirmed with `readelf -d bin/node`: the NEEDED entry is absent in v24.x and present in v25.x and v26.x, on both linux-x64 and linux-arm64). The dotnet/runtime-deps base image does not ship that library, so a workflow 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: No such file or directory Add libatomic1 to the existing apt transaction in the runtime stage. It comes from Ubuntu main (source package gcc-14), so it adds no new repository or trust anchor, ships no executables, and costs ~50 kB installed. Reusing the existing RUN keeps the layer count unchanged and keeps the package lists cleaned up in the same step. Also add a cheap regression test to the docker job so the library cannot silently disappear from the image again. Fixes #4591 --- .github/workflows/build.yml | 8 ++++++++ images/Dockerfile | 16 ++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) 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/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 From 35dd96e41cc05c90e04980db463222a6fe5aefec Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 14 Aug 2026 14:26:17 +0000 Subject: [PATCH 2/2] Install libatomic in installdependencies.sh and document it Non-containerized self-hosted runners hit the same Node.js 25+ failure as the container image: actions/setup-node installs Node into the tool cache, and it cannot start without libatomic.so.1. Install the library from each distribution's own package manager (libatomic1 on Debian/SUSE based, libatomic on Fedora based). This is done best-effort rather than as a hard requirement: the runner itself does not need libatomic today, since the bundled externals/node20 and externals/node24 do not link against it, so a distribution that does not package it must still configure successfully. On failure the script prints an actionable warning naming the package and the error it prevents. For the same reason config.sh is left alone -- gating runner configuration on a library only future Node.js versions need would be a regression. Document the dependency and the reasoning in docs/start/envlinux.md. --- docs/start/envlinux.md | 20 +++++++++++++++ src/Misc/layoutbin/installdependencies.sh | 31 ++++++++++++++++++++--- 2 files changed, 48 insertions(+), 3 deletions(-) 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/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