Unverified Commit 1f278a20 authored by OTABI Tomoya's avatar OTABI Tomoya Committed by GitHub
Browse files

Merge pull request #318384 from NyCodeGHG/nixos/renovate

nixos/renovate: init
parents e913ae34 dd8e2c72
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -14,6 +14,8 @@

- [Quickwit](https://quickwit.io), sub-second search & analytics engine on cloud storage. Available as [services.quickwit](options.html#opt-services.quickwit).

- [Renovate](https://github.com/renovatebot/renovate), a dependency updating tool for various git forges and language ecosystems. Available as [services.renovate](#opt-services.renovate.enable).

## Backward Incompatibilities {#sec-release-24.11-incompatibilities}

- `nginx` package no longer includes `gd` and `geoip` dependencies. For enabling it, override `nginx` package with the optionals `withImageFilter` and `withGeoIP`.
+1 −0
Original line number Diff line number Diff line
@@ -794,6 +794,7 @@
  ./services/misc/radarr.nix
  ./services/misc/readarr.nix
  ./services/misc/redmine.nix
  ./services/misc/renovate.nix
  ./services/misc/ripple-data-api.nix
  ./services/misc/rippled.nix
  ./services/misc/rmfakecloud.nix
+153 −0
Original line number Diff line number Diff line
{
  config,
  lib,
  pkgs,
  ...
}:
let
  inherit (lib)
    mkEnableOption
    mkPackageOption
    mkOption
    types
    mkIf
    ;
  json = pkgs.formats.json { };
  cfg = config.services.renovate;
  generateValidatedConfig =
    name: value:
    pkgs.callPackage (
      { runCommand, jq }:
      runCommand name
        {
          nativeBuildInputs = [
            jq
            cfg.package
          ];
          value = builtins.toJSON value;
          passAsFile = [ "value" ];
          preferLocalBuild = true;
        }
        ''
          jq . "$valuePath"> $out
          renovate-config-validator $out
        ''
    ) { };
  generateConfig = if cfg.validateSettings then generateValidatedConfig else json.generate;
in
{
  meta.maintainers = with lib.maintainers; [ marie natsukium ];

  options.services.renovate = {
    enable = mkEnableOption "renovate";
    package = mkPackageOption pkgs "renovate" { };
    schedule = mkOption {
      type = with types; nullOr str;
      description = "How often to run renovate. See {manpage}`systemd.time(7)` for the format.";
      example = "*:0/10";
      default = null;
    };
    credentials = mkOption {
      type = with types; attrsOf path;
      description = ''
        Allows configuring environment variable credentials for renovate, read from files.
        This should always be used for passing confidential data to renovate.
      '';
      example = {
        RENOVATE_TOKEN = "/etc/renovate/token";
      };
      default = { };
    };
    runtimePackages = mkOption {
      type = with types; listOf package;
      description = "Packages available to renovate.";
      default = [ ];
    };
    validateSettings = mkOption {
      type = types.bool;
      default = true;
      description = "Weither to run renovate's config validator on the built configuration.";
    };
    settings = mkOption {
      type = json.type;
      default = { };
      example = {
        platform = "gitea";
        endpoint = "https://git.example.com";
        gitAuthor = "Renovate <renovate@example.com>";
      };
      description = ''
        Renovate's global configuration.
        If you want to pass secrets to renovate, please use {option}`services.renovate.credentials` for that.
      '';
    };
  };

  config = mkIf cfg.enable {
    services.renovate.settings = {
      cacheDir = "/var/cache/renovate";
      baseDir = "/var/lib/renovate";
    };

    systemd.services.renovate = {
      description = "Renovate dependency updater";
      documentation = [ "https://docs.renovatebot.com/" ];
      after = [ "network.target" ];
      startAt = lib.optional (cfg.schedule != null) cfg.schedule;
      path = [
        config.systemd.package
        pkgs.git
      ] ++ cfg.runtimePackages;

      serviceConfig = {
        Type = "oneshot";
        User = "renovate";
        Group = "renovate";
        DynamicUser = true;
        LoadCredential = lib.mapAttrsToList (name: value: "SECRET-${name}:${value}") cfg.credentials;
        RemainAfterExit = false;
        Restart = "on-failure";
        CacheDirectory = "renovate";
        StateDirectory = "renovate";

        # Hardening
        CapabilityBoundingSet = [ "" ];
        DeviceAllow = [ "" ];
        LockPersonality = true;
        PrivateDevices = true;
        PrivateUsers = true;
        ProcSubset = "pid";
        ProtectClock = true;
        ProtectControlGroups = true;
        ProtectHome = true;
        ProtectHostname = true;
        ProtectKernelLogs = true;
        ProtectKernelModules = true;
        ProtectKernelTunables = true;
        ProtectProc = "invisible";
        RestrictAddressFamilies = [
          "AF_INET"
          "AF_INET6"
        ];
        RestrictNamespaces = true;
        RestrictRealtime = true;
        SystemCallArchitectures = "native";
        UMask = "0077";
      };

      script = ''
        ${lib.concatStringsSep "\n" (
          builtins.map (name: "export ${name}=$(systemd-creds cat 'SECRET-${name}')") (
            lib.attrNames cfg.credentials
          )
        )}
        exec ${lib.escapeShellArg (lib.getExe cfg.package)}
      '';

      environment = {
        RENOVATE_CONFIG_FILE = generateConfig "renovate-config.json" cfg.settings;
        HOME = "/var/lib/renovate";
      };
    };
  };
}
+1 −0
Original line number Diff line number Diff line
@@ -803,6 +803,7 @@ in {
  redis = handleTest ./redis.nix {};
  redlib = handleTest ./redlib.nix {};
  redmine = handleTest ./redmine.nix {};
  renovate = handleTest ./renovate.nix {};
  restartByActivationScript = handleTest ./restart-by-activation-script.nix {};
  restic-rest-server = handleTest ./restic-rest-server.nix {};
  restic = handleTest ./restic.nix {};
+69 −0
Original line number Diff line number Diff line
import ./make-test-python.nix (
  { pkgs, ... }:
  {
    name = "renovate";
    meta.maintainers = with pkgs.lib.maintainers; [ marie natsukium ];

    nodes.machine =
      { config, ... }:
      {
        services.renovate = {
          enable = true;
          settings = {
            platform = "gitea";
            endpoint = "http://localhost:3000";
            autodiscover = true;
            gitAuthor = "Renovate <renovate@example.com>";
          };
          credentials = {
            RENOVATE_TOKEN = "/etc/renovate-token";
          };
        };
        environment.systemPackages = [
          config.services.forgejo.package
          pkgs.tea
          pkgs.git
        ];
        services.forgejo = {
          enable = true;
          settings.server.HTTP_PORT = 3000;
        };
      };

    testScript = ''
      def gitea(command):
        return machine.succeed(f"cd /var/lib/forgejo && sudo --user=forgejo GITEA_WORK_DIR=/var/lib/forgejo GITEA_CUSTOM=/var/lib/forgejo/custom gitea {command}")

      machine.wait_for_unit("forgejo.service")
      machine.wait_for_open_port(3000)

      machine.systemctl("stop forgejo.service")

      gitea("admin user create --username meow --email meow@example.com --password meow")

      machine.systemctl("start forgejo.service")
      machine.wait_for_unit("forgejo.service")
      machine.wait_for_open_port(3000)

      accessToken = gitea("admin user generate-access-token --raw --username meow --scopes all | tr -d '\n'")

      machine.succeed(f"tea login add --name default --user meow --token '{accessToken}' --password meow --url http://localhost:3000")
      machine.succeed("tea repo create --name kitty --init")
      machine.succeed("git config --global user.name Meow")
      machine.succeed("git config --global user.email meow@example.com")
      machine.succeed(f"git clone http://meow:{accessToken}@localhost:3000/meow/kitty.git /tmp/kitty")
      machine.succeed("echo '{ \"name\": \"meow\", \"version\": \"0.1.0\" }' > /tmp/kitty/package.json")
      machine.succeed("git -C /tmp/kitty add /tmp/kitty/package.json")
      machine.succeed("git -C /tmp/kitty commit -m 'add package.json'")
      machine.succeed("git -C /tmp/kitty push origin")

      machine.succeed(f"echo '{accessToken}' > /etc/renovate-token")
      machine.systemctl("start renovate.service")

      machine.succeed("tea pulls list --repo meow/kitty | grep 'Configure Renovate'")
      machine.succeed("tea pulls merge --repo meow/kitty 1")

      machine.systemctl("start renovate.service")
    '';
  }
)
Loading