main
  1{
  2  den,
  3  lib,
  4  inputs,
  5  ...
  6}: {
  7  den.aspects.services.forgejo.runner = {
  8    includes = [den.aspects.services.podman];
  9    settings = {
 10      instances = lib.mkOption {
 11        type = lib.types.attrsOf (lib.types.submodule ({name, ...}: {
 12          options = {
 13            name = lib.mkOption {
 14              type = lib.types.str;
 15              default = name;
 16            };
 17            servers = lib.mkOption {
 18              type = lib.types.attrsOf (lib.types.submodule {
 19                options = {
 20                  url = lib.mkOption {
 21                    type = lib.types.str;
 22                  };
 23                  uuid = lib.mkOption {
 24                    type = lib.types.str;
 25                  };
 26                  tokenFileAged = lib.mkOption {
 27                    type = lib.types.path;
 28                  };
 29                  labels = lib.mkOption {
 30                    type = lib.types.listOf lib.types.str;
 31                    description = "Extra labels used for this server.";
 32                    default = [];
 33                  };
 34                };
 35              });
 36              default = {};
 37            };
 38            labels = lib.mkOption {
 39              type = lib.types.listOf lib.types.str;
 40              default = [];
 41            };
 42            extraEnvironments = lib.mkOption {
 43              type = lib.types.attrsOf lib.types.str;
 44              default = {};
 45            };
 46            extraSettings = lib.mkOption {
 47              type = lib.types.attrsOf lib.types.anything;
 48              default = {};
 49            };
 50          };
 51        }));
 52        default = {};
 53      };
 54    };
 55
 56    persist = {
 57      directoies = [
 58        {
 59          directory = "/var/lib/private/forgejo-runner";
 60          user = "nobody";
 61          group = "nogroup";
 62          mode = "0700";
 63        }
 64      ];
 65    };
 66
 67    nixos = {
 68      host,
 69      config,
 70      ...
 71    }: let
 72      cfg = host.settings.services.forgejo.runner;
 73      mkServerTokenSecretName = instance: server: "forgejo-runner-${instance}-${server}-token";
 74    in {
 75      imports = [inputs.nur-hpcesia.nixosModules.forgejo-runner];
 76
 77      # If you would like to use docker runners in combination with cache actions,
 78      # be sure to add docker bridge interfaces “br-*” to the firewalls’ trusted interfaces.
 79      # See https://forgejo.org/docs/next/admin/actions/runner-installation/#nixos
 80      networking.firewall.trustedInterfaces =
 81        if (config.networking.nftables.enable)
 82        then ["br-*"]
 83        else ["br-+"];
 84
 85      services.forgejo-runner.instances =
 86        lib.mapAttrs (instance: instanceCfg: {
 87          enable = true;
 88          inherit (instanceCfg) name labels;
 89
 90          servers =
 91            lib.mapAttrs (server: serverCfg: {
 92              inherit (serverCfg) url uuid;
 93              tokenFile = "$CREDENTIALS_DIRECTORY/${server}-token";
 94              labels = lib.unique (instanceCfg.labels ++ (serverCfg.labels));
 95            })
 96            instanceCfg.servers;
 97
 98          settings = lib.mkMerge [
 99            {
100              cache = {
101                enabled = true;
102                # See https://forgejo.org/docs/latest/user/actions/advanced-features/#cache
103                # ONLY for podman backend
104                proxy_port = 4000;
105                actions_cache_url_override = "http://host.containers.internal:4000";
106              };
107              container = {
108                enable_ipv6 = true;
109                options = "--cap-add sys_admin --cap-add mknod --device /dev/fuse";
110              };
111            }
112            instanceCfg.extraSettings
113          ];
114        })
115        cfg.instances;
116
117      systemd.services = lib.mapAttrs' (instance: instanceCfg:
118        lib.nameValuePair "forgejo-runner-${instance}" {
119          serviceConfig.LoadCredential =
120            lib.map
121            (server: "${server}-token:${config.vaultix.secrets.${mkServerTokenSecretName instance server}.path}")
122            (lib.attrNames instanceCfg.servers);
123        })
124      cfg.instances;
125
126      vaultix.secrets = lib.mergeAttrsList (
127        lib.mapAttrsToList (instance: instanceCfg:
128          lib.mapAttrs' (
129            server: serverCfg:
130              lib.nameValuePair (mkServerTokenSecretName instance server) {
131                file = serverCfg.tokenFileAged;
132              }
133          )
134          instanceCfg.servers)
135        cfg.instances
136      );
137    };
138  };
139}