1{ autoPatchelfHook 2, autoSignDarwinBinariesHook 3, buildDotnetModule 4, dotnetCorePackages 5, fetchFromGitHub 6, fetchpatch 7, git 8, glibc 9, glibcLocales 10, lib 11, nixosTests 12, stdenv 13, which 14, buildPackages 15, runtimeShell 16 # List of Node.js runtimes the package should support 17, nodeRuntimes ? [ "node20" ] 18, nodejs_20 19}: 20 21# Node.js runtimes supported by upstream 22assert builtins.all (x: builtins.elem x [ "node20" ]) nodeRuntimes; 23 24buildDotnetModule rec { 25 pname = "github-runner"; 26 version = "2.311.0"; 27 28 src = fetchFromGitHub { 29 owner = "actions"; 30 repo = "runner"; 31 rev = "v${version}"; 32 hash = "sha256-71SwPuX1XZygT/TdAHECudxFxsQuXrl/tcAYVAxfxfI="; 33 leaveDotGit = true; 34 postFetch = '' 35 git -C $out rev-parse --short HEAD > $out/.git-revision 36 rm -rf $out/.git 37 ''; 38 }; 39 40 # The git commit is read during the build and some tests depend on a git repo to be present 41 # https://github.com/actions/runner/blob/22d1938ac420a4cb9e3255e47a91c2e43c38db29/src/dir.proj#L5 42 unpackPhase = '' 43 cp -r $src $TMPDIR/src 44 chmod -R +w $TMPDIR/src 45 cd $TMPDIR/src 46 ( 47 export PATH=${buildPackages.git}/bin:$PATH 48 git init 49 git config user.email "root@localhost" 50 git config user.name "root" 51 git add . 52 git commit -m "Initial commit" 53 git checkout -b v${version} 54 ) 55 mkdir -p $TMPDIR/bin 56 cat > $TMPDIR/bin/git <<EOF 57 #!${runtimeShell} 58 if [ \$# -eq 1 ] && [ "\$1" = "rev-parse" ]; then 59 echo $(cat $TMPDIR/src/.git-revision) 60 exit 0 61 fi 62 exec ${buildPackages.git}/bin/git "\$@" 63 EOF 64 chmod +x $TMPDIR/bin/git 65 export PATH=$TMPDIR/bin:$PATH 66 ''; 67 68 patches = [ 69 # Replace some paths that originally point to Nix's read-only store 70 ./patches/host-context-dirs.patch 71 # Use GetDirectory() to obtain "diag" dir 72 ./patches/use-get-directory-for-diag.patch 73 # Don't try to install service 74 ./patches/dont-install-service.patch 75 # Access `.env` and `.path` relative to `$RUNNER_ROOT`, if set 76 ./patches/env-sh-use-runner-root.patch 77 # Fix FHS path: https://github.com/actions/runner/pull/2464 78 (fetchpatch { 79 name = "ln-fhs.patch"; 80 url = "https://github.com/actions/runner/commit/5ff0ce1.patch"; 81 hash = "sha256-2Vg3cKZK3cE/OcPDZkdN2Ro2WgvduYTTwvNGxwCfXas="; 82 }) 83 ] ++ lib.optionals (nodeRuntimes == [ "node20" ]) [ 84 # If the package is built without Node 16, make Node 20 the default internal version 85 # https://github.com/actions/runner/pull/2844 86 (fetchpatch { 87 name = "internal-node-20.patch"; 88 url = "https://github.com/actions/runner/commit/acdc6ed.patch"; 89 hash = "sha256-3/6yhhJPr9OMWBFc5/NU/DRtn76aTYvjsjQo2u9ZqnU="; 90 }) 91 ]; 92 93 postPatch = '' 94 # Ignore changes to src/Runner.Sdk/BuildConstants.cs 95 substituteInPlace src/dir.proj \ 96 --replace 'git update-index --assume-unchanged ./Runner.Sdk/BuildConstants.cs' \ 97 'true' 98 ''; 99 100 DOTNET_SYSTEM_GLOBALIZATION_INVARIANT = isNull glibcLocales; 101 LOCALE_ARCHIVE = lib.optionalString (!DOTNET_SYSTEM_GLOBALIZATION_INVARIANT) "${glibcLocales}/lib/locale/locale-archive"; 102 103 postConfigure = '' 104 # Generate src/Runner.Sdk/BuildConstants.cs 105 dotnet msbuild \ 106 -t:GenerateConstant \ 107 -p:ContinuousIntegrationBuild=true \ 108 -p:Deterministic=true \ 109 -p:PackageRuntime="${dotnetCorePackages.systemToDotnetRid stdenv.hostPlatform.system}" \ 110 -p:RunnerVersion="${version}" \ 111 src/dir.proj 112 ''; 113 114 nativeBuildInputs = [ 115 which 116 git 117 ] ++ lib.optionals stdenv.isLinux [ 118 autoPatchelfHook 119 ] ++ lib.optionals (stdenv.isDarwin && stdenv.isAarch64) [ 120 autoSignDarwinBinariesHook 121 ]; 122 123 buildInputs = [ stdenv.cc.cc.lib ]; 124 125 dotnet-sdk = dotnetCorePackages.sdk_6_0; 126 dotnet-runtime = dotnetCorePackages.runtime_6_0; 127 128 dotnetFlags = [ "-p:PackageRuntime=${dotnetCorePackages.systemToDotnetRid stdenv.hostPlatform.system}" ]; 129 130 # As given here: https://github.com/actions/runner/blob/0befa62/src/dir.proj#L33-L41 131 projectFile = [ 132 "src/Sdk/Sdk.csproj" 133 "src/Runner.Common/Runner.Common.csproj" 134 "src/Runner.Listener/Runner.Listener.csproj" 135 "src/Runner.Worker/Runner.Worker.csproj" 136 "src/Runner.PluginHost/Runner.PluginHost.csproj" 137 "src/Runner.Sdk/Runner.Sdk.csproj" 138 "src/Runner.Plugins/Runner.Plugins.csproj" 139 ]; 140 nugetDeps = ./deps.nix; 141 142 doCheck = true; 143 144 __darwinAllowLocalNetworking = true; 145 146 # Fully qualified name of disabled tests 147 disabledTests = 148 [ 149 "GitHub.Runner.Common.Tests.Listener.SelfUpdaterL0.TestSelfUpdateAsync" 150 "GitHub.Runner.Common.Tests.ProcessInvokerL0.OomScoreAdjIsInherited" 151 ] 152 ++ map (x: "GitHub.Runner.Common.Tests.Listener.SelfUpdaterL0.TestSelfUpdateAsync_${x}") [ 153 "Cancel_CloneHashTask_WhenNotNeeded" 154 "CloneHash_RuntimeAndExternals" 155 "DownloadRetry" 156 "FallbackToFullPackage" 157 "NoUpdateOnOldVersion" 158 "NotUseExternalsRuntimeTrimmedPackageOnHashMismatch" 159 "UseExternalsRuntimeTrimmedPackage" 160 "UseExternalsTrimmedPackage" 161 "ValidateHash" 162 ] 163 ++ map (x: "GitHub.Runner.Common.Tests.Worker.ActionManagerL0.PrepareActions_${x}") [ 164 "CompositeActionWithActionfile_CompositeContainerNested" 165 "CompositeActionWithActionfile_CompositePrestepNested" 166 "CompositeActionWithActionfile_MaxLimit" 167 "CompositeActionWithActionfile_Node" 168 "DownloadActionFromGraph" 169 "NotPullOrBuildImagesMultipleTimes" 170 "RepositoryActionWithActionYamlFile_DockerHubImage" 171 "RepositoryActionWithActionfileAndDockerfile" 172 "RepositoryActionWithActionfile_DockerHubImage" 173 "RepositoryActionWithActionfile_Dockerfile" 174 "RepositoryActionWithActionfile_DockerfileRelativePath" 175 "RepositoryActionWithActionfile_Node" 176 "RepositoryActionWithDockerfile" 177 "RepositoryActionWithDockerfileInRelativePath" 178 "RepositoryActionWithDockerfilePrepareActions_Repository" 179 "RepositoryActionWithInvalidWrapperActionfile_Node" 180 "RepositoryActionWithWrapperActionfile_PreSteps" 181 ] 182 ++ map (x: "GitHub.Runner.Common.Tests.DotnetsdkDownloadScriptL0.${x}") [ 183 "EnsureDotnetsdkBashDownloadScriptUpToDate" 184 "EnsureDotnetsdkPowershellDownloadScriptUpToDate" 185 ] 186 ++ [ "GitHub.Runner.Common.Tests.Listener.RunnerL0.TestRunOnceHandleUpdateMessage" ] 187 # Tests for trimmed runner packages which aim at reducing the update size. Not relevant for Nix. 188 ++ map (x: "GitHub.Runner.Common.Tests.PackagesTrimL0.${x}") [ 189 "RunnerLayoutParts_CheckExternalsHash" 190 "RunnerLayoutParts_CheckDotnetRuntimeHash" 191 ] 192 ++ lib.optionals (stdenv.hostPlatform.system == "aarch64-linux") [ 193 # "JavaScript Actions in Alpine containers are only supported on x64 Linux runners. Detected Linux Arm64" 194 "GitHub.Runner.Common.Tests.Worker.StepHostL0.DetermineNodeRuntimeVersionInAlpineContainerAsync" 195 "GitHub.Runner.Common.Tests.Worker.StepHostL0.DetermineNode20RuntimeVersionInAlpineContainerAsync" 196 ] 197 ++ lib.optionals DOTNET_SYSTEM_GLOBALIZATION_INVARIANT [ 198 "GitHub.Runner.Common.Tests.ProcessExtensionL0.SuccessReadProcessEnv" 199 "GitHub.Runner.Common.Tests.Util.StringUtilL0.FormatUsesInvariantCulture" 200 "GitHub.Runner.Common.Tests.Worker.VariablesL0.Constructor_SetsOrdinalIgnoreCaseComparer" 201 "GitHub.Runner.Common.Tests.Worker.WorkerL0.DispatchCancellation" 202 "GitHub.Runner.Common.Tests.Worker.WorkerL0.DispatchRunNewJob" 203 ] 204 ++ lib.optionals (!lib.elem "node16" nodeRuntimes) [ 205 "GitHub.Runner.Common.Tests.ProcessExtensionL0.SuccessReadProcessEnv" 206 ]; 207 208 testProjectFile = [ "src/Test/Test.csproj" ]; 209 210 preCheck = '' 211 mkdir -p _layout/externals 212 '' + lib.optionalString (lib.elem "node20" nodeRuntimes) '' 213 ln -s ${nodejs_20} _layout/externals/node20 214 ''; 215 216 postInstall = '' 217 mkdir -p $out/bin 218 219 install -m755 src/Misc/layoutbin/runsvc.sh $out/lib/github-runner 220 install -m755 src/Misc/layoutbin/RunnerService.js $out/lib/github-runner 221 install -m755 src/Misc/layoutroot/run.sh $out/lib/github-runner 222 install -m755 src/Misc/layoutroot/run-helper.sh.template $out/lib/github-runner/run-helper.sh 223 install -m755 src/Misc/layoutroot/config.sh $out/lib/github-runner 224 install -m755 src/Misc/layoutroot/env.sh $out/lib/github-runner 225 226 # env.sh is patched to not require any wrapping 227 ln -sr "$out/lib/github-runner/env.sh" "$out/bin/" 228 229 substituteInPlace $out/lib/github-runner/config.sh \ 230 --replace './bin/Runner.Listener' "$out/bin/Runner.Listener" 231 '' + lib.optionalString stdenv.isLinux '' 232 substituteInPlace $out/lib/github-runner/config.sh \ 233 --replace 'command -v ldd' 'command -v ${glibc.bin}/bin/ldd' \ 234 --replace 'ldd ./bin' '${glibc.bin}/bin/ldd ${dotnet-runtime}/shared/Microsoft.NETCore.App/${dotnet-runtime.version}/' \ 235 --replace '/sbin/ldconfig' '${glibc.bin}/bin/ldconfig' 236 '' + '' 237 # Remove uneeded copy for run-helper template 238 substituteInPlace $out/lib/github-runner/run.sh --replace 'cp -f "$DIR"/run-helper.sh.template "$DIR"/run-helper.sh' ' ' 239 substituteInPlace $out/lib/github-runner/run-helper.sh --replace '"$DIR"/bin/' '"$DIR"/' 240 241 # Make paths absolute 242 substituteInPlace $out/lib/github-runner/runsvc.sh \ 243 --replace './externals' "$out/lib/externals" \ 244 --replace './bin/RunnerService.js' "$out/lib/github-runner/RunnerService.js" 245 246 # The upstream package includes Node and expects it at the path 247 # externals/node$version. As opposed to the official releases, we don't 248 # link the Alpine Node flavors. 249 mkdir -p $out/lib/externals 250 '' + lib.optionalString (lib.elem "node20" nodeRuntimes) '' 251 ln -s ${nodejs_20} $out/lib/externals/node20 252 '' + '' 253 # Install Nodejs scripts called from workflows 254 install -D src/Misc/layoutbin/hashFiles/index.js $out/lib/github-runner/hashFiles/index.js 255 mkdir -p $out/lib/github-runner/checkScripts 256 install src/Misc/layoutbin/checkScripts/* $out/lib/github-runner/checkScripts/ 257 '' + lib.optionalString stdenv.isLinux '' 258 # Wrap explicitly to, e.g., prevent extra entries for LD_LIBRARY_PATH 259 makeWrapperArgs=() 260 261 # We don't wrap with libicu 262 substituteInPlace $out/lib/github-runner/config.sh \ 263 --replace '$LDCONFIG_COMMAND -NXv ''${libpath//:/ }' 'echo libicu' 264 '' + '' 265 # XXX: Using the corresponding Nix argument does not work as expected: 266 # https://github.com/NixOS/nixpkgs/issues/218449 267 # Common wrapper args for `executables` 268 makeWrapperArgs+=( 269 --run 'export RUNNER_ROOT="''${RUNNER_ROOT:-"$HOME/.github-runner"}"' 270 --run 'mkdir -p "$RUNNER_ROOT"' 271 --chdir "$out" 272 ) 273 ''; 274 275 # List of files to wrap 276 executables = [ 277 "config.sh" 278 "Runner.Listener" 279 "Runner.PluginHost" 280 "Runner.Worker" 281 "run.sh" 282 "runsvc.sh" 283 ]; 284 285 doInstallCheck = true; 286 installCheckPhase = '' 287 runHook preInstallCheck 288 289 export RUNNER_ROOT="$TMPDIR" 290 291 $out/bin/config.sh --help >/dev/null 292 $out/bin/Runner.Listener --help >/dev/null 293 294 version=$($out/bin/Runner.Listener --version) 295 if [[ "$version" != "${version}" ]]; then 296 printf 'Unexpected version %s' "$version" 297 exit 1 298 fi 299 300 commit=$($out/bin/Runner.Listener --commit) 301 if [[ "$commit" != "$(git rev-parse HEAD)" ]]; then 302 printf 'Unexpected commit %s' "$commit" 303 exit 1 304 fi 305 306 runHook postInstallCheck 307 ''; 308 309 passthru = { 310 tests.smoke-test = nixosTests.github-runner; 311 updateScript = ./update.sh; 312 }; 313 314 meta = with lib; { 315 changelog = "https://github.com/actions/runner/releases/tag/v${version}"; 316 description = "Self-hosted runner for GitHub Actions"; 317 homepage = "https://github.com/actions/runner"; 318 license = licenses.mit; 319 maintainers = with maintainers; [ veehaitch newam kfollesdal aanderse zimbatm ]; 320 platforms = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ]; 321 sourceProvenance = with sourceTypes; [ binaryNativeCode ]; 322 }; 323}