nixpkgs mirror (for testing)
github.com/NixOS/nixpkgs
nix
1{
2 lib,
3 pkgs,
4 ...
5}:
6{
7 options.services.github-runners = lib.mkOption {
8 description = ''
9 Multiple GitHub Runners.
10 '';
11 example = {
12 runner1 = {
13 enable = true;
14 url = "https://github.com/owner/repo";
15 name = "runner1";
16 tokenFile = "/secrets/token1";
17 };
18
19 runner2 = {
20 enable = true;
21 url = "https://github.com/owner/repo";
22 name = "runner2";
23 tokenFile = "/secrets/token2";
24 };
25 };
26 default = { };
27 type = lib.types.attrsOf (
28 lib.types.submodule (
29 { name, config, ... }:
30 {
31 options = {
32 enable = lib.mkOption {
33 default = false;
34 example = true;
35 description = ''
36 Whether to enable GitHub Actions runner.
37
38 Note: GitHub recommends using self-hosted runners with private repositories only. Learn more here:
39 [About self-hosted runners](https://docs.github.com/en/actions/hosting-your-own-runners/about-self-hosted-runners).
40 '';
41 type = lib.types.bool;
42 };
43
44 url = lib.mkOption {
45 type = lib.types.str;
46 description = ''
47 Repository to add the runner to.
48
49 Changing this option triggers a new runner registration.
50
51 IMPORTANT: If your token is org-wide (not per repository), you need to
52 provide a github org link, not a single repository, so do it like this
53 `https://github.com/nixos`, not like this
54 `https://github.com/nixos/nixpkgs`.
55 Otherwise, you are going to get a `404 NotFound`
56 from `POST https://api.github.com/actions/runner-registration`
57 in the configure script.
58 '';
59 example = "https://github.com/nixos/nixpkgs";
60 };
61
62 tokenFile = lib.mkOption {
63 type = lib.types.path;
64 description = ''
65 The full path to a file which contains either
66
67 * a fine-grained personal access token (PAT),
68 * a classic PAT
69 * or a runner registration token
70
71 Changing this option or the `tokenFile`’s content triggers a new runner registration.
72
73 We suggest using the fine-grained PATs. A runner registration token is valid
74 only for 1 hour after creation, so the next time the runner configuration changes
75 this will give you hard-to-debug HTTP 404 errors in the configure step.
76
77 The file should contain exactly one line with the token without any newline.
78 (Use `echo -n '…token…' > …token file…` to make sure no newlines sneak in.)
79
80 If the file contains a PAT, the service creates a new registration token
81 on startup as needed.
82 If a registration token is given, it can be used to re-register a runner of the same
83 name but is time-limited as noted above.
84
85 For fine-grained PATs:
86
87 Give it "Read and Write access to organization/repository self hosted runners",
88 depending on whether it is organization wide or per-repository. You might have to
89 experiment a little, fine-grained PATs are a `beta` Github feature and still subject
90 to change; nonetheless they are the best option at the moment.
91
92 For classic PATs:
93
94 Make sure the PAT has a scope of `admin:org` for organization-wide registrations
95 or a scope of `repo` for a single repository.
96
97 For runner registration tokens:
98
99 Nothing special needs to be done, but updating will break after one hour,
100 so these are not recommended.
101 '';
102 example = "/run/secrets/github-runner/nixos.token";
103 };
104
105 tokenType = lib.mkOption {
106 type = lib.types.enum [
107 "auto"
108 "access"
109 "registration"
110 ];
111 description = ''
112 Type of token to use for runner registration.
113
114 An access token is a personal access token or any other kind of GitHub token that
115 starts with `ghp_`, `gho_`, etc prefix. It is passed as `--pat` to the runner
116 config script.
117
118 A registration token is an unprefixed string generated by the
119 "Add new self-hosted runner" page. It is passed as `--token` to runner config
120 script.
121
122 The default `auto` attempts to detect the token type automatically based on its
123 format.
124 '';
125 example = "registration";
126 default = "auto";
127 };
128
129 name = lib.mkOption {
130 type = lib.types.nullOr lib.types.str;
131 description = ''
132 Name of the runner to configure. If null, defaults to the hostname.
133
134 Changing this option triggers a new runner registration.
135 '';
136 example = "nixos";
137 default = name;
138 };
139
140 runnerGroup = lib.mkOption {
141 type = lib.types.nullOr lib.types.str;
142 description = ''
143 Name of the runner group to add this runner to (defaults to the default runner group).
144
145 Changing this option triggers a new runner registration.
146 '';
147 default = null;
148 };
149
150 extraLabels = lib.mkOption {
151 type = lib.types.listOf lib.types.str;
152 description = ''
153 Extra labels in addition to the default (unless disabled through the `noDefaultLabels` option).
154
155 Changing this option triggers a new runner registration.
156 '';
157 example = lib.literalExpression ''[ "nixos" ]'';
158 default = [ ];
159 };
160
161 noDefaultLabels = lib.mkOption {
162 type = lib.types.bool;
163 description = ''
164 Disables adding the default labels. Also see the `extraLabels` option.
165
166 Changing this option triggers a new runner registration.
167 '';
168 default = false;
169 };
170
171 replace = lib.mkOption {
172 type = lib.types.bool;
173 description = ''
174 Replace any existing runner with the same name.
175
176 Without this flag, registering a new runner with the same name fails.
177 '';
178 default = false;
179 };
180
181 extraPackages = lib.mkOption {
182 type = lib.types.listOf lib.types.package;
183 description = ''
184 Extra packages to add to `PATH` of the service to make them available to workflows.
185 '';
186 default = [ ];
187 };
188
189 extraEnvironment = lib.mkOption {
190 type = lib.types.attrs;
191 description = ''
192 Extra environment variables to set for the runner, as an attrset.
193 '';
194 example = {
195 GIT_CONFIG = "/path/to/git/config";
196 };
197 default = { };
198 };
199
200 serviceOverrides = lib.mkOption {
201 type = lib.types.attrs;
202 description = ''
203 Modify the systemd service. Can be used to, e.g., adjust the sandboxing options.
204 See {manpage}`systemd.exec(5)` for more options.
205 '';
206 example = {
207 ProtectHome = false;
208 RestrictAddressFamilies = [ "AF_PACKET" ];
209 };
210 default = { };
211 };
212
213 package = lib.mkPackageOption pkgs "github-runner" { } // {
214 apply = pkg: pkg.override { inherit (config) nodeRuntimes; };
215 };
216
217 ephemeral = lib.mkOption {
218 type = lib.types.bool;
219 description = ''
220 If enabled, causes the following behavior:
221
222 - Passes the `--ephemeral` flag to the runner configuration script
223 - De-registers and stops the runner with GitHub after it has processed one job
224 - On stop, systemd wipes the runtime directory (this always happens, even without using the ephemeral option)
225 - Restarts the service after its successful exit
226 - On start, wipes the state directory and configures a new runner
227
228 You should only enable this option if `tokenFile` points to a file which contains a
229 personal access token (PAT). If you're using the option with a registration token, restarting the
230 service will fail as soon as the registration token expired.
231
232 Changing this option triggers a new runner registration.
233 '';
234 default = false;
235 };
236
237 user = lib.mkOption {
238 type = lib.types.nullOr lib.types.str;
239 description = ''
240 User under which to run the service.
241
242 If this option and the `group` option is set to `null`,
243 the service runs as a dynamically allocated user.
244
245 Also see the `group` option for an overview on the effects of the `user` and `group` settings.
246 '';
247 default = null;
248 defaultText = lib.literalExpression "username";
249 };
250
251 group = lib.mkOption {
252 type = lib.types.nullOr lib.types.str;
253 description = ''
254 Group under which to run the service.
255
256 The effect of this option depends on the value of the `user` option:
257
258 - `group == null` and `user == null`:
259 The service runs with a dynamically allocated user and group.
260 - `group == null` and `user != null`:
261 The service runs as the given user and its default group.
262 - `group != null` and `user == null`:
263 This configuration is invalid. In this case, the service would use the given group
264 but run as root implicitly. If this is really what you want, set `user = "root"` explicitly.
265 '';
266 default = null;
267 defaultText = lib.literalExpression "groupname";
268 };
269
270 workDir = lib.mkOption {
271 type = with lib.types; nullOr str;
272 description = ''
273 Working directory, available as `$GITHUB_WORKSPACE` during workflow runs
274 and used as a default for [repository checkouts](https://github.com/actions/checkout).
275 The service cleans this directory on every service start.
276
277 A value of `null` will default to the systemd `RuntimeDirectory`.
278
279 Changing this option triggers a new runner registration.
280 '';
281 default = null;
282 };
283
284 nodeRuntimes = lib.mkOption {
285 type =
286 with lib.types;
287 nonEmptyListOf (enum [
288 "node20"
289 "node24"
290 ]);
291 default = [
292 "node20"
293 "node24"
294 ];
295 description = ''
296 List of Node.js runtimes the runner should support.
297 '';
298 };
299 };
300 }
301 )
302 );
303 };
304}