From 06f5dab0657f0a51c8a220bdb2b6089ce68b2e96 Mon Sep 17 00:00:00 2001 From: Vincent Haupert Date: Wed, 28 Feb 2024 09:40:25 +0100 Subject: github-runners: adapt to NixOS module While #859 added basic support for configuring GitHub runners through nix-darwin, it did not yet support all of the options the NixOS module offers. I am aware that this is a rather big overhaul. I think, however, that it's worth it: - Copies the `options.nix` from the [NixOS module] with only minor adaptations. This should help to keep track of any changes to it. - Respect the `workDir` config option. So far, the implementation didn't even read the value of the option. - Allow configuring a custom user and group. If both are `null`, nix-darwin manages the `_github-runner` user shared among all instances. Take care of creating your own users if that's not what you want. - Also creates the necessary directories for state, logs and the working directory (unless `workDir != null`). It uses the following locations: * state: `/var/lib/github-runners/${name}` * logs: `/var/log/github-runners/${name}` * work: The value of `workDir` or `/var/run/github-runners/${name}` if (`workDir == null`). We have to create the logs directory before starting the service since launchd expects that the `Standard{Error,Out}Path` exist. We do this by prepending to [`system.activationScripts.launchd.text`]. All directories belong to the configured `user` and `group`. - Warn if a `tokenFile` points to the Nix store. [NixOS module]: https://github.com/NixOS/nixpkgs/blob/3c30c56/nixos/modules/services/continuous-integration/github-runner/options.nix [`system.activationScripts.launchd.text`]: https://github.com/LnL7/nix-darwin/blob/bbde06b/modules/system/launchd.nix#L99-L123 --- modules/services/github-runner/options.nix | 182 +++++++++++++++++++++-------- 1 file changed, 135 insertions(+), 47 deletions(-) (limited to 'modules/services/github-runner/options.nix') diff --git a/modules/services/github-runner/options.nix b/modules/services/github-runner/options.nix index 5e421df..300ca32 100644 --- a/modules/services/github-runner/options.nix +++ b/modules/services/github-runner/options.nix @@ -6,30 +6,46 @@ with lib; { options.services.github-runners = mkOption { - default = { }; description = mdDoc '' - Configure multiple GitHub Runners. - ''; - example = literalExpression '' - { - m1-runner = { - enable = true; - ephemeral = true; - replace = true; - tokenFile = "/secrets/github-org-pat.token"; - url = "https://github.com/nixos"; - }; - - m2-runner = { - enable = true; - extraLabels = [ "nixpkgs" ]; - replace = true; - tokenFile = "/secrets/github-repo-pat.token"; - url = "https://github.com/nixos/nixpkgs"; - }; - } + Multiple GitHub Runners. + + If `user` and `group` are set to `null`, the module will configure nix-darwin to + manage the `_github-runner` user and group. Note that multiple runner + configurations share the same user/group, which means they can access + resources from other runners. Make each runner use its own user and group if + this is not what you want. In this case, you will have to do the user and + group creation yourself. If only `user` is set, while `group` is set to + `null`, the service will infer the primary group of the `user`. + + For each GitHub runner, the system activation script creates the following + directories: + + * `/var/lib/github-runners/`: + State directory to store the runner registration credentials + * `/var/log/github-runners/`: + The launchd service writes the stdout and stderr streams to this + directory. + * `/var/run/github-runners/`: + Working directory for workflow files. The runner only uses this + directory if `workDir` is `null` (see the `workDir` option for details). ''; - type = with types; attrsOf (submodule ({ name, ... }: { + example = { + runner1 = { + enable = true; + url = "https://github.com/owner/repo"; + name = "runner1"; + tokenFile = "/secrets/token1"; + }; + + runner2 = { + enable = true; + url = "https://github.com/owner/repo"; + name = "runner2"; + tokenFile = "/secrets/token2"; + }; + }; + default = { }; + type = types.attrsOf (types.submodule ({ name, ... }: { options = { enable = mkOption { default = false; @@ -40,7 +56,7 @@ with lib; Note: GitHub recommends using self-hosted runners with private repositories only. Learn more here: [About self-hosted runners](https://docs.github.com/en/actions/hosting-your-own-runners/about-self-hosted-runners). ''; - type = lib.types.bool; + type = types.bool; }; url = mkOption { @@ -64,25 +80,50 @@ with lib; tokenFile = mkOption { type = types.path; description = mdDoc '' - The full path to a file which contains either a runner registration token or a - (fine-grained) personal access token (PAT). + The full path to a file which contains either + + * a fine-grained personal access token (PAT), + * a classic PAT + * or a runner registration token + + Changing this option or the `tokenFile`’s content triggers a new runner registration. + + We suggest using the fine-grained PATs. A runner registration token is valid + only for 1 hour after creation, so the next time the runner configuration changes + this will give you hard-to-debug HTTP 404 errors in the configure step. + The file should contain exactly one line with the token without any newline. + (Use `echo -n '…token…' > …token file…` to make sure no newlines sneak in.) + + If the file contains a PAT, the service creates a new registration token + on startup as needed. If a registration token is given, it can be used to re-register a runner of the same - name but is time-limited. If the file contains a PAT, the service creates a new - registration token on startup as needed. Make sure the PAT has a scope of - `admin:org` for organization-wide registrations or a scope of - `repo` for a single repository. Fine-grained PATs need read and write permission - to the "Adminstration" resources. + name but is time-limited as noted above. + + For fine-grained PATs: - Changing this option or the file's content triggers a new runner registration. + Give it "Read and Write access to organization/repository self hosted runners", + depending on whether it is organization wide or per-repository. You might have to + experiment a little, fine-grained PATs are a `beta` Github feature and still subject + to change; nonetheless they are the best option at the moment. + + For classic PATs: + + Make sure the PAT has a scope of `admin:org` for organization-wide registrations + or a scope of `repo` for a single repository. + + For runner registration tokens: + + Nothing special needs to be done, but updating will break after one hour, + so these are not recommended. ''; example = "/run/secrets/github-runner/nixos.token"; }; name = mkOption { - type = types.str; + type = types.nullOr types.str; description = mdDoc '' - Name of the runner to configure. Defaults to the attribute name. + Name of the runner to configure. If null, defaults to the hostname. Changing this option triggers a new runner registration. ''; @@ -103,7 +144,7 @@ with lib; extraLabels = mkOption { type = types.listOf types.str; description = mdDoc '' - Extra labels in addition to the default (`["self-hosted", "Linux", "X64"]`). + Extra labels in addition to the default (unless disabled through the `noDefaultLabels` option). Changing this option triggers a new runner registration. ''; @@ -111,6 +152,16 @@ with lib; default = [ ]; }; + noDefaultLabels = mkOption { + type = types.bool; + description = mdDoc '' + Disables adding the default labels. Also see the `extraLabels` option. + + Changing this option triggers a new runner registration. + ''; + default = false; + }; + replace = mkOption { type = types.bool; description = mdDoc '' @@ -143,22 +194,12 @@ with lib; serviceOverrides = mkOption { type = types.attrs; description = mdDoc '' - Overrides for the systemd service. Can be used to adjust the sandboxing options. + Modify the service. Can be used to, e.g., adjust the sandboxing options. ''; - example = { - ProtectHome = false; - }; default = { }; }; - package = mkOption { - type = types.package; - description = mdDoc '' - Which github-runner derivation to use. - ''; - default = pkgs.github-runner; - defaultText = literalExpression "pkgs.github-runner"; - }; + package = mkPackageOptionMD pkgs "github-runner" { }; ephemeral = mkOption { type = types.bool; @@ -167,14 +208,61 @@ with lib; - Passes the `--ephemeral` flag to the runner configuration script - De-registers and stops the runner with GitHub after it has processed one job - - The runner wipes some state before it exists + - Restarts the service after its successful exit + - On start, wipes the state directory and configures a new runner You should only enable this option if `tokenFile` points to a file which contains a personal access token (PAT). If you're using the option with a registration token, restarting the service will fail as soon as the registration token expired. + + Changing this option triggers a new runner registration. ''; default = false; }; + + user = mkOption { + type = types.nullOr types.str; + description = mdDoc '' + User under which to run the service. + + If this option and the `group` option is set to `null`, nix-darwin creates + the `github-runner` user and group. + ''; + defaultText = literalExpression "username"; + default = null; + }; + + group = mkOption { + type = types.nullOr types.str; + description = mdDoc '' + Group under which to run the service. + + If this option and the `user` option is set to `null`, nix-darwin creates + the `github-runner` user and group. + ''; + defaultText = literalExpression "groupname"; + default = null; + }; + + workDir = mkOption { + type = with types; nullOr str; + description = mdDoc '' + Working directory, available as `$GITHUB_WORKSPACE` during workflow runs + and used as a default for [repository checkouts](https://github.com/actions/checkout). + The service cleans this directory on every service start. + + Changing this option triggers a new runner registration. + ''; + default = null; + }; + + nodeRuntimes = mkOption { + type = with types; nonEmptyListOf (enum [ "node20" ]); + default = [ "node20" ]; + description = mdDoc '' + List of Node.js runtimes the runner should support. + ''; + }; }; })); }; -- cgit v1.2.3