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