modules/legit: enable free-form settings
2 files changed, 198 insertions(+), 0 deletions(-)
M modules/nixos/default.nix → modules/nixos/default.nix
@@ -3,4 +3,5 @@ # Add your NixOS modules here # # my-module = ./my-module; laminar = ./laminar.nix; + legit = ./legit.nix; }
A modules/nixos/legit.nix
@@ -0,0 +1,197 @@ +{ config +, lib +, pkgs +, ... +}: + +let + inherit (lib) + literalExpression + mkEnableOption + mkIf + mkOption + mkPackageOption + optionalAttrs + optional + types + ; + + cfg = config.services.legit; + + yaml = pkgs.formats.yaml { }; + configFile = yaml.generate "legit.yaml" cfg.settings; + + defaultStateDir = "/var/lib/legit"; + defaultStaticDir = "${cfg.settings.repo.scanPath}/static"; + defaultTemplatesDir = "${cfg.settings.repo.scanPath}/templates"; +in +{ + options.services.legit = { + enable = mkEnableOption "legit git web frontend"; + + package = mkPackageOption pkgs "legit-web" { }; + + user = mkOption { + type = types.str; + default = "legit"; + description = "User account under which legit runs."; + }; + + group = mkOption { + type = types.str; + default = "legit"; + description = "Group account under which legit runs."; + }; + + settings = mkOption { + default = { }; + description = '' + The primary legit configuration. See the + [sample configuration](https://github.com/icyphox/legit/blob/master/config.yaml) + for possible values. + ''; + type = types.submodule { + freeformType = yaml.type; + options.repo = { + scanPath = mkOption { + type = types.path; + default = defaultStateDir; + description = "Directory where legit will scan for repositories."; + }; + readme = mkOption { + type = types.listOf types.str; + default = [ ]; + description = "Readme files to look for."; + }; + mainBranch = mkOption { + type = types.listOf types.str; + default = [ + "main" + "master" + ]; + description = "Main branch to look for."; + }; + ignore = mkOption { + type = types.listOf types.str; + default = [ ]; + description = "Repositories to ignore."; + }; + }; + options.dirs = { + templates = mkOption { + type = types.path; + default = "${pkgs.legit-web}/lib/legit/templates"; + defaultText = literalExpression ''"''${pkgs.legit-web}/lib/legit/templates"''; + description = "Directories where template files are located."; + }; + static = mkOption { + type = types.path; + default = "${pkgs.legit-web}/lib/legit/static"; + defaultText = literalExpression ''"''${pkgs.legit-web}/lib/legit/static"''; + description = "Directories where static files are located."; + }; + }; + options.meta = { + title = mkOption { + type = types.str; + default = "legit"; + description = "Website title."; + }; + description = mkOption { + type = types.str; + default = "git frontend"; + description = "Website description."; + }; + }; + options.server = { + name = mkOption { + type = types.str; + default = "localhost"; + description = "Server name."; + }; + host = mkOption { + type = types.str; + default = "127.0.0.1"; + description = "Host address."; + }; + port = mkOption { + type = types.port; + default = 5555; + description = "Legit port."; + }; + }; + }; + }; + }; + + config = mkIf cfg.enable { + users.groups = optionalAttrs (cfg.group == "legit") { + "${cfg.group}" = { }; + }; + + users.users = optionalAttrs (cfg.user == "legit") { + "${cfg.user}" = { + group = cfg.group; + isSystemUser = true; + }; + }; + + systemd.services.legit = { + description = "legit git frontend"; + + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + restartTriggers = [ configFile ]; + + serviceConfig = { + Type = "simple"; + User = cfg.user; + Group = cfg.group; + ExecStart = "${cfg.package}/bin/legit -config ${configFile}"; + Restart = "always"; + + WorkingDirectory = cfg.settings.repo.scanPath; + StateDirectory = + [ ] + ++ optional (cfg.settings.repo.scanPath == defaultStateDir) "legit" + ++ optional (cfg.settings.dirs.static == defaultStaticDir) "legit/static" + ++ optional (cfg.settings.dirs.templates == defaultTemplatesDir) "legit/templates"; + + # Hardening + CapabilityBoundingSet = [ "" ]; + DeviceAllow = [ "" ]; + LockPersonality = true; + MemoryDenyWriteExecute = true; + NoNewPrivileges = true; + PrivateDevices = true; + PrivateTmp = true; + PrivateUsers = true; + ProcSubset = "pid"; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + ProtectSystem = "strict"; + ReadWritePaths = cfg.settings.repo.scanPath; + RemoveIPC = true; + RestrictAddressFamilies = [ + "AF_INET" + "AF_INET6" + ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ + "@system-service" + "~@privileged" + ]; + UMask = "0077"; + }; + }; + }; +}