kore / nixos / roles / git.nix82 lines · 2275B · raw
1{ config, lib, pkgs, ... }:
2
3let
4 inherit (config.kore) identities repos;
5 root = "/srv/git";
6
7 acl = pkgs.writeText "kore-git-acl" (lib.concatLines (lib.concatLists (lib.mapAttrsToList (repo: access:
8 map (id: "${repo} write ${id}") access.write
9 ++ map (id: "${repo} read ${id}") access.read
10 ) repos)));
11
12 kore-git = pkgs.writeShellApplication {
13 name = "kore-git";
14 runtimeInputs = [ pkgs.git pkgs.gnugrep ];
15 text = ''
16 id="$1"
17 cmd="''${SSH_ORIGINAL_COMMAND:-}"
18
19 deny() {
20 echo "kore-git: access denied" >&2
21 exit 1
22 }
23
24 verb="''${cmd%% *}"
25 case "$verb" in
26 git-upload-pack | git-upload-archive) perm="read" ;;
27 git-receive-pack) perm="write" ;;
28 *)
29 echo "kore-git: hi $id, shell access is not provided" >&2
30 exit 1
31 ;;
32 esac
33
34 path="''${cmd#"$verb" }"
35 path="''${path#\'}"
36 path="''${path%\'}"
37 path="''${path#/}"
38 path="''${path%/}"
39 path="''${path%.git}"
40
41 [[ "$path" =~ ^[A-Za-z0-9_][A-Za-z0-9._-]*(/[A-Za-z0-9_][A-Za-z0-9._-]*)*$ ]] || deny
42
43 grep -qFx "$path write $id" ${acl} \
44 || { [ "$perm" = read ] && grep -qFx "$path read $id" ${acl}; } \
45 || deny
46
47 exec git-shell -c "$verb '${root}/$path.git'"
48 '';
49 };
50
51 members = lib.unique (lib.concatLists (lib.mapAttrsToList (_: access: access.write ++ access.read) repos));
52in {
53 users.groups.git = {};
54 users.users.git = {
55 isSystemUser = true;
56 group = "git";
57 home = root;
58 createHome = true;
59 shell = pkgs.bash;
60
61 openssh.authorizedKeys.keys = lib.concatMap (id:
62 map (key: ''command="${kore-git}/bin/kore-git ${id}",restrict ${key}'') (identities.${id}.sshKeys or [])
63 ) members;
64 };
65
66 systemd.services.kore-git-repos = {
67 wantedBy = [ "multi-user.target" ];
68 after = [ "local-fs.target" ];
69 serviceConfig = {
70 Type = "oneshot";
71 User = "git";
72 Group = "git";
73 };
74 path = [ pkgs.git pkgs.coreutils ];
75 script = lib.concatMapStrings (repo: ''
76 if [ ! -d '${root}/${repo}.git' ]; then
77 mkdir -p "$(dirname '${root}/${repo}.git')"
78 git init --quiet --bare --initial-branch=main '${root}/${repo}.git'
79 fi
80 '') (lib.attrNames repos);
81 };
82}