From 3a745690a57fd9c8588682808a0d64328c8b81e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=B6nig?= Date: Thu, 9 Jul 2026 07:43:50 +0200 Subject: [PATCH] chore: the nix stuff --- flake.lock | 27 ++++++++++++++ flake.nix | 42 +++++++++++++++++++++ nix/module.nix | 98 +++++++++++++++++++++++++++++++++++++++++++++++++ nix/package.nix | 52 ++++++++++++++++++++++++++ 4 files changed, 219 insertions(+) create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 nix/module.nix create mode 100644 nix/package.nix diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..a7355d3 --- /dev/null +++ b/flake.lock @@ -0,0 +1,27 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1783389287, + "narHash": "sha256-0xIy4dVLqq47rA+mRy0hXDfjhQd4E5PoIns/RmB7nR4=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "0ad6f47ea4fe188f4bc8f0380f93ae8523337c6c", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-26.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..74889d2 --- /dev/null +++ b/flake.nix @@ -0,0 +1,42 @@ +{ + description = "AZess - internal Active Directory user setup web application"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-26.05"; + }; + + outputs = { + self, + nixpkgs, + }: let + systems = [ + "x86_64-linux" + "aarch64-linux" + ]; + forAllSystems = nixpkgs.lib.genAttrs systems; + in { + packages = forAllSystems (system: let + pkgs = nixpkgs.legacyPackages.${system}; + azess = pkgs.callPackage ./nix/package.nix {}; + in { + inherit azess; + default = azess; + }); + + apps = forAllSystems (system: { + default = { + type = "app"; + program = "${nixpkgs.lib.getExe self.packages.${system}.default}"; + }; + azess = self.apps.${system}.default; + }); + + checks = forAllSystems (system: { + default = self.packages.${system}.default; + }); + + formatter = forAllSystems (system: nixpkgs.legacyPackages.${system}.alejandra); + + nixosModules.default = import ./nix/module.nix {inherit self;}; + }; +} diff --git a/nix/module.nix b/nix/module.nix new file mode 100644 index 0000000..a18e731 --- /dev/null +++ b/nix/module.nix @@ -0,0 +1,98 @@ +{self}: { + config, + lib, + pkgs, + ... +}: let + cfg = config.services.azess; + inherit (lib) mkEnableOption mkIf mkOption types; + + defaultPackage = self.packages.${pkgs.stdenv.hostPlatform.system}.default; + gunicornArgs = + [ + "--workers" + (toString cfg.workers) + "--bind" + "${cfg.host}:${toString cfg.port}" + ] + ++ cfg.extraArgs; +in { + options.services.azess = { + enable = mkEnableOption "AZess Flask/Gunicorn web application"; + + package = mkOption { + type = types.package; + default = defaultPackage; + defaultText = "self.packages.\${pkgs.stdenv.hostPlatform.system}.default"; + description = "AZess package to run."; + }; + + host = mkOption { + type = types.str; + default = "127.0.0.1"; + description = "Host/IP address Gunicorn binds to."; + }; + + port = mkOption { + type = types.port; + default = 8000; + description = "TCP port Gunicorn binds to."; + }; + + workers = mkOption { + type = types.ints.positive; + default = 4; + description = "Number of Gunicorn worker processes."; + }; + + openFirewall = mkOption { + type = types.bool; + default = false; + description = "Open the configured TCP port in the local firewall."; + }; + + extraArgs = mkOption { + type = types.listOf types.str; + default = []; + description = "Additional arguments passed to Gunicorn before app:app."; + }; + }; + + config = mkIf cfg.enable { + users.groups.azess = {}; + users.users.azess = { + isSystemUser = true; + group = "azess"; + description = "AZess service user"; + }; + + systemd.services.azess = { + description = "AZess Active Directory user setup application"; + wantedBy = ["multi-user.target"]; + after = ["network.target"]; + + environment = { + XDG_CACHE_HOME = "/var/cache/azess"; + }; + + serviceConfig = { + ExecStart = "${lib.getExe cfg.package} ${lib.escapeShellArgs gunicornArgs}"; + Restart = "on-failure"; + RestartSec = "5s"; + + User = "azess"; + Group = "azess"; + CacheDirectory = "azess"; + RuntimeDirectory = "azess"; + + NoNewPrivileges = true; + PrivateTmp = true; + ProtectHome = true; + ProtectSystem = "strict"; + RestrictAddressFamilies = ["AF_UNIX" "AF_INET" "AF_INET6"]; + }; + }; + + networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [cfg.port]; + }; +} diff --git a/nix/package.nix b/nix/package.nix new file mode 100644 index 0000000..c2f8d0c --- /dev/null +++ b/nix/package.nix @@ -0,0 +1,52 @@ +{ + lib, + python3, + stdenvNoCC, +}: let + pythonEnv = python3.withPackages (ps: [ + ps.flask + ps.gunicorn + ps.weasyprint + ]); +in + stdenvNoCC.mkDerivation { + pname = "azess"; + version = "0.1.0"; + + src = lib.fileset.toSource { + root = ../.; + fileset = lib.fileset.unions [ + ../app.py + ../templates + ../README.md + ../requirements.txt + ]; + }; + + dontBuild = true; + + installPhase = '' + runHook preInstall + + mkdir -p $out/bin $out/share/azess + cp app.py $out/share/azess/ + cp -r templates $out/share/azess/ + cp README.md requirements.txt $out/share/azess/ + + cat > $out/bin/azess <