{ config , lib , pkgs , ... }: let inherit (builtins) mapAttrs attrValues; inherit (lib) pipe flatten mergeAttrsList mapAttrsToList; inherit (import ../../../lib/caddy.nix { inherit lib; }) security-headers; repos = "${config.services.gitolite.dataDir}/repositories"; mirrors = { sourcehut = { hostname = "git.sr.ht"; username = "~alanpearce"; }; codeberg = { hostname = "codeberg.org"; username = "alanpearce"; }; github = { hostname = "github.com"; username = "alanpearce"; }; }; repoMirrors = { nixfiles = [ "sourcehut" ]; searchix = [ "sourcehut" ]; website = [ "sourcehut" ]; nix-packages = [ "sourcehut" "github" ]; zola-bearblog = [ "sourcehut" "codeberg" ]; }; createMirrorService = name: { hostname, username }: { services."mirror-to-${name}@" = { path = with pkgs; [ gitMinimal openssh ]; serviceConfig = { Type = "oneshot"; User = "gitolite"; WorkingDirectory = "${repos}/%i.git"; ExecStart = "${pkgs.gitMinimal}/bin/git push --mirror git@${hostname}:${username}/%i"; }; unitConfig = { # only mirror public repositories ConditionPathExists = "${repos}/%i.git/git-daemon-export-ok"; }; }; paths."mirror-to-${name}@" = { pathConfig = { PathChanged = "${repos}/%i.git/refs/heads"; StartLimitIntervalSec = "1h"; StartLimitBurst = 5; }; }; }; mkMirrorWants = repo: map (target: "mirror-to-${target}@${repo}.path"); in { services.fcgiwrap = { enable = true; user = "gitolite"; group = "gitolite"; preforkProcesses = 2; socketType = "tcp6"; socketAddress = "[::1]:9000"; }; services.gitolite = { enable = true; adminPubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII8VIII+598QOBxi/52O1Kb19RdUdX0aZmS1/dNoyqc5 alan@hetzner.strongbox"; extraGitoliteRc = '' $RC{UMASK} = 0027; $RC{LOG_EXTRA} = 0; $RC{HOSTNAME} = "${config.networking.hostName}"; $RC{LOCAL_CODE} = "$rc{GL_ADMIN_BASE}/local"; push( @{$RC{ENABLE}}, 'D' ); push( @{$RC{ENABLE}}, 'Shell alan' ); push( @{$RC{ENABLE}}, 'cgit' ); ''; }; services.legit = { enable = true; group = "gitolite"; settings = { server.name = "legit.alanpearce.eu"; dirs = { templates = "/srv/http/legit/src/templates"; }; repo = { scanPath = "/srv/http/legit/repos"; readme = [ "readme" "readme.md" "README.md" ]; }; }; }; services.gitDaemon = { enable = true; user = "gitolite"; group = "gitolite"; basePath = repos; }; services.caddy.virtualHosts = { "git.alanpearce.eu" = let fcgi = config.services.fcgiwrap; fcgisocket = "${fcgi.socketType}/${fcgi.socketAddress}"; in { useACMEHost = "alanpearce.eu"; extraConfig = '' root * ${pkgs.cgit-pink}/cgit/ encode zstd gzip ${security-headers { overrides.content-security-policy = { default-src = [ "none" ]; base-uri = [ "none" ]; style-src = [ "self" "unsafe-inline" ]; script-src = [ "self" "unsafe-inline" ]; form-action = [ "self" ]; connect-src = [ "self" ]; img-src = [ "https" ]; object-src = [ "none" ]; }; }} handle_path /custom/* { file_server { root /srv/http/cgit/ } } rewrite /robots.txt /assets/robots.txt handle_path /assets/* { file_server { hide cgit.cgi } } @git_http_backend path_regexp "^.*/(HEAD|info/refs|objects/info/[^/]+|git-upload-pack)$" handle @git_http_backend { reverse_proxy ${fcgisocket} { transport fastcgi { env SCRIPT_FILENAME ${pkgs.git}/libexec/git-core/git-http-backend env GIT_PROJECT_ROOT ${repos} } } } handle { reverse_proxy ${fcgisocket} { transport fastcgi { env SCRIPT_FILENAME {http.vars.root}/cgit.cgi env CGIT_CONFIG ${pkgs.writeText "cgitrc" '' head-include=/srv/http/cgit/responsive-cgit-css-master/head.html css=/custom/responsive-cgit-css-master/cgit.css virtual-root=/ logo= readme=:README.md source-filter=${pkgs.cgit-pink}/lib/cgit/filters/syntax-highlighting.py about-filter=${pkgs.cgit-pink}/lib/cgit/filters/about-formatting.sh enable-git-config=1 enable-index-owner=0 enable-index-links=1 enable-follow-links=0 enable-log-linecount=1 max-stats=year snapshots=tar.lz tar.zst zip cache-size=10240 enable-http-clone=1 enable-commit-graph=1 mimetype-file=${pkgs.nginx}/conf/mime.types section-from-path=1 noplainemail=1 repository-sort=age root-title=my personal projects clone-url=git://git.alanpearce.eu/$CGIT_REPO_URL https://git.alanpearce.eu/$CGIT_REPO_URL remove-suffix=1 strict-export=git-daemon-export-ok scan-path=${repos} ''} } } } ''; }; "legit.alanpearce.eu" = let server = config.services.legit.settings.server; in { useACMEHost = "alanpearce.eu"; extraConfig = '' encode zstd gzip handle_path /static/* { root * /srv/http/legit/src/static file_server } ${security-headers { overrides.content-security-policy = { default-src = [ "none" ]; base-uri = [ "none" ]; style-src = [ "self" ]; script-src = [ "none" ]; form-action = [ "self" ]; connect-src = [ "self" ]; img-src = [ "https" ]; object-src = [ "none" ]; }; }} reverse_proxy ${server.host}:${toString server.port} ''; }; }; programs.ssh = with pkgs; { knownHostsFiles = [ (writeText "github.keys" '' # github.com:22 SSH-2.0-babeld-05989c77 # github.com:22 SSH-2.0-babeld-05989c77 # github.com:22 SSH-2.0-babeld-05989c77 # github.com:22 SSH-2.0-babeld-05989c77 # github.com:22 SSH-2.0-babeld-05989c77 github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk= github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl '') (writeText "gitlab.keys" '' # gitlab.com:22 SSH-2.0-GitLab-SSHD # gitlab.com:22 SSH-2.0-GitLab-SSHD # gitlab.com:22 SSH-2.0-GitLab-SSHD # gitlab.com:22 SSH-2.0-GitLab-SSHD # gitlab.com:22 SSH-2.0-GitLab-SSHD gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9 gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY= gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf '') (writeText "codeberg.keys" '' # codeberg.org:22 SSH-2.0-OpenSSH_9.2p1 Debian-2+deb12u2 # codeberg.org:22 SSH-2.0-OpenSSH_9.2p1 Debian-2+deb12u2 # codeberg.org:22 SSH-2.0-OpenSSH_9.2p1 Debian-2+deb12u2 # codeberg.org:22 SSH-2.0-OpenSSH_9.2p1 Debian-2+deb12u2 # codeberg.org:22 SSH-2.0-OpenSSH_9.2p1 Debian-2+deb12u2 codeberg.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8hZi7K1/2E2uBX8gwPRJAHvRAob+3Sn+y2hxiEhN0buv1igjYFTgFO2qQD8vLfU/HT/P/rqvEeTvaDfY1y/vcvQ8+YuUYyTwE2UaVU5aJv89y6PEZBYycaJCPdGIfZlLMmjilh/Sk8IWSEK6dQr+g686lu5cSWrFW60ixWpHpEVB26eRWin3lKYWSQGMwwKv4LwmW3ouqqs4Z4vsqRFqXJ/eCi3yhpT+nOjljXvZKiYTpYajqUC48IHAxTWugrKe1vXWOPxVXXMQEPsaIRc2hpK+v1LmfB7GnEGvF1UAKnEZbUuiD9PBEeD5a1MZQIzcoPWCrTxipEpuXQ5Tni4mN codeberg.org ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBL2pDxWr18SoiDJCGZ5LmxPygTlPu+cCKSkpqkvCyQzl5xmIMeKNdfdBpfbCGDPoZQghePzFZkKJNR/v9Win3Sc= codeberg.org ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIVIC02vnjFyL+I4RHfvIGNtOgJMe769VTF1VR4EB3ZB '') (writeText "sr.ht.keys" '' # git.sr.ht:22 SSH-2.0-OpenSSH_9.6 # git.sr.ht:22 SSH-2.0-OpenSSH_9.6 # git.sr.ht:22 SSH-2.0-OpenSSH_9.6 # git.sr.ht:22 SSH-2.0-OpenSSH_9.6 # git.sr.ht:22 SSH-2.0-OpenSSH_9.6 git.sr.ht ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDZ+l/lvYmaeOAPeijHL8d4794Am0MOvmXPyvHTtrqvgmvCJB8pen/qkQX2S1fgl9VkMGSNxbp7NF7HmKgs5ajTGV9mB5A5zq+161lcp5+f1qmn3Dp1MWKp/AzejWXKW+dwPBd3kkudDBA1fa3uK6g1gK5nLw3qcuv/V4emX9zv3P2ZNlq9XRvBxGY2KzaCyCXVkL48RVTTJJnYbVdRuq8/jQkDRA8lHvGvKI+jqnljmZi2aIrK9OGT2gkCtfyTw2GvNDV6aZ0bEza7nDLU/I+xmByAOO79R1Uk4EYCvSc1WXDZqhiuO2sZRmVxa0pQSBDn1DB3rpvqPYW+UvKB3SOz git.sr.ht ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBCj6y+cJlqK3BHZRLZuM+KP2zGPrh4H66DacfliU1E2DHAd1GGwF4g1jwu3L8gOZUTIvUptqWTkmglpYhFp4Iy4= git.sr.ht ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMZvRd4EtM7R+IHVMWmDkVU3VLQTSwQDSAvW0t2Tkj60 '') ]; }; systemd = (pipe mirrors [ (mapAttrsToList createMirrorService) mergeAttrsList ]) // { targets.git-mirroring = { wantedBy = [ "multi-user.target" ]; wants = pipe repoMirrors [ (mapAttrsToList mkMirrorWants) flatten ]; }; }; }