about summary refs log tree commit diff
path: root/nixos/tests
diff options
context:
space:
mode:
authorh7x4 <h7x4@nani.wtf>2023-07-27 21:13:55 +0200
committerSandro Jäckel <sandro.jaeckel@gmail.com>2024-06-11 13:10:44 +0200
commitd952db86c9f57d50af70e2b15cc9fb2910aedca2 (patch)
tree37979f0b56fb92dbb36f3deb6f35607e191806a9 /nixos/tests
parentba2ec015bd7234b2b7068175fa7dbe02b7def65e (diff)
nixos/vaultwarden: add test for backup script, fix flaky sqlite test
Diffstat (limited to 'nixos/tests')
-rw-r--r--nixos/tests/all-tests.nix2
-rw-r--r--nixos/tests/vaultwarden.nix263
2 files changed, 138 insertions, 127 deletions
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
index aa7e007e4fddb..f141fd29133b0 100644
--- a/nixos/tests/all-tests.nix
+++ b/nixos/tests/all-tests.nix
@@ -1013,7 +1013,7 @@ in {
   vault-agent = handleTest ./vault-agent.nix {};
   vault-dev = handleTest ./vault-dev.nix {};
   vault-postgresql = handleTest ./vault-postgresql.nix {};
-  vaultwarden = handleTest ./vaultwarden.nix {};
+  vaultwarden = discoverTests (import ./vaultwarden.nix);
   vector = handleTest ./vector {};
   vengi-tools = handleTest ./vengi-tools.nix {};
   victoriametrics = handleTest ./victoriametrics.nix {};
diff --git a/nixos/tests/vaultwarden.nix b/nixos/tests/vaultwarden.nix
index 28ff170e36107..5b1d55f406b5f 100644
--- a/nixos/tests/vaultwarden.nix
+++ b/nixos/tests/vaultwarden.nix
@@ -1,38 +1,94 @@
-{ system ? builtins.currentSystem
-, config ? { }
-, pkgs ? import ../.. { inherit system config; }
-}:
-
 # These tests will:
 #  * Set up a vaultwarden server
-#  * Have Firefox use the web vault to create an account, log in, and save a password to the valut
+#  * Have Firefox use the web vault to create an account, log in, and save a password to the vault
 #  * Have the bw cli log in and read that password from the vault
 #
 # Note that Firefox must be on the same machine as the server for WebCrypto APIs to be available (or HTTPS must be configured)
 #
 # The same tests should work without modification on the official bitwarden server, if we ever package that.
 
-with import ../lib/testing-python.nix { inherit system pkgs; };
-with pkgs.lib;
 let
-  backends = [ "sqlite" "mysql" "postgresql" ];
-
-  dbPassword = "please_dont_hack";
-
-  userEmail = "meow@example.com";
-  userPassword = "also_super_secret_ZJWpBKZi668QGt"; # Must be complex to avoid interstitial warning on the signup page
-
-  storedPassword = "seeeecret";
+  makeVaultwardenTest = name: {
+    backend ? name,
+    withClient ? true,
+    testScript ? null,
+  }: import ./make-test-python.nix ({ lib, pkgs, ...}: let
+    dbPassword = "please_dont_hack";
+    userEmail = "meow@example.com";
+    userPassword = "also_super_secret_ZJWpBKZi668QGt"; # Must be complex to avoid interstitial warning on the signup page
+    storedPassword = "seeeecret";
+
+    testRunner = pkgs.writers.writePython3Bin "test-runner" {
+      libraries = [ pkgs.python3Packages.selenium ];
+      flakeIgnore = [  "E501" ];
+    } ''
+
+      from selenium.webdriver.common.by import By
+      from selenium.webdriver import Firefox
+      from selenium.webdriver.firefox.options import Options
+      from selenium.webdriver.support.ui import WebDriverWait
+      from selenium.webdriver.support import expected_conditions as EC
+
+      options = Options()
+      options.add_argument('--headless')
+      driver = Firefox(options=options)
+
+      driver.implicitly_wait(20)
+      driver.get('http://localhost/#/register')
+
+      wait = WebDriverWait(driver, 10)
+
+      wait.until(EC.title_contains("Vaultwarden Web"))
+
+      driver.find_element(By.CSS_SELECTOR, 'input#register-form_input_email').send_keys(
+          '${userEmail}'
+      )
+      driver.find_element(By.CSS_SELECTOR, 'input#register-form_input_name').send_keys(
+          'A Cat'
+      )
+      driver.find_element(By.CSS_SELECTOR, 'input#register-form_input_master-password').send_keys(
+          '${userPassword}'
+      )
+      driver.find_element(By.CSS_SELECTOR, 'input#register-form_input_confirm-master-password').send_keys(
+          '${userPassword}'
+      )
+      if driver.find_element(By.CSS_SELECTOR, 'input#checkForBreaches').is_selected():
+          driver.find_element(By.CSS_SELECTOR, 'input#checkForBreaches').click()
+
+      driver.find_element(By.XPATH, "//button[contains(., 'Create account')]").click()
+
+      wait.until_not(EC.title_contains("Create account"))
+
+      driver.find_element(By.XPATH, "//button[contains(., 'Continue')]").click()
+
+      driver.find_element(By.CSS_SELECTOR, 'input#login_input_master-password').send_keys(
+          '${userPassword}'
+      )
+      driver.find_element(By.XPATH, "//button[contains(., 'Log in')]").click()
+
+      wait.until(EC.title_contains("Vaults"))
+
+      driver.find_element(By.XPATH, "//button[contains(., 'New item')]").click()
+
+      driver.find_element(By.CSS_SELECTOR, 'input#name').send_keys(
+          'secrets'
+      )
+      driver.find_element(By.CSS_SELECTOR, 'input#loginPassword').send_keys(
+          '${storedPassword}'
+      )
+
+      driver.find_element(By.XPATH, "//button[contains(., 'Save')]").click()
+    '';
+  in {
+    inherit name;
 
-  makeVaultwardenTest = backend: makeTest {
-    name = "vaultwarden-${backend}";
     meta = {
-      maintainers = with pkgs.lib.maintainers; [ jjjollyjim ];
+      maintainers = with pkgs.lib.maintainers; [ dotlambda SuperSandro2000 ];
     };
 
     nodes = {
-      server = { pkgs, ... }:
-        let backendConfig = {
+      server = { pkgs, ... }: lib.mkMerge [
+        {
           mysql = {
             services.mysql = {
               enable = true;
@@ -53,113 +109,47 @@ let
           postgresql = {
             services.postgresql = {
               enable = true;
-              initialScript = pkgs.writeText "postgresql-init.sql" ''
-                CREATE USER bitwardenuser WITH PASSWORD '${dbPassword}';
-                CREATE DATABASE bitwarden WITH OWNER bitwardenuser;
-              '';
+              ensureDatabases = [ "vaultwarden" ];
+              ensureUsers = [{
+                name = "vaultwarden";
+                ensureDBOwnership = true;
+              }];
             };
 
-            services.vaultwarden.config.databaseUrl = "postgresql://bitwardenuser:${dbPassword}@localhost/bitwarden";
+            services.vaultwarden.config.databaseUrl = "postgresql:///vaultwarden?host=/run/postgresql";
 
             systemd.services.vaultwarden.after = [ "postgresql.service" ];
           };
 
-          sqlite = { };
-        };
-        in
-        mkMerge [
-          backendConfig.${backend}
-          {
-            services.vaultwarden = {
-              enable = true;
-              dbBackend = backend;
-              config = {
-                rocketAddress = "0.0.0.0";
-                rocketPort = 80;
-              };
-            };
+          sqlite = {
+            services.vaultwarden.backupDir = "/var/lib/vaultwarden/backups";
+
+            environment.systemPackages = [ pkgs.sqlite ];
+          };
+        }.${backend}
 
-            networking.firewall.allowedTCPPorts = [ 80 ];
-
-            environment.systemPackages =
-              let
-                testRunner = pkgs.writers.writePython3Bin "test-runner"
-                  {
-                    libraries = [ pkgs.python3Packages.selenium ];
-                    flakeIgnore = [
-                      "E501"
-                    ];
-                  } ''
-
-                  from selenium.webdriver.common.by import By
-                  from selenium.webdriver import Firefox
-                  from selenium.webdriver.firefox.options import Options
-                  from selenium.webdriver.support.ui import WebDriverWait
-                  from selenium.webdriver.support import expected_conditions as EC
-
-                  options = Options()
-                  options.add_argument('--headless')
-                  driver = Firefox(options=options)
-
-                  driver.implicitly_wait(20)
-                  driver.get('http://localhost/#/register')
-
-                  wait = WebDriverWait(driver, 10)
-
-                  wait.until(EC.title_contains("Vaultwarden Web"))
-
-                  driver.find_element(By.CSS_SELECTOR, 'input#register-form_input_email').send_keys(
-                      '${userEmail}'
-                  )
-                  driver.find_element(By.CSS_SELECTOR, 'input#register-form_input_name').send_keys(
-                      'A Cat'
-                  )
-                  driver.find_element(By.CSS_SELECTOR, 'input#register-form_input_master-password').send_keys(
-                      '${userPassword}'
-                  )
-                  driver.find_element(By.CSS_SELECTOR, 'input#register-form_input_confirm-master-password').send_keys(
-                      '${userPassword}'
-                  )
-                  if driver.find_element(By.CSS_SELECTOR, 'input#checkForBreaches').is_selected():
-                      driver.find_element(By.CSS_SELECTOR, 'input#checkForBreaches').click()
-
-                  driver.find_element(By.XPATH, "//button[contains(., 'Create account')]").click()
-
-                  wait.until_not(EC.title_contains("Create account"))
-
-                  driver.find_element(By.XPATH, "//button[contains(., 'Continue')]").click()
-
-                  driver.find_element(By.CSS_SELECTOR, 'input#login_input_master-password').send_keys(
-                      '${userPassword}'
-                  )
-                  driver.find_element(By.XPATH, "//button[contains(., 'Log in')]").click()
-
-                  wait.until(EC.title_contains("Vaults"))
-
-                  driver.find_element(By.XPATH, "//button[contains(., 'New item')]").click()
-
-                  driver.find_element(By.CSS_SELECTOR, 'input#name').send_keys(
-                      'secrets'
-                  )
-                  driver.find_element(By.CSS_SELECTOR, 'input#loginPassword').send_keys(
-                      '${storedPassword}'
-                  )
-
-                  driver.find_element(By.XPATH, "//button[contains(., 'Save')]").click()
-                '';
-              in
-              [ pkgs.firefox-unwrapped pkgs.geckodriver testRunner ];
-
-          }
-        ];
-
-      client = { pkgs, ... }:
         {
-          environment.systemPackages = [ pkgs.bitwarden-cli ];
-        };
+          services.vaultwarden = {
+            enable = true;
+            dbBackend = backend;
+            config = {
+              rocketAddress = "0.0.0.0";
+              rocketPort = 80;
+            };
+          };
+
+          networking.firewall.allowedTCPPorts = [ 80 ];
+
+          environment.systemPackages = [ pkgs.firefox-unwrapped pkgs.geckodriver testRunner ];
+        }
+      ];
+    } // lib.optionalAttrs withClient {
+      client = { pkgs, ... }: {
+        environment.systemPackages = [ pkgs.bitwarden-cli ];
+      };
     };
 
-    testScript = ''
+    testScript = if testScript != null then testScript else ''
       start_all()
       server.wait_for_unit("vaultwarden.service")
       server.wait_for_open_port(80)
@@ -184,15 +174,36 @@ let
           client.succeed(f"bw --nointeraction --raw --session {key} sync -f")
 
       with subtest("get the password with the cli"):
-          password = client.succeed(
-              f"bw --nointeraction --raw --session {key} list items | ${pkgs.jq}/bin/jq -r .[].login.password"
+          password = client.wait_until_succeeds(
+              f"bw --nointeraction --raw --session {key} list items | ${pkgs.jq}/bin/jq -r .[].login.password",
+              timeout=60
           )
           assert password.strip() == "${storedPassword}"
     '';
-  };
+  });
 in
-builtins.listToAttrs (
-  map
-    (backend: { name = backend; value = makeVaultwardenTest backend; })
-    backends
-)
+builtins.mapAttrs (k: v: makeVaultwardenTest k v) {
+  mysql = {};
+  postgresql = {};
+  sqlite = {};
+  sqlite-backup = {
+    backend = "sqlite";
+    withClient = false;
+
+    testScript = ''
+      start_all()
+      server.wait_for_unit("vaultwarden.service")
+      server.wait_for_open_port(80)
+
+      with subtest("Set up vaultwarden"):
+          server.succeed("PYTHONUNBUFFERED=1 test-runner | systemd-cat -t test-runner")
+
+      with subtest("Run the backup script"):
+          server.start_job("backup-vaultwarden.service")
+
+      with subtest("Check that backup exists"):
+          server.succeed('[ -d "/var/lib/vaultwarden/backups" ]')
+          server.succeed('[ -f "/var/lib/vaultwarden/backups/db.sqlite3" ]')
+    '';
+  };
+}