{ config , lib , pkgs , ... }: let inherit (lib) pipe flatten concatMapAttrs 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 }: { "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"; }; }; }; createMirrorPath = name: { hostname, username }: { "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.instances.gitolite = { process = { user = "gitolite"; group = "gitolite"; prefork = 2; }; socket = { type = "tcp6"; address = "[::1]:9000"; }; }; services.gitolite = { enable = true; adminPubkey = "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHYUyDdw92TNXguAxcmcmZmn/7ECGdRp6ckjxU+5zCw3BCnsS5+xEvHBVnnFdJRoH2XpfMeJjE+fi67zFVhlbn4= root@secretive.marvin"; 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' ); push( @{$RC{ENABLE}}, 'repo-specific-hooks' ); ''; }; 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.instances.gitolite; fcgisocket = "${fcgi.socket.type}/${fcgi.socket.address}"; 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} { request_buffers 4k 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 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} ''; }; }; systemd.services = concatMapAttrs createMirrorService mirrors; systemd.paths = concatMapAttrs createMirrorPath mirrors; systemd.targets.git-mirroring = { wantedBy = [ "multi-user.target" ]; wants = pipe repoMirrors [ (mapAttrsToList mkMirrorWants) flatten ]; }; }