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