all repos

mugit @ 474cf87d8e81244720fa4973f370643b8fc77df4

🐮 git server that your cow will love

mugit/flake.nix (view raw)

Oleksandr Smirnov Oleksandr Smirnov
olexsmir@gmail.com
nix: remove all the firewall related stuff, 2 months ago
1
{
2
  description = "a git server that your cow will love";
3
  inputs.nixpkgs.url = "github:NixOS/nixpkgs";
4
  outputs = { self, nixpkgs }:
5
    let
6
      systems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ];
7
      forAllSystems = f: nixpkgs.lib.genAttrs systems (system: f nixpkgs.legacyPackages.${system});
8
    in
9
      {
10
      packages = forAllSystems (pkgs:
11
        let version = self.rev or "dev";
12
        in {
13
          default = self.packages.${pkgs.stdenv.hostPlatform.system}.mugit;
14
          mugit = pkgs.buildGo126Module {
15
            pname = "mugit";
16
            version = version;
17
            src = ./.;
18
            vendorHash = "sha256-rnBcUcEN24Qul0Fljo7aQ9aholXDZuUgQhoyzhEC49E=";
19
            ldflags = [ "-s" "-w" "-X main.version=${version}" ];
20
            meta = with pkgs.lib; {
21
              homepage = "https://git.olexsmir.xyz/mugit";
22
              license = licenses.mit;
23
            };
24
          };
25
        }
26
      );
27
28
      nixosModules.default = { config, lib, pkgs, ... }:
29
        with lib;
30
        let
31
          cfg = config.services.mugit;
32
          format = pkgs.formats.yaml { };
33
          configFile = format.generate "config.yaml" cfg.config;
34
        in
35
        {
36
          options.services.mugit = {
37
            enable = mkEnableOption "mugit service";
38
39
            package = mkOption {
40
              type = types.package;
41
              default = self.packages.${pkgs.stdenv.hostPlatform.system}.mugit;
42
              defaultText = literalExpression "self.packages.\${pkgs.stdenv.hostPlatform.system}.mugit";
43
              description = "The mugit package to use.";
44
            };
45
46
            exposeCli = mkOption {
47
              type = types.bool;
48
              default = false;
49
              description = "Whether to expose a mugit CLI wrapper to all system users, runs as the mugit user/group.";
50
            };
51
52
            configFile = mkOption {
53
              type = types.nullOr types.path;
54
              default = null;
55
              description = "Path to an existing mugit configuration file. Mutually exclusive with `config`.";
56
            };
57
58
            user = mkOption {
59
              type = types.str;
60
              default = "mugit";
61
              description = "User account under which mugit runs.";
62
            };
63
64
            group = mkOption {
65
              type = types.str;
66
              default = "mugit";
67
              description = "Group under which mugit runs.";
68
            };
69
70
            config = mkOption {
71
              default = {};
72
              description = ''
73
                The primary mugit configuration.
74
                See [docs](https://github.com/olexsmir/mugit) for possible values.
75
              '';
76
              example = literalExpression ''
77
                {
78
                  meta.host = "git.example.org";
79
                  repo.dir = "/var/lib/mugit";
80
                  ssh = {
81
                    enable = true;
82
                    host_key = "/var/lib/mugit/key";
83
                  };
84
                }
85
              '';
86
              type = types.submodule {
87
                options.meta = {
88
                  title = mkOption {
89
                    type = types.str;
90
                    default = "mugit";
91
                    description = "Website title";
92
                  };
93
                  description = mkOption {
94
                    type = types.str;
95
                    default = "";
96
                    description = "Website description";
97
                  };
98
                  host = mkOption {
99
                    type = types.str;
100
                    default = "";
101
                    description = "Website CNAME (required)";
102
                  };
103
                };
104
                options.server = {
105
                  host = mkOption {
106
                    type = types.str;
107
                    default = "";
108
                    description = "Host address";
109
                  };
110
                  port = mkOption {
111
                    type = types.port;
112
                    default = 8080;
113
                    description = "Website port";
114
                  };
115
                };
116
                options.repo = {
117
                  dir = mkOption {
118
                    type = types.str;
119
                    default = "";
120
                    description = "Directory which mugit will scan for repositories (required)";
121
                  };
122
                  masters = mkOption {
123
                    type = types.listOf types.str;
124
                    default = ["master" "main"];
125
                    description = "Master branch to look for";
126
                  };
127
                  readmes = mkOption {
128
                    type = types.listOf types.str;
129
                    default = ["README.md" "readme.md" "README.html" "readme.html" "README.txt" "readme.txt" "readme"];
130
                    description = "Readme files to look for";
131
                  };
132
                };
133
                options.ssh = {
134
                  enable = mkOption {
135
                    type = types.bool;
136
                    default = false;
137
                    description = "Wharever to run ssh server";
138
                  };
139
                  user = mkOption {
140
                    type = types.str;
141
                    default = "git";
142
                    description = "User used for git access";
143
                  };
144
                  port = mkOption {
145
                    type = types.port;
146
                    default = 2222;
147
                    description = "Website port";
148
                  };
149
                  host_key = mkOption {
150
                    type = types.str;
151
                    default = "";
152
                    description = "Path to ssh private key (required if ssh enabled)";
153
                  };
154
                  keys = mkOption {
155
                    type = types.listOf types.str;
156
                    default = [];
157
                    description = "List of public ssh keys which are allows to do git pushes, and access private repositories";
158
                  };
159
                };
160
                options.mirror = {
161
                  enable = mkOption {
162
                    type = types.bool;
163
                    default = false;
164
                    description = "Wharever to run mirroring worker";
165
                  };
166
                  interval = mkOption {
167
                    type = types.str;
168
                    default = "8h";
169
                    description = "Interval in which mirroring will happen";
170
                  };
171
                  github_token = mkOption {
172
                    type = types.str;
173
                    default = "";
174
                    description = "Github token for pulling from github repos";
175
                  };
176
                };
177
                options.cache = {
178
                  home_page = mkOption {
179
                    type = types.str;
180
                    default = "5m";
181
                    description = "For how long index page is cached";
182
                  };
183
                  readme = mkOption {
184
                    type = types.str;
185
                    default = "1m";
186
                    description = "For how long repos readme is cached";
187
                  };
188
                };
189
              };
190
            };
191
          };
192
193
          config = mkIf cfg.enable {
194
            users.users.${cfg.user} = {
195
              isSystemUser = true;
196
              group = cfg.group;
197
              home = cfg.config.repo.dir;
198
              createHome = true;
199
              description = "mugit service user";
200
            };
201
202
            users.groups.${cfg.group} = { };
203
204
            environment.systemPackages = lib.mkIf cfg.exposeCli [
205
              (pkgs.runCommandLocal "mugit-completions" {} ''
206
                mkdir -p $out/share/bash-completion/completions
207
                mkdir -p $out/share/zsh/site-functions
208
                mkdir -p $out/share/fish/vendor_completions.d
209
                ${cfg.package}/bin/mugit completion bash > $out/share/bash-completion/completions/mugit
210
                ${cfg.package}/bin/mugit completion zsh  > $out/share/zsh/site-functions/_mugit
211
                ${cfg.package}/bin/mugit completion fish > $out/share/fish/vendor_completions.d/mugit.fish
212
              '')
213
            ];
214
215
            security.wrappers = lib.mkIf cfg.exposeCli {
216
              mugit = {
217
                source =
218
                  let
219
                    resolvedConfig = if cfg.configFile != null then cfg.configFile else configFile;
220
                    mugitWrapped = pkgs.writeScriptBin "mugit" ''
221
                      #!${pkgs.bash}/bin/bash
222
                      exec ${cfg.package}/bin/mugit --config ${resolvedConfig} "$@"
223
                    '';
224
                  in
225
                  "${mugitWrapped}/bin/mugit";
226
                owner = cfg.user;
227
                group = cfg.group;
228
                setuid = true;
229
                setgid = true;
230
                permissions = "u+rx,g+rx,o+rx";
231
              };
232
            };
233
234
            systemd.services.mugit = {
235
              description = "mugit service";
236
              wantedBy = [ "multi-user.target" ];
237
              after = [ "network.target" ];
238
              path = [ pkgs.git ];
239
              serviceConfig = {
240
                Type = "simple";
241
                User = cfg.user;
242
                Group = cfg.group;
243
                WorkingDirectory = cfg.config.repo.dir;
244
                StateDirectory = "mugit";
245
                ExecStart = "${cfg.package}/bin/mugit serve --config ${configFile}";
246
                Restart = "on-failure";
247
                RestartSec = "5s";
248
                NoNewPrivileges = true;
249
                PrivateTmp = true;
250
                ProtectSystem = "strict";
251
                ProtectHome = true;
252
                ReadWritePaths = [ cfg.config.repo.dir ];
253
                ProtectKernelTunables = true;
254
                ProtectKernelModules = true;
255
                ProtectControlGroups = true;
256
              } // lib.optionalAttrs (cfg.config.ssh.enable && cfg.config.ssh.port < 1024) {
257
                AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ];
258
              };
259
            };
260
          };
261
        };
262
    };
263
}