add initial NixOS module
4 files changed, 254 insertions(+), 40 deletions(-)
M default.nix → default.nix
@@ -1,41 +1,6 @@ -{ pkgs ? ( - let - sources = import ./nix/default.nix; - in - import sources.nixpkgs { - overlays = [ - (import "${sources.gomod2nix}/overlay.nix") - ]; - } - ) -}: -let - inherit (pkgs) buildGoApplication lib nixosTests; -in -buildGoApplication { - pname = "elgit"; - version = "unstable-2025-03-30"; - - src = ./.; - modules = ./nix/gomod2nix.toml; - - vendorHash = "sha256-NrJXVOfWcxm9Jt6++d2x2uS5AGEJ7plJK4ZnbFC4GTg="; - - postInstall = '' - mkdir -p $out/lib/elgit/templates - mkdir -p $out/lib/elgit/static - - cp -r $src/templates/* $out/lib/elgit/templates - cp -r $src/static/* $out/lib/elgit/static - ''; - - passthru.tests = { inherit (nixosTests) legit; }; - - meta = { - description = "Web frontend for git"; - homepage = "https://elgit.alanpearce.eu/elgit"; - license = lib.licenses.mit; - maintainers = [ lib.maintainers.alanpearce ]; - mainProgram = "elgit"; - }; +{ + imports = [ + ./nix/overlay.nix + ./nix/nixos-module.nix + ]; }
A nix/nixos-module.nix
@@ -0,0 +1,195 @@ +{ config +, lib +, pkgs +, ... +}: + +let + inherit (lib) + literalExpression + mkEnableOption + mkIf + mkOption + mkPackageOption + optionalAttrs + optional + types + ; + + cfg = config.services.elgit; + + yaml = pkgs.formats.yaml { }; + configFile = yaml.generate "elgit.yaml" cfg.settings; + + defaultStateDir = "/var/lib/elgit"; + defaultStaticDir = "${defaultStateDir}/static"; +in +{ + options.services.elgit = { + enable = mkEnableOption "elgit git web frontend"; + + package = mkPackageOption pkgs "elgit" { }; + + user = mkOption { + type = types.str; + default = "elgit"; + description = "User account under which elgit runs."; + }; + + group = mkOption { + type = types.str; + default = "elgit"; + description = "Group account under which elgit runs."; + }; + + settings = mkOption { + default = { }; + description = '' + The primary elgit configuration. See the + [sample configuration](https://github.com/icyphox/elgit/blob/master/config.yaml) + for possible values. + ''; + type = types.submodule { + freeformType = yaml.type; + options.repo = { + root = mkOption { + type = types.path; + default = defaultStateDir; + description = "Directory where elgit 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."; + }; + unlisted = mkOption { + type = types.listOf types.str; + default = [ ]; + description = "Repositories to hide from index."; + }; + }; + options.dirs = { + static = mkOption { + type = types.path; + default = "${pkgs.elgit}/lib/elgit/static"; + defaultText = literalExpression ''"''${pkgs.elgit}/lib/elgit/static"''; + description = "Directories where static files are located."; + }; + }; + options.meta = { + title = mkOption { + type = types.str; + default = "elgit"; + description = "Website title."; + }; + description = mkOption { + type = types.str; + default = "git frontend"; + description = "Website description."; + }; + syntaxHighlight = mkOption { + type = types.nullOr types.str; + default = null; + example = "monokailight"; + description = "Syntax highlighting theme."; + }; + }; + 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 = "elgit port."; + }; + }; + }; + }; + }; + + config = mkIf cfg.enable { + users.groups = optionalAttrs (cfg.group == "elgit") { + "${cfg.group}" = { }; + }; + + users.users = optionalAttrs (cfg.user == "elgit") { + "${cfg.user}" = { + group = cfg.group; + isSystemUser = true; + }; + }; + + systemd.services.elgit = { + description = "elgit git frontend"; + + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + restartTriggers = [ configFile ]; + + serviceConfig = { + Type = "simple"; + User = cfg.user; + Group = cfg.group; + ExecStart = "${cfg.package}/bin/elgit -config ${configFile}"; + Restart = "always"; + + WorkingDirectory = cfg.settings.repo.root; + StateDirectory = + [ ] + ++ optional (cfg.settings.repo.root == defaultStateDir) "elgit" + ++ optional (cfg.settings.dirs.static == defaultStaticDir) "elgit/static"; + + # 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.root; + RemoveIPC = true; + RestrictAddressFamilies = [ + "AF_INET" + "AF_INET6" + ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ + "@system-service" + "~@privileged" + ]; + UMask = "0077"; + }; + }; + }; +}
A nix/overlay.nix
@@ -0,0 +1,12 @@ +{ + nixpkgs.overlays = + let + sources = import ./default.nix; + in + [ + (import "${sources.gomod2nix}/overlay.nix") + (self: super: { + elgit = super.callPackage ./package { }; + }) + ]; +}
A nix/package/default.nix
@@ -0,0 +1,42 @@ +{ pkgs ? ( + let + sources = import ../default.nix; + in + import sources.nixpkgs { + overlays = [ + (import "${sources.gomod2nix}/overlay.nix") + ]; + } + ) +, buildGoApplication ? pkgs.buildGoApplication +}: +let + inherit (pkgs) lib nixosTests; +in +buildGoApplication { + pname = "elgit"; + version = "0.1"; + + src = ../..; + modules = ../gomod2nix.toml; + + vendorHash = "sha256-NrJXVOfWcxm9Jt6++d2x2uS5AGEJ7plJK4ZnbFC4GTg="; + + postInstall = '' + mkdir -p $out/lib/elgit/templates + mkdir -p $out/lib/elgit/static + + cp -r $src/templates/* $out/lib/elgit/templates + cp -r $src/static/* $out/lib/elgit/static + ''; + + passthru.tests = { inherit (nixosTests) legit; }; + + meta = { + description = "Web frontend for git"; + homepage = "https://elgit.alanpearce.eu/elgit"; + license = lib.licenses.mit; + maintainers = [ lib.maintainers.alanpearce ]; + mainProgram = "elgit"; + }; +}