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, ... }: 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 name = lib.mkOption { 106 type = lib.types.nullOr lib.types.str; 107 description = '' 108 Name of the runner to configure. If null, defaults to the hostname. 109 110 Changing this option triggers a new runner registration. 111 ''; 112 example = "nixos"; 113 default = name; 114 }; 115 116 runnerGroup = lib.mkOption { 117 type = lib.types.nullOr lib.types.str; 118 description = '' 119 Name of the runner group to add this runner to (defaults to the default runner group). 120 121 Changing this option triggers a new runner registration. 122 ''; 123 default = null; 124 }; 125 126 extraLabels = lib.mkOption { 127 type = lib.types.listOf lib.types.str; 128 description = '' 129 Extra labels in addition to the default (unless disabled through the `noDefaultLabels` option). 130 131 Changing this option triggers a new runner registration. 132 ''; 133 example = lib.literalExpression ''[ "nixos" ]''; 134 default = [ ]; 135 }; 136 137 noDefaultLabels = lib.mkOption { 138 type = lib.types.bool; 139 description = '' 140 Disables adding the default labels. Also see the `extraLabels` option. 141 142 Changing this option triggers a new runner registration. 143 ''; 144 default = false; 145 }; 146 147 replace = lib.mkOption { 148 type = lib.types.bool; 149 description = '' 150 Replace any existing runner with the same name. 151 152 Without this flag, registering a new runner with the same name fails. 153 ''; 154 default = false; 155 }; 156 157 extraPackages = lib.mkOption { 158 type = lib.types.listOf lib.types.package; 159 description = '' 160 Extra packages to add to `PATH` of the service to make them available to workflows. 161 ''; 162 default = [ ]; 163 }; 164 165 extraEnvironment = lib.mkOption { 166 type = lib.types.attrs; 167 description = '' 168 Extra environment variables to set for the runner, as an attrset. 169 ''; 170 example = { 171 GIT_CONFIG = "/path/to/git/config"; 172 }; 173 default = { }; 174 }; 175 176 serviceOverrides = lib.mkOption { 177 type = lib.types.attrs; 178 description = '' 179 Modify the systemd service. Can be used to, e.g., adjust the sandboxing options. 180 See {manpage}`systemd.exec(5)` for more options. 181 ''; 182 example = { 183 ProtectHome = false; 184 RestrictAddressFamilies = [ "AF_PACKET" ]; 185 }; 186 default = { }; 187 }; 188 189 package = lib.mkPackageOption pkgs "github-runner" { }; 190 191 ephemeral = lib.mkOption { 192 type = lib.types.bool; 193 description = '' 194 If enabled, causes the following behavior: 195 196 - Passes the `--ephemeral` flag to the runner configuration script 197 - De-registers and stops the runner with GitHub after it has processed one job 198 - On stop, systemd wipes the runtime directory (this always happens, even without using the ephemeral option) 199 - Restarts the service after its successful exit 200 - On start, wipes the state directory and configures a new runner 201 202 You should only enable this option if `tokenFile` points to a file which contains a 203 personal access token (PAT). If you're using the option with a registration token, restarting the 204 service will fail as soon as the registration token expired. 205 206 Changing this option triggers a new runner registration. 207 ''; 208 default = false; 209 }; 210 211 user = lib.mkOption { 212 type = lib.types.nullOr lib.types.str; 213 description = '' 214 User under which to run the service. 215 216 If this option and the `group` option is set to `null`, 217 the service runs as a dynamically allocated user. 218 219 Also see the `group` option for an overview on the effects of the `user` and `group` settings. 220 ''; 221 default = null; 222 defaultText = lib.literalExpression "username"; 223 }; 224 225 group = lib.mkOption { 226 type = lib.types.nullOr lib.types.str; 227 description = '' 228 Group under which to run the service. 229 230 The effect of this option depends on the value of the `user` option: 231 232 - `group == null` and `user == null`: 233 The service runs with a dynamically allocated user and group. 234 - `group == null` and `user != null`: 235 The service runs as the given user and its default group. 236 - `group != null` and `user == null`: 237 This configuration is invalid. In this case, the service would use the given group 238 but run as root implicitly. If this is really what you want, set `user = "root"` explicitly. 239 ''; 240 default = null; 241 defaultText = lib.literalExpression "groupname"; 242 }; 243 244 workDir = lib.mkOption { 245 type = with lib.types; nullOr str; 246 description = '' 247 Working directory, available as `$GITHUB_WORKSPACE` during workflow runs 248 and used as a default for [repository checkouts](https://github.com/actions/checkout). 249 The service cleans this directory on every service start. 250 251 A value of `null` will default to the systemd `RuntimeDirectory`. 252 253 Changing this option triggers a new runner registration. 254 ''; 255 default = null; 256 }; 257 258 nodeRuntimes = lib.mkOption { 259 type = with lib.types; nonEmptyListOf (enum [ "node20" ]); 260 default = [ "node20" ]; 261 description = '' 262 List of Node.js runtimes the runner should support. 263 ''; 264 }; 265 }; 266 } 267 ) 268 ); 269 }; 270}