diff --git a/flake.lock b/flake.lock index fd28b020..933fb47a 100644 --- a/flake.lock +++ b/flake.lock @@ -197,6 +197,32 @@ "type": "github" } }, + "entrance-exam": { + "inputs": { + "devshell": [ + "devshell" + ], + "flake-utils": [ + "flake-utils" + ], + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1747833382, + "narHash": "sha256-Y5wAdHAhjkFwS6Jg30fSR516q6EljREnAkjwV7tJz9Y=", + "ref": "refs/heads/main", + "rev": "284d8881f93be4d29bdb2aa5afa94fd6e8a59a8a", + "revCount": 10, + "type": "git", + "url": "https://git.chvp.be/chvp/entrance-exam" + }, + "original": { + "type": "git", + "url": "https://git.chvp.be/chvp/entrance-exam" + } + }, "flake-compat": { "flake": false, "locked": { @@ -461,6 +487,7 @@ "darwin": "darwin", "devshell": "devshell", "emacs-overlay": "emacs-overlay", + "entrance-exam": "entrance-exam", "flake-utils": "flake-utils", "home-manager": "home-manager", "nix-index-database": "nix-index-database", diff --git a/flake.nix b/flake.nix index 9550720f..bc200744 100644 --- a/flake.nix +++ b/flake.nix @@ -53,6 +53,14 @@ url = "github:nix-community/emacs-overlay"; inputs.nixpkgs.follows = "nixpkgs"; }; + entrance-exam = { + url = "git+https://git.chvp.be/chvp/entrance-exam"; + inputs = { + devshell.follows = "devshell"; + flake-utils.follows = "flake-utils"; + nixpkgs.follows = "nixpkgs"; + }; + }; flake-utils = { url = "github:numtide/flake-utils"; inputs.systems.follows = "systems"; @@ -95,7 +103,7 @@ }; }; - outputs = inputs@{ self, nixpkgs, accentor, accentor-api, accentor-web, agenix, darwin, devshell, emacs-overlay, flake-utils, home-manager, nix-index-database, nixos-mailserver, nur, tetris, www-chvp-be, ... }: + outputs = inputs@{ self, nixpkgs, accentor, accentor-api, accentor-web, agenix, darwin, devshell, emacs-overlay, entrance-exam, flake-utils, home-manager, nix-index-database, nixos-mailserver, nur, tetris, www-chvp-be, ... }: let patches = builtins.map (patch: ./patches + "/${patch}") (builtins.filter (x: x != ".keep") (builtins.attrNames (builtins.readDir ./patches))); # Avoid IFD if there are no patches @@ -118,6 +126,9 @@ (self: super: { tetris = tetris.packages.${self.system}.default; }) + (self: super: { + entrance-exam = entrance-exam.packages.${self.system}.default; + }) nur.overlays.default www-chvp-be.overlays.default ]; diff --git a/machines/marabethia/default.nix b/machines/marabethia/default.nix index 137297bb..233abbd2 100644 --- a/machines/marabethia/default.nix +++ b/machines/marabethia/default.nix @@ -41,6 +41,12 @@ fast = true; location = "elendel.vanpetegem.me"; } + { + path = "zroot/safe/services/entrance-exam"; + remotePath = "zdata/recv/marabethia/safe/services/entrance-exam"; + fast = true; + location = "elendel.vanpetegem.me"; + } { path = "zroot/safe/services/forgejo"; remotePath = "zdata/recv/marabethia/safe/services/forgejo"; @@ -92,6 +98,7 @@ enable = true; runner.enable = true; }; + entrance-exam.enable = true; mail.enable = true; matrix.enable = true; mumble.enable = true; diff --git a/machines/marabethia/hardware.nix b/machines/marabethia/hardware.nix index caba7e7f..f16fa6a5 100644 --- a/machines/marabethia/hardware.nix +++ b/machines/marabethia/hardware.nix @@ -65,6 +65,10 @@ device = "zroot/local/services/docker"; fsType = "zfs"; }; + "/var/lib/entrance-exam" = { + device = "zroot/safe/services/entrance-exam"; + fsType = "zfs"; + }; "/var/lib/forgejo" = { device = "zroot/safe/services/forgejo"; fsType = "zfs"; diff --git a/modules/nixos/services/default.nix b/modules/nixos/services/default.nix index d52b4cae..d63ffb3c 100644 --- a/modules/nixos/services/default.nix +++ b/modules/nixos/services/default.nix @@ -5,6 +5,7 @@ ./accentor ./containers ./data-access + ./entrance-exam ./git ./mail ./matrix diff --git a/modules/nixos/services/entrance-exam/default.nix b/modules/nixos/services/entrance-exam/default.nix new file mode 100644 index 00000000..e73762ca --- /dev/null +++ b/modules/nixos/services/entrance-exam/default.nix @@ -0,0 +1,120 @@ +{ config, lib, pkgs, ... }: + +{ + options.chvp.services.entrance-exam.enable = lib.mkOption { + default = false; + example = true; + }; + + config = lib.mkIf config.chvp.services.entrance-exam.enable ( + let + serverPackage = pkgs.entrance-exam; + gemsPackage = serverPackage.env; + environmentFile = config.age.secrets."passwords/services/entrance-exam".path; + home = "/var/lib/entrance-exam"; + env = { + BOOTSNAP_READONLY = "TRUE"; + PIDFILE = "/run/entrance-exam/server.pid"; + RACK_ENV = "production"; + RAILS_ENV = "production"; + RAILS_LOG_TO_STDOUT = "yes"; + RAILS_STORAGE_PATH = "${home}/storage"; + RAILS_DATABASE_PATH = "${home}/production.sqlite"; + RAILS_CACHE_DATABASE_PATH = "${home}/production_cache.sqlite"; + RAILS_QUEUE_DATABASE_PATH = "${home}/production_queue.sqlite"; + RUBY_ENABLE_YJIT = "1"; + SOLID_QUEUE_IN_PUMA = "1"; + }; + exports = lib.concatStringsSep + "\n" + (lib.mapAttrsToList (name: value: "export ${name}=\"${value}\"") env); + console = pkgs.writeShellScriptBin "entrance-exam-console" '' + ${exports} + export $(cat ${environmentFile} | xargs) + cd ${serverPackage} + ${gemsPackage}/bin/bundle exec rails c + ''; + shell = pkgs.writeShellScriptBin "entrance-exam-shell" '' + ${exports} + export $(cat ${environmentFile} | xargs) + export PATH="${gemsPackage}/bin/:$PATH" + cd ${serverPackage} + bash + ''; + in + { + environment.systemPackages = [ console shell ]; + systemd.tmpfiles.rules = [ + "d /run/entrance-exam 0755 entrance-exam entrance-exam -" + "d ${home}/storage 0755 entrance-exam entrance-exam -" + ]; + systemd.services = { + entrance-exam = { + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + environment = env; + path = [ gemsPackage gemsPackage.wrappedRuby ]; + serviceConfig = { + EnvironmentFile = environmentFile; + Type = "simple"; + User = "entrance-exam"; + Group = "entrance-exam"; + Restart = "on-failure"; + WorkingDirectory = serverPackage; + ExecStartPre = [ + "${gemsPackage}/bin/bundle exec rails db:migrate" + ]; + ExecStart = "${gemsPackage}/bin/puma -C ${serverPackage}/config/puma.rb"; + }; + }; + }; + users.users.entrance-exam = { + group = "entrance-exam"; + home = home; + createHome = true; + uid = 696; + }; + users.groups.entrance-exam.gid = 696; + + services.nginx = { + virtualHosts."vanpetegem.gent" = { + enableACME = true; + forceSSL = true; + root = "${serverPackage}/public"; + locations = { + "/" = { + tryFiles = "$uri @app"; + }; + "@app" = { + proxyPass = "http://localhost:3000"; + extraConfig = '' + proxy_set_header X-Forwarded-Ssl on; + client_max_body_size 40M; + ''; + }; + }; + }; + }; + + security.doas.extraRules = [ + { + users = [ "charlotte" ]; + noPass = true; + cmd = "entrance-exam-console"; + runAs = "entrance-exam"; + } + { + users = [ "charlotte" ]; + noPass = true; + cmd = "entrance-exam-shell"; + runAs = "entrance-exam"; + } + ]; + + age.secrets."passwords/services/entrance-exam" = { + file = ../../../../secrets/passwords/services/entrance-exam.age; + owner = "entrance-exam"; + }; + } + ); +} diff --git a/secrets.nix b/secrets.nix index e4b18bc5..28c27600 100644 --- a/secrets.nix +++ b/secrets.nix @@ -45,6 +45,8 @@ in "secrets/passwords/services/accentor.age".publicKeys = [ elendel ] ++ users; + "secrets/passwords/services/entrance-exam.age".publicKeys = [ marabethia ] ++ users; + "secrets/files/services/phone-push-url.age".publicKeys = hosts ++ users; "secrets/passwords/services/mail/charlotte_at_vanpetegem.be.age".publicKeys = [ marabethia ] ++ users; diff --git a/secrets/passwords/services/entrance-exam.age b/secrets/passwords/services/entrance-exam.age new file mode 100644 index 00000000..a5afe874 Binary files /dev/null and b/secrets/passwords/services/entrance-exam.age differ