diff options
author | Benedikt Peetz <benedikt.peetz@b-peetz.de> | 2025-06-06 21:34:09 +0200 |
---|---|---|
committer | Benedikt Peetz <benedikt.peetz@b-peetz.de> | 2025-06-06 21:34:09 +0200 |
commit | c5f4fd12735673831ead5faca8d9ad410d77a938 (patch) | |
tree | bbdeb8c5e328740f4ff64a001e0ce9e33f450900 | |
parent | fix(back::web::main): Pretty print error, on failed connection accept (diff) | |
download | back-c5f4fd12735673831ead5faca8d9ad410d77a938.zip |
feat(flake): Export the module and ensure that it works with a test
-rw-r--r-- | flake.nix | 17 | ||||
-rw-r--r-- | nix/module.nix | 41 | ||||
-rw-r--r-- | nix/package.nix | 1 | ||||
-rw-r--r-- | tests/base.nix | 296 |
4 files changed, 139 insertions, 216 deletions
diff --git a/flake.nix b/flake.nix index b6df3c8..cf3fd77 100644 --- a/flake.nix +++ b/flake.nix @@ -38,14 +38,19 @@ flake-utils, treefmt-nix, ... - }: - flake-utils.lib.eachDefaultSystem (system: let - pkgs = nixpkgs.legacyPackages."x86_64-linux"; + }: let + pkgs = nixpkgs.legacyPackages."x86_64-linux"; + back = pkgs.callPackage ./nix/package.nix {}; + module = import ./nix/module.nix {extraPackages = {inherit back;};}; + in + (flake-utils.lib.eachDefaultSystem (system: let treefmtEval = import ./treefmt.nix { inherit treefmt-nix pkgs; }; + nixos-lib = import (nixpkgs + "/nixos/lib") {}; + rustfmt = pkgs.writeShellScriptBin "rustfmt" '' # Avoid the duplicated edition flag, that rust-analyzer passes. if [ "$1" = "--edition" ] && [ "$2" == "2024" ]; then @@ -57,6 +62,7 @@ in { checks = { formatting = treefmtEval.config.build.check self; + nixos = pkgs.callPackage ./tests/base.nix {inherit module nixos-lib;}; }; formatter = treefmtEval.config.build.wrapper; @@ -75,7 +81,10 @@ pkgs.reuse ]; }; - }); + })) + // { + nixosModules.default = module; + }; } # vim: ts=2 diff --git a/nix/module.nix b/nix/module.nix index eb1257c..82a6bd3 100644 --- a/nix/module.nix +++ b/nix/module.nix @@ -8,21 +8,34 @@ # # You should have received a copy of the License along with this program. # If not, see <https://www.gnu.org/licenses/agpl.txt>. -{ +{extraPackages}: { config, lib, - vhackPackages, pkgs, ... }: let cfg = config.vhack.back; in { options.vhack.back = { - enable = lib.mkEnableOption "Back issue tracker (inspired by TVL's panettone)"; + enable = lib.mkEnableOption "Back"; - domain = lib.mkOption { + package = lib.mkPackageOption extraPackages "back" {}; + + group = lib.mkOption { + type = lib.types.str; + description = '' + The group to run back under. + + This group needs read and write access to the git repositories. + ''; + }; + user = lib.mkOption { type = lib.types.str; - description = "The domain to host this `back` instance on."; + description = '' + The user to run back under. + + This user needs read and write access to the git repositories. + ''; }; settings = { @@ -44,7 +57,6 @@ in { root_url = lib.mkOption { type = lib.types.str; description = "The url to this instance of back."; - default = "https://${cfg.domain}"; }; }; }; @@ -57,19 +69,19 @@ in { wantedBy = ["default.target"]; serviceConfig = { - ExecStart = "${lib.getExe vhackPackages.back} ${(pkgs.formats.json {}).generate "config.json" cfg.settings}"; + ExecStart = "${lib.getExe cfg.package} ${(pkgs.formats.json {}).generate "config.json" cfg.settings}"; # Ensure that the service can read the repository # FIXME(@bpeetz): This has the implied assumption, that all the exposed git # repositories are readable for the git group. This should not be necessary. <2024-12-23> - User = "git"; - Group = "git"; + Group = cfg.group; + User = cfg.user; - DynamicUser = true; Restart = "always"; # Sandboxing ProtectSystem = "strict"; + ReadWritePaths = ["${cfg.settings.scan_path}"]; ProtectHome = true; PrivateTmp = true; PrivateDevices = true; @@ -89,15 +101,8 @@ in { PrivateMounts = true; # System Call Filtering SystemCallArchitectures = "native"; - SystemCallFilter = ["~@cpu-emulation @debug @keyring @mount @obsolete @privileged @setuid"]; + SystemCallFilter = []; }; }; - - services.nginx.virtualHosts."${cfg.domain}" = { - locations."/".proxyPass = "http://127.0.0.1:8000"; - - enableACME = true; - forceSSL = true; - }; }; } diff --git a/nix/package.nix b/nix/package.nix index b974ea2..bbcf981 100644 --- a/nix/package.nix +++ b/nix/package.nix @@ -33,5 +33,6 @@ rustPlatform.buildRustPackage { meta = { mainProgram = "back"; + description = "An extremely simple git bug visualization system. Inspired by TVL's panettone"; }; } diff --git a/tests/base.nix b/tests/base.nix index 5aebe6a..4c033c1 100644 --- a/tests/base.nix +++ b/tests/base.nix @@ -9,208 +9,116 @@ # You should have received a copy of the License along with this program. # If not, see <https://www.gnu.org/licenses/agpl.txt>. { - nixos-lib, - pkgsUnstable, - nixpkgs-unstable, - vhackPackages, pkgs, - extraModules, - nixLib, + module, + nixos-lib, ... -}: let - domain = "server"; - - sshKeys = - import ../../gi/git-server/ssh_keys.nix {inherit pkgs;}; - - gitoliteAdminConfSnippet = pkgs.writeText "gitolite-admin-conf-snippet" '' - repo CREATOR/[a-zA-Z0-9].* - C = @all - RW+ = CREATOR - RW = WRITERS - R = READERS - option user-configs = cgit\.owner cgit\.desc cgit\.section cgit\.homepage - ''; -in - nixos-lib.runTest { - hostPkgs = pkgs; # the Nixpkgs package set used outside the VMs +}: +nixos-lib.runTest { + hostPkgs = pkgs; + + name = "back"; + + node = { + # Use the nixpkgs as constructed by the `nixpkgs.*` options + pkgs = null; + }; + + nodes = { + machine = {config, ...}: { + environment.systemPackages = [ + pkgs.git + pkgs.git-bug + pkgs.curl + ]; + + imports = [module]; + + vhack = { + back = { + enable = true; + + user = "root"; + group = "root"; + + settings = { + scan_path = "/srv/git/repositories"; + project_list = "/srv/git/projects.list"; + root_url = "https://issues.examplec.com"; + }; + }; + }; + }; + }; - name = "back"; + testScript = {nodes, ...}: + /* + python + */ + '' + start_all() - node = { - specialArgs = {inherit pkgsUnstable vhackPackages nixpkgs-unstable nixLib;}; + with subtest("Create git-bug issues in owner/repo"): + machine.succeed("${pkgs.writeShellScript "setup-git-repo" '' + set -ex - # Use the nixpkgs as constructed by the `nixpkgs.*` options - pkgs = null; - }; + mkdir --parents /srv/git/repositories + cd /srv/git/repositories - nodes = { - server = {config, ...}: { - environment.systemPackages = [pkgs.git]; - - imports = - extraModules - ++ [ - ../../../../modules - ]; - - vhack = { - persist.enable = true; - openssh.enable = true; - nginx = { - enable = true; - selfsign = true; - }; - git-server = { - enable = true; - domain = "git.${domain}"; - gitolite.adminPubkey = sshKeys.admin.pub; - }; - back = { - enable = true; - domain = "issues.${domain}"; - - settings = { - scan_path = "${config.services.gitolite.dataDir}/repositories"; - project_list = "${config.services.gitolite.dataDir}/projects.list"; - }; - }; - }; - }; + echo "owner/repo" > /srv/git/projects.list - client = {nodes, ...}: { - environment.systemPackages = [pkgs.git pkgs.curl pkgs.git-bug pkgs.gawk]; - programs.ssh.extraConfig = '' - Host * - UserKnownHostsFile /dev/null - StrictHostKeyChecking no - # there's nobody around that can input password - PreferredAuthentications publickey - ''; - users.users.alice = {isNormalUser = true;}; - networking.hosts = { - "${nodes.server.networking.primaryIPAddress}" = [ - "git.${domain}" - "issues.${domain}" - "${domain}" - ]; - }; - }; - }; + mkdir --parents owner/repo_base + cd owner/repo_base + git init + + git bug user new --avatar "" --email "alice@machine.org" --name "alice" --non-interactive + + git bug bug new \ + --title "Some bug title" \ + --message "A long description of the bug. Probably has some code segments, maybe even *markdown* mark_up_, <html> or other things" \ + --non-interactive + + git bug bug new \ + --title "Second bug title" \ + --message "" \ + --non-interactive - testScript = {nodes, ...}: - /* - python - */ - '' - start_all() + git bug bug new \ + --title "Third bug title" \ + --message "" \ + --non-interactive - with subtest("can setup ssh keys on client"): - client.succeed( - "mkdir -p ~root/.ssh", - "cp ${sshKeys.admin.priv} ~root/.ssh/id_ed25519", - "chmod 600 ~root/.ssh/id_ed25519", - ) - client.succeed( - "sudo -u alice mkdir -p ~alice/.ssh", - "sudo -u alice cp ${sshKeys.alice.priv} ~alice/.ssh/id_ed25519", - "sudo -u alice chmod 600 ~alice/.ssh/id_ed25519", - ) - - with subtest("gitolite server starts"): - server.wait_for_unit("gitolite-init.service") - server.wait_for_unit("sshd.service") - client.succeed("ssh -n git@git.${domain} info") - - - with subtest("admin can clone and configure gitolite-admin.git"): - client.succeed("${pkgs.writeShellScript "setup-gitolite-admin.git" '' - set -xe - - git clone git@git.${domain}:gitolite-admin.git - git config --global user.name 'System Administrator' - git config --global user.email root\@domain.example - - cp ${sshKeys.alice.pub} gitolite-admin/keydir/alice.pub - - (cd gitolite-admin && git switch -c master && git branch -D main) - - (cd gitolite-admin && git add . && git commit -m 'Add keys for alice' && git push -u origin master) - cat ${gitoliteAdminConfSnippet} >> gitolite-admin/conf/gitolite.conf - (cd gitolite-admin && git add . && git commit -m 'Add support for wild repos' && git push) - (cd gitolite-admin && git push -d origin main) - ''}") - - with subtest("alice can create a repo"): - client.succeed("sudo -u alice ${pkgs.writeShellScript "alice-create-repo" '' - set -xe - - mkdir --parents ./alice/repo1 && cd alice/repo1; - - git init --initial-branch main - echo "# Alice's Repo" > README.md - git add README.md - git -c user.name=Alice -c user.email=alice@domain.example commit -m 'Add readme' - - git remote add origin git@git.${domain}:alice/repo1.git - git push --set-upstream origin main - ''}") - - with subtest("can setup git-bug issues in alice/repo1"): - client.succeed("sudo -u alice ${pkgs.writeShellScript "setup-git-repo" '' - set -ex - - cd alice/repo1 - - git bug user create --avatar "" --email "alice@server.org" --name "alice" --non-interactive - - git bug add \ - --title "Some bug title" \ - --message "A long description of the bug. Probably has some code segments, maybe even *markdown* mark_up_ or other things" \ - --non-interactive - - git bug add \ - --title "Second bug title" \ - --message "" \ - --non-interactive - - git bug add \ - --title "Third bug title" \ - --message "" \ - --non-interactive - - git bug select "$(git bug ls --format plain | awk '{print $1}' | head -n 1)" - - git bug comment add --message "Some comment message" --non-interactive - git bug comment add --message "Second comment message" --non-interactive - git bug label add "Test" - - # TODO: This should use `git bug push`, but their ssh implementation is just - # too special to work in a VM test <2025-03-08> - git push origin +refs/bugs/* - git push origin +refs/identities/* - - ssh git@${domain} -- config alice/repo1 --add cgit.owner Alice - ssh git@${domain} -- perms alice/repo1 + READERS @all - ''}") - - with subtest("back server starts"): - server.wait_for_unit("back.service") - - with subtest("client can access the server"): - client.succeed("${pkgs.writeShellScript "curl-back" '' - set -xe - - curl --insecure --fail --show-error "https://issues.${domain}/alice/repo1.git/issues/open" --output /root/issues.html - grep -- 'Second bug title' /root/issues.html + git bug bug select "$(git bug bug --format plain | awk '{print $1}' | head -n 1)" - curl --insecure --fail --show-error "https://issues.${domain}/" --output /root/repos.html - grep -- 'repo' /root/repos.html - grep -- "<No description>" /root/repos.html - grep -- '<span class="user-name">Alice</span>' /root/repos.html - ''} >&2") + git bug bug comment new --message "Some <comment> message" --non-interactive + git bug bug comment new --message "Second comment message" --non-interactive + git bug bug label new "Test" + git bug bug label new "Test2" - client.copy_from_vm("/root/issues.html", ""); - client.copy_from_vm("/root/repos.html", ""); - ''; - } + cd /srv/git/repositories + git clone \ + --bare \ + --config 'remote.origin.fetch=+refs/bugs/*:refs/bugs/*' \ + --config 'remote.origin.fetch=+refs/identities/*:refs/identities/*' \ + ./owner/repo_base ./owner/repo.git + ''}") + + with subtest("back machine starts"): + machine.wait_for_unit("back.service") + + with subtest("client can access the machine"): + machine.succeed("${pkgs.writeShellScript "curl-back" '' + set -xe + + curl --insecure --fail --show-error "http://127.0.0.1:8000/owner/repo/issues/?query=status:open" --output /root/issues.html + grep -- 'Second bug title' /root/issues.html + + curl --insecure --fail --show-error "http://127.0.0.1:8000/" --output /root/repos.html + grep -- 'repo' /root/repos.html + grep -- "Unnamed repository; edit this file 'description' to name the repository." /root/repos.html + ''} >&2") + + machine.copy_from_vm("/root/issues.html", ""); + machine.copy_from_vm("/root/repos.html", ""); + ''; +} |