Merge #361424: refactor lib.packagesFromDirectoryRecursive (v2)
[NixPkgs.git] / nixos / modules / services / networking / legit.nix
blob2a4024a9fd286f036f56d0f4786001d79ff8ca57
2   config,
3   lib,
4   pkgs,
5   ...
6 }:
8 let
9   inherit (lib)
10     literalExpression
11     mkEnableOption
12     mkIf
13     mkOption
14     mkPackageOption
15     optionalAttrs
16     optional
17     types
18     ;
20   cfg = config.services.legit;
22   yaml = pkgs.formats.yaml { };
23   configFile = yaml.generate "legit.yaml" cfg.settings;
25   defaultStateDir = "/var/lib/legit";
26   defaultStaticDir = "${cfg.settings.repo.scanPath}/static";
27   defaultTemplatesDir = "${cfg.settings.repo.scanPath}/templates";
30   options.services.legit = {
31     enable = mkEnableOption "legit git web frontend";
33     package = mkPackageOption pkgs "legit-web" { };
35     user = mkOption {
36       type = types.str;
37       default = "legit";
38       description = "User account under which legit runs.";
39     };
41     group = mkOption {
42       type = types.str;
43       default = "legit";
44       description = "Group account under which legit runs.";
45     };
47     settings = mkOption {
48       default = { };
49       description = ''
50         The primary legit configuration. See the
51         [sample configuration](https://github.com/icyphox/legit/blob/master/config.yaml)
52         for possible values.
53       '';
54       type = types.submodule {
55         options.repo = {
56           scanPath = mkOption {
57             type = types.path;
58             default = defaultStateDir;
59             description = "Directory where legit will scan for repositories.";
60           };
61           readme = mkOption {
62             type = types.listOf types.str;
63             default = [ ];
64             description = "Readme files to look for.";
65           };
66           mainBranch = mkOption {
67             type = types.listOf types.str;
68             default = [
69               "main"
70               "master"
71             ];
72             description = "Main branch to look for.";
73           };
74           ignore = mkOption {
75             type = types.listOf types.str;
76             default = [ ];
77             description = "Repositories to ignore.";
78           };
79         };
80         options.dirs = {
81           templates = mkOption {
82             type = types.path;
83             default = "${pkgs.legit-web}/lib/legit/templates";
84             defaultText = literalExpression ''"''${pkgs.legit-web}/lib/legit/templates"'';
85             description = "Directories where template files are located.";
86           };
87           static = mkOption {
88             type = types.path;
89             default = "${pkgs.legit-web}/lib/legit/static";
90             defaultText = literalExpression ''"''${pkgs.legit-web}/lib/legit/static"'';
91             description = "Directories where static files are located.";
92           };
93         };
94         options.meta = {
95           title = mkOption {
96             type = types.str;
97             default = "legit";
98             description = "Website title.";
99           };
100           description = mkOption {
101             type = types.str;
102             default = "git frontend";
103             description = "Website description.";
104           };
105         };
106         options.server = {
107           name = mkOption {
108             type = types.str;
109             default = "localhost";
110             description = "Server name.";
111           };
112           host = mkOption {
113             type = types.str;
114             default = "127.0.0.1";
115             description = "Host address.";
116           };
117           port = mkOption {
118             type = types.port;
119             default = 5555;
120             description = "Legit port.";
121           };
122         };
123       };
124     };
125   };
127   config = mkIf cfg.enable {
128     users.groups = optionalAttrs (cfg.group == "legit") {
129       "${cfg.group}" = { };
130     };
132     users.users = optionalAttrs (cfg.user == "legit") {
133       "${cfg.user}" = {
134         group = cfg.group;
135         isSystemUser = true;
136       };
137     };
139     systemd.services.legit = {
140       description = "legit git frontend";
142       after = [ "network.target" ];
143       wantedBy = [ "multi-user.target" ];
144       restartTriggers = [ configFile ];
146       serviceConfig = {
147         Type = "simple";
148         User = cfg.user;
149         Group = cfg.group;
150         ExecStart = "${cfg.package}/bin/legit -config ${configFile}";
151         Restart = "always";
153         WorkingDirectory = cfg.settings.repo.scanPath;
154         StateDirectory =
155           [ ]
156           ++ optional (cfg.settings.repo.scanPath == defaultStateDir) "legit"
157           ++ optional (cfg.settings.dirs.static == defaultStaticDir) "legit/static"
158           ++ optional (cfg.settings.dirs.templates == defaultTemplatesDir) "legit/templates";
160         # Hardening
161         CapabilityBoundingSet = [ "" ];
162         DeviceAllow = [ "" ];
163         LockPersonality = true;
164         MemoryDenyWriteExecute = true;
165         NoNewPrivileges = true;
166         PrivateDevices = true;
167         PrivateTmp = true;
168         PrivateUsers = true;
169         ProcSubset = "pid";
170         ProtectClock = true;
171         ProtectControlGroups = true;
172         ProtectHome = true;
173         ProtectHostname = true;
174         ProtectKernelLogs = true;
175         ProtectKernelModules = true;
176         ProtectKernelTunables = true;
177         ProtectProc = "invisible";
178         ProtectSystem = "strict";
179         ReadWritePaths = cfg.settings.repo.scanPath;
180         RemoveIPC = true;
181         RestrictAddressFamilies = [
182           "AF_INET"
183           "AF_INET6"
184         ];
185         RestrictNamespaces = true;
186         RestrictRealtime = true;
187         RestrictSUIDSGID = true;
188         SystemCallArchitectures = "native";
189         SystemCallFilter = [
190           "@system-service"
191           "~@privileged"
192         ];
193         UMask = "0077";
194       };
195     };
196   };