{ lib, pkgs, config, ... }: { networking = { firewall.allowedTCPPorts = [ 22 80 443 ]; }; security.acme = { acceptTerms = true; defaults.email = "something@fediversity.eu"; }; age.secrets = lib.mapAttrs (_: group: { owner = "root"; inherit group; mode = "440"; }) { woodpecker-gitea-client = "woodpecker-server"; woodpecker-gitea-secret = "woodpecker-server"; woodpecker-agent-exec = "woodpecker-agent-exec"; woodpecker-agent-container = "woodpecker-agent-docker"; }; # needs `sudo generate-vars` vars.settings.on-machine.enable = true; vars.generators.woodpecker-agent-secret = { runtimeInputs = [ pkgs.openssl ]; files.my-secret.secret = true; script = '' openssl rand -hex 32 > "$out"/my-secret ''; }; vars.generators.woodpecker-rpc-secret = { runtimeInputs = with pkgs; [ coreutils bash ]; files.rpc-secret.secret = true; # wrap in bash command to prevent `vars`' pipefail aborting half-way script = '' bash -c "tr -dc 'A-Za-z0-9\!?%=' < /dev/urandom | head -c 32 > $out/rpc-secret" ''; }; vars.generators.woodpecker = let fileNames = [ "woodpecker-gitea-client" "woodpecker-gitea-secret" "woodpecker-agent-exec" "woodpecker-agent-container" ]; in { runtimeInputs = [ pkgs.coreutils pkgs.openssl ]; files = lib.genAttrs fileNames (_: { secret = true; }); script = '' ${lib.concatStringsSep "\n" ( lib.lists.map (file: ''cp ${config.age.secrets.${file}.path} "$out/"'') fileNames )} ''; }; vars.generators."templates" = rec { dependencies = [ "woodpecker" "woodpecker-agent-secret" "woodpecker-rpc-secret" ]; runtimeInputs = [ pkgs.coreutils pkgs.gnused ]; script = lib.concatStringsSep "\n" ( lib.mapAttrsToList (template: _: '' cp "$templates/${template}" "$out/${template}" echo "filling placeholders in template ${template}..." ${lib.concatStringsSep "\n" ( lib.lists.map (dependency: '' echo "filling placeholders in template ${template} from generator ${dependency}..." ${lib.concatStringsSep "\n" ( lib.mapAttrsToList ( parent: { placeholder, ... }: '' sed -i "s/${placeholder}/$(cat "$in/${dependency}/${parent}")/g" "$out/${template}" echo "- substituted ${parent}" '' ) config.vars.generators.${dependency}.files )} '') dependencies )} '') files ); # files."woodpecker-server.conf" = { # secret = true; # template = pkgs.writeText "woodpecker-server.conf" '' # WOODPECKER_DATABASE_DRIVER=sqlite3 # WOODPECKER_DISABLE_USER_AGENT_REGISTRATION=false # WOODPECKER_OPEN=false # WOODPECKER_ADMIN=kiara,fricklerhandwerk,niols # WOODPECKER_HOST=https://woodpecker.fediversity.eu # WOODPECKER_GITEA=true # WOODPECKER_GITEA_URL=https://git.fediversity.eu # WOODPECKER_GITEA_CLIENT_FILE=${config.vars.generators.woodpecker.files.woodpecker-gitea-client.placeholder} # WOODPECKER_GITEA_SECRET_FILE=${config.vars.generators.woodpecker.files.woodpecker-gitea-secret.placeholder} # WOODPECKER_AGENT_SECRET_FILE=${config.vars.generators.woodpecker-agent-secret.files.my-secret.placeholder} # WOODPECKER_GRPC_SECRET_FILE=${config.vars.generators.woodpecker-rpc-secret.files.rpc-secret.placeholder} # WOODPECKER_LOG_LEVEL=info # WOODPECKER_DEFAULT_CLONE_PLUGIN=docker.io/woodpeckerci/plugin-git # WOODPECKER_SERVER_ADDR=:8000 # WOODPECKER_GRPC_ADDR=:9000 # ''; # }; files = let shared = '' WOODPECKER_SERVER=localhost:9000 WOODPECKER_USERNAME=x-oauth-basic WOODPECKER_HOSTNAME=https://woodpecker.fediversity.eu WOODPECKER_MAX_WORKFLOWS=5 WOODPECKER_LOG_LEVEL=info WOODPECKER_DEBUG_PRETTY=false WOODPECKER_DEBUG_NOCOLOR=true WOODPECKER_HEALTHCHECK=false WOODPECKER_GRPC_VERIFY=false # TODO: fix WOODPECKER_GRPC_SECURE=false ''; in { "woodpecker-agent-exec.conf" = { secret = true; template = pkgs.writeText "woodpecker-agent-exec.conf" ( lib.concatStringsSep "\n" [ shared '' WOODPECKER_AGENT_SECRET=${config.vars.generators.woodpecker.files.woodpecker-agent-exec.placeholder} WOODPECKER_BACKEND=local WOODPECKER_AGENT_LABELS=type=local '' ] ); }; "woodpecker-agent-podman.conf" = { secret = true; template = pkgs.writeText "woodpecker-agent-podman.conf" ( lib.concatStringsSep "\n" [ shared '' WOODPECKER_AGENT_SECRET=${config.vars.generators.woodpecker.files.woodpecker-agent-container.placeholder} WOODPECKER_BACKEND=docker WOODPECKER_AGENT_LABELS=type=docker DOCKER_HOST=unix:///run/podman/podman.sock '' ] ); }; }; }; # enable git-lfs programs.git = { enable = true; lfs.enable = true; }; services = { nginx = { enable = true; recommendedProxySettings = true; recommendedOptimisation = true; recommendedTlsSettings = true; virtualHosts."woodpecker.fediversity.eu" = { enableACME = true; forceSSL = true; locations."/" = { recommendedProxySettings = true; proxyPass = "http://127.0.0.1:8000"; }; }; }; woodpecker-server = { enable = true; # environmentFile = config.vars.generators."templates".files."woodpecker-server.conf".path; # https://woodpecker-ci.org/docs/administration/configuration/server environment = { WOODPECKER_DATABASE_DRIVER = "sqlite3"; WOODPECKER_DISABLE_USER_AGENT_REGISTRATION = "false"; WOODPECKER_OPEN = "false"; WOODPECKER_ADMIN = "kiara,fricklerhandwerk,niols"; WOODPECKER_HOST = "https://woodpecker.fediversity.eu"; WOODPECKER_GITEA = "true"; WOODPECKER_GITEA_URL = "https://git.fediversity.eu"; WOODPECKER_GITEA_CLIENT_FILE = config.age.secrets.woodpecker-gitea-client.path; WOODPECKER_GITEA_SECRET_FILE = config.age.secrets.woodpecker-gitea-secret.path; WOODPECKER_AGENT_SECRET_FILE = config.vars.generators.woodpecker-agent-secret.files.my-secret.path; WOODPECKER_GRPC_SECRET_FILE = config.vars.generators.woodpecker-rpc-secret.files.rpc-secret.path; WOODPECKER_LOG_LEVEL = "info"; WOODPECKER_DEFAULT_CLONE_PLUGIN = "docker.io/woodpeckerci/plugin-git"; WOODPECKER_SERVER_ADDR = ":8000"; WOODPECKER_GRPC_ADDR = ":9000"; }; }; # https://woodpecker-ci.org/docs/administration/configuration/agent woodpecker-agents.agents = # let # shared = { # WOODPECKER_SERVER = "localhost:9000"; # # TODO: separate to agent-specific tokens? # # TODO: why will it only accept `WOODPECKER_AGENT_SECRET`, not `WOODPECKER_AGENT_SECRET_FILE`? # # WOODPECKER_AGENT_SECRET_FILE = config.vars.generators.woodpecker-agent-secret.files.my-secret.path; # WOODPECKER_USERNAME = "x-oauth-basic"; # WOODPECKER_HOSTNAME = "https://woodpecker.fediversity.eu"; # WOODPECKER_MAX_WORKFLOWS = "4"; # WOODPECKER_LOG_LEVEL = "info"; # WOODPECKER_DEBUG_PRETTY = "false"; # WOODPECKER_DEBUG_NOCOLOR = "true"; # WOODPECKER_GRPC_SECURE = "false"; # TODO: fix # WOODPECKER_GRPC_VERIFY = "false"; # WOODPECKER_HEALTHCHECK = "false"; # }; # in { # local exec = { enable = true; path = with pkgs; [ git git-lfs woodpecker-plugin-git bash coreutils nix attic-client ]; environmentFile = [ config.vars.generators."templates".files."woodpecker-agent-exec.conf".path ]; # # https://woodpecker-ci.org/docs/administration/configuration/backends/local#environment-variables # environment = lib.mkMerge [ # shared # { # WOODPECKER_BACKEND = "local"; # WOODPECKER_AGENT_LABELS = "type=local"; # WOODPECKER_AGENT_SECRET_FILE = config.age.secrets.woodpecker-agent-exec.path; # } # ]; }; # container docker = { enable = true; environmentFile = [ config.vars.generators."templates".files."woodpecker-agent-podman.conf".path ]; # # https://woodpecker-ci.org/docs/administration/configuration/backends/docker#environment-variables # environment = lib.mkMerge [ # shared # { # WOODPECKER_BACKEND = "docker"; # DOCKER_HOST = "unix:///run/podman/podman.sock"; # WOODPECKER_AGENT_LABELS = "type=docker"; # WOODPECKER_AGENT_SECRET_FILE = config.age.secrets.woodpecker-agent-container.path; # } # ]; }; }; }; networking.firewall.allowedTCPPorts = [ 22 80 443 ]; virtualisation.podman = { enable = true; autoPrune = { enable = true; dates = "weekly"; }; }; systemd.services.woodpecker-agent-docker = { wants = [ "podman.socket" ]; after = [ "podman.socket" ]; serviceConfig.SupplementaryGroups = [ "podman" ]; }; }