diff options
Diffstat (limited to 'modules/services/github-runner')
| -rw-r--r-- | modules/services/github-runner/options.nix | 49 | ||||
| -rw-r--r-- | modules/services/github-runner/service.nix | 50 |
2 files changed, 62 insertions, 37 deletions
diff --git a/modules/services/github-runner/options.nix b/modules/services/github-runner/options.nix index 300ca32..5152cc4 100644 --- a/modules/services/github-runner/options.nix +++ b/modules/services/github-runner/options.nix @@ -3,10 +3,12 @@ , ... }: -with lib; +let + inherit (lib) literalExpression mkOption mkPackageOption types; +in { options.services.github-runners = mkOption { - description = mdDoc '' + description = '' Multiple GitHub Runners. If `user` and `group` are set to `null`, the module will configure nix-darwin to @@ -22,12 +24,12 @@ with lib; * `/var/lib/github-runners/<name>`: State directory to store the runner registration credentials + * `/var/lib/github-runners/_work/<name>`: + Working directory for workflow files. The runner only uses this + directory if `workDir` is `null` (see the `workDir` option for details). * `/var/log/github-runners/<name>`: The launchd service writes the stdout and stderr streams to this directory. - * `/var/run/github-runners/<name>`: - Working directory for workflow files. The runner only uses this - directory if `workDir` is `null` (see the `workDir` option for details). ''; example = { runner1 = { @@ -50,7 +52,7 @@ with lib; enable = mkOption { default = false; example = true; - description = mdDoc '' + description = '' Whether to enable GitHub Actions runner. Note: GitHub recommends using self-hosted runners with private repositories only. Learn more here: @@ -61,7 +63,7 @@ with lib; url = mkOption { type = types.str; - description = mdDoc '' + description = '' Repository to add the runner to. Changing this option triggers a new runner registration. @@ -79,7 +81,7 @@ with lib; tokenFile = mkOption { type = types.path; - description = mdDoc '' + description = '' The full path to a file which contains either * a fine-grained personal access token (PAT), @@ -88,6 +90,9 @@ with lib; Changing this option or the `tokenFile`’s content triggers a new runner registration. + You can also manually trigger a new runner registration by deleting + {file}`/var/lib/github-runners/<name>/.runner` and restarting the service. + 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. @@ -122,7 +127,7 @@ with lib; name = mkOption { type = types.nullOr types.str; - description = mdDoc '' + description = '' Name of the runner to configure. If null, defaults to the hostname. Changing this option triggers a new runner registration. @@ -133,7 +138,7 @@ with lib; runnerGroup = mkOption { type = types.nullOr types.str; - description = mdDoc '' + description = '' Name of the runner group to add this runner to (defaults to the default runner group). Changing this option triggers a new runner registration. @@ -143,7 +148,7 @@ with lib; extraLabels = mkOption { type = types.listOf types.str; - description = mdDoc '' + description = '' Extra labels in addition to the default (unless disabled through the `noDefaultLabels` option). Changing this option triggers a new runner registration. @@ -154,7 +159,7 @@ with lib; noDefaultLabels = mkOption { type = types.bool; - description = mdDoc '' + description = '' Disables adding the default labels. Also see the `extraLabels` option. Changing this option triggers a new runner registration. @@ -164,7 +169,7 @@ with lib; replace = mkOption { type = types.bool; - description = mdDoc '' + description = '' Replace any existing runner with the same name. Without this flag, registering a new runner with the same name fails. @@ -174,7 +179,7 @@ with lib; extraPackages = mkOption { type = types.listOf types.package; - description = mdDoc '' + description = '' Extra packages to add to `PATH` of the service to make them available to workflows. ''; default = [ ]; @@ -182,7 +187,7 @@ with lib; extraEnvironment = mkOption { type = types.attrs; - description = mdDoc '' + description = '' Extra environment variables to set for the runner, as an attrset. ''; example = { @@ -193,17 +198,17 @@ with lib; serviceOverrides = mkOption { type = types.attrs; - description = mdDoc '' + description = '' Modify the service. Can be used to, e.g., adjust the sandboxing options. ''; default = { }; }; - package = mkPackageOptionMD pkgs "github-runner" { }; + package = mkPackageOption pkgs "github-runner" { }; ephemeral = mkOption { type = types.bool; - description = mdDoc '' + description = '' If enabled, causes the following behavior: - Passes the `--ephemeral` flag to the runner configuration script @@ -222,7 +227,7 @@ with lib; user = mkOption { type = types.nullOr types.str; - description = mdDoc '' + description = '' User under which to run the service. If this option and the `group` option is set to `null`, nix-darwin creates @@ -234,7 +239,7 @@ with lib; group = mkOption { type = types.nullOr types.str; - description = mdDoc '' + description = '' Group under which to run the service. If this option and the `user` option is set to `null`, nix-darwin creates @@ -246,7 +251,7 @@ with lib; workDir = mkOption { type = with types; nullOr str; - description = mdDoc '' + description = '' 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. @@ -259,7 +264,7 @@ with lib; nodeRuntimes = mkOption { type = with types; nonEmptyListOf (enum [ "node20" ]); default = [ "node20" ]; - description = mdDoc '' + description = '' List of Node.js runtimes the runner should support. ''; }; diff --git a/modules/services/github-runner/service.nix b/modules/services/github-runner/service.nix index 53f2cdd..029f863 100644 --- a/modules/services/github-runner/service.nix +++ b/modules/services/github-runner/service.nix @@ -1,10 +1,14 @@ { config, lib, pkgs, ... }: -with lib; + let + inherit (lib) any attrValues boolToString concatStringsSep escapeShellArg + flatten flip getExe getExe' hasAttr hasPrefix mapAttrsToList mapAttrs' mkBefore + mkDefault mkIf mkMerge nameValuePair optionalAttrs optionalString replaceStrings; + mkSvcName = name: "github-runner-${name}"; mkStateDir = cfg: "/var/lib/github-runners/${cfg.name}"; mkLogDir = cfg: "/var/log/github-runners/${cfg.name}"; - mkWorkDir = cfg: if (cfg.workDir != null) then cfg.workDir else "/var/run/github-runners/${cfg.name}"; + mkWorkDir = cfg: if (cfg.workDir != null) then cfg.workDir else "/var/lib/github-runners/_work/${cfg.name}"; in { config.assertions = flatten ( @@ -17,6 +21,10 @@ in assertion = !cfg.noDefaultLabels || (cfg.extraLabels != [ ]); message = "`services.github-runners.${name}`: The `extraLabels` option is mandatory if `noDefaultLabels` is set"; } + { + assertion = cfg.workDir == null || !(hasPrefix "/run/" cfg.workDir || hasPrefix "/var/run/" cfg.workDir || hasPrefix "/private/var/run/"); + message = "`services.github-runners.${name}`: `workDir` being inside /run is not supported"; + } ]) ); @@ -44,14 +52,22 @@ in text = mkBefore ('' echo >&2 "setting up GitHub Runner '${cfg.name}'..." - ${pkgs.coreutils}/bin/mkdir -p -m 0750 ${escapeShellArg (mkStateDir cfg)} - ${pkgs.coreutils}/bin/chown ${user}:${group} ${escapeShellArg (mkStateDir cfg)} + ( + umask -S u=rwx,g=rx,o= > /dev/null + + ${getExe' pkgs.coreutils "mkdir"} -p ${escapeShellArg (mkStateDir cfg)} + ${getExe' pkgs.coreutils "chown"} ${user}:${group} ${escapeShellArg (mkStateDir cfg)} + + ${getExe' pkgs.coreutils "mkdir"} -p ${escapeShellArg (mkLogDir cfg)} + # launchd will fail to start the service if the outer direction doesn't have sufficient permissions + ${getExe' pkgs.coreutils "chmod"} o+rx ${escapeShellArg (mkLogDir { name = ""; })} + ${getExe' pkgs.coreutils "chown"} ${user}:${group} ${escapeShellArg (mkLogDir cfg)} - ${pkgs.coreutils}/bin/mkdir -p -m 0750 ${escapeShellArg (mkLogDir cfg)} - ${pkgs.coreutils}/bin/chown ${user}:${group} ${escapeShellArg (mkLogDir cfg)} - '' + optionalString (cfg.workDir == null) '' - ${pkgs.coreutils}/bin/mkdir -p -m 0750 ${escapeShellArg (mkWorkDir cfg)} - ${pkgs.coreutils}/bin/chown ${user}:${group} ${escapeShellArg (mkWorkDir cfg)} + ${optionalString (cfg.workDir == null) '' + ${getExe' pkgs.coreutils "mkdir"} -p ${escapeShellArg (mkWorkDir cfg)} + ${getExe' pkgs.coreutils "chown"} ${user}:${group} ${escapeShellArg (mkWorkDir cfg)} + ''} + ) ''); }; })); @@ -84,9 +100,13 @@ in script = let + # https://github.com/NixOS/nixpkgs/pull/333744 introduced an inconsistency with different + # versions of nixpkgs. Use the old version of escapeShellArg to make sure that labels + # are always escaped to avoid https://www.shellcheck.net/wiki/SC2054 + escapeShellArgAlways = string: "'${replaceStrings ["'"] ["'\\''"] (toString string)}'"; configure = pkgs.writeShellApplication { name = "configure-github-runner-${name}"; - text = '' + text = /*bash*/'' export RUNNER_ROOT args=( @@ -94,7 +114,7 @@ in --disableupdate --work ${escapeShellArg workDir} --url ${escapeShellArg cfg.url} - --labels ${escapeShellArg (concatStringsSep "," cfg.extraLabels)} + --labels ${escapeShellArgAlways (concatStringsSep "," cfg.extraLabels)} ${optionalString (cfg.name != null ) "--name ${escapeShellArg cfg.name}"} ${optionalString cfg.replace "--replace"} ${optionalString (cfg.runnerGroup != null) "--runnergroup ${escapeShellArg cfg.runnerGroup}"} @@ -109,7 +129,7 @@ in else args+=(--token "$token") fi - ${package}/bin/config.sh "''${args[@]}" + ${getExe' package "config.sh"} "''${args[@]}" ''; }; in @@ -117,12 +137,12 @@ in echo "Configuring GitHub Actions Runner" # Always clean the working directory - ${pkgs.findutils}/bin/find ${escapeShellArg workDir} -mindepth 1 -delete + ${getExe pkgs.findutils} ${escapeShellArg workDir} -mindepth 1 -delete # Clean the $RUNNER_ROOT if we are in ephemeral mode if ${boolToString cfg.ephemeral}; then echo "Cleaning $RUNNER_ROOT" - ${pkgs.findutils}/bin/find "$RUNNER_ROOT" -mindepth 1 -delete + ${getExe pkgs.findutils} "$RUNNER_ROOT" -mindepth 1 -delete fi # If the `.runner` file does not exist, we assume the runner is not configured @@ -131,7 +151,7 @@ in fi # Start the service - ${package}/bin/Runner.Listener run --startuptype service + ${getExe' package "Runner.Listener"} run --startuptype service ''; serviceConfig = mkMerge [ |
