at 25.11-pre 4.3 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7let 8 inherit (lib) 9 mkEnableOption 10 mkPackageOption 11 mkOption 12 types 13 mkIf 14 ; 15 json = pkgs.formats.json { }; 16 cfg = config.services.renovate; 17 generateValidatedConfig = 18 name: value: 19 pkgs.callPackage ( 20 { runCommand, jq }: 21 runCommand name 22 { 23 nativeBuildInputs = [ 24 jq 25 cfg.package 26 ]; 27 value = builtins.toJSON value; 28 passAsFile = [ "value" ]; 29 preferLocalBuild = true; 30 } 31 '' 32 jq . "$valuePath"> $out 33 renovate-config-validator $out 34 '' 35 ) { }; 36 generateConfig = if cfg.validateSettings then generateValidatedConfig else json.generate; 37in 38{ 39 meta.maintainers = with lib.maintainers; [ 40 marie 41 natsukium 42 ]; 43 44 options.services.renovate = { 45 enable = mkEnableOption "renovate"; 46 package = mkPackageOption pkgs "renovate" { }; 47 schedule = mkOption { 48 type = with types; nullOr str; 49 description = "How often to run renovate. See {manpage}`systemd.time(7)` for the format."; 50 example = "*:0/10"; 51 default = null; 52 }; 53 credentials = mkOption { 54 type = with types; attrsOf path; 55 description = '' 56 Allows configuring environment variable credentials for renovate, read from files. 57 This should always be used for passing confidential data to renovate. 58 ''; 59 example = { 60 RENOVATE_TOKEN = "/etc/renovate/token"; 61 }; 62 default = { }; 63 }; 64 runtimePackages = mkOption { 65 type = with types; listOf package; 66 description = "Packages available to renovate."; 67 default = [ ]; 68 }; 69 validateSettings = mkOption { 70 type = types.bool; 71 default = true; 72 description = "Whether to run renovate's config validator on the built configuration."; 73 }; 74 settings = mkOption { 75 type = json.type; 76 default = { }; 77 example = { 78 platform = "gitea"; 79 endpoint = "https://git.example.com"; 80 gitAuthor = "Renovate <renovate@example.com>"; 81 }; 82 description = '' 83 Renovate's global configuration. 84 If you want to pass secrets to renovate, please use {option}`services.renovate.credentials` for that. 85 ''; 86 }; 87 }; 88 89 config = mkIf cfg.enable { 90 services.renovate.settings = { 91 cacheDir = "/var/cache/renovate"; 92 baseDir = "/var/lib/renovate"; 93 }; 94 95 systemd.services.renovate = { 96 description = "Renovate dependency updater"; 97 documentation = [ "https://docs.renovatebot.com/" ]; 98 after = [ "network.target" ]; 99 startAt = lib.optional (cfg.schedule != null) cfg.schedule; 100 path = [ 101 config.systemd.package 102 pkgs.git 103 ] ++ cfg.runtimePackages; 104 105 serviceConfig = { 106 User = "renovate"; 107 Group = "renovate"; 108 DynamicUser = true; 109 LoadCredential = lib.mapAttrsToList (name: value: "SECRET-${name}:${value}") cfg.credentials; 110 CacheDirectory = "renovate"; 111 StateDirectory = "renovate"; 112 113 # Hardening 114 CapabilityBoundingSet = [ "" ]; 115 DeviceAllow = [ "" ]; 116 LockPersonality = true; 117 PrivateDevices = true; 118 PrivateUsers = true; 119 ProcSubset = "pid"; 120 ProtectClock = true; 121 ProtectControlGroups = true; 122 ProtectHome = true; 123 ProtectHostname = true; 124 ProtectKernelLogs = true; 125 ProtectKernelModules = true; 126 ProtectKernelTunables = true; 127 ProtectProc = "invisible"; 128 RestrictAddressFamilies = [ 129 "AF_INET" 130 "AF_INET6" 131 "AF_UNIX" 132 ]; 133 RestrictNamespaces = true; 134 RestrictRealtime = true; 135 SystemCallArchitectures = "native"; 136 UMask = "0077"; 137 }; 138 139 script = '' 140 ${lib.concatStringsSep "\n" ( 141 builtins.map (name: '' 142 ${name}="$(systemd-creds cat 'SECRET-${name}')" 143 export ${name} 144 '') (lib.attrNames cfg.credentials) 145 )} 146 exec ${lib.escapeShellArg (lib.getExe cfg.package)} 147 ''; 148 149 environment = { 150 RENOVATE_CONFIG_FILE = generateConfig "renovate-config.json" cfg.settings; 151 HOME = "/var/lib/renovate"; 152 }; 153 }; 154 }; 155}