import ./make-test-python.nix (
  { pkgs, ... }:
  {
    name = "tang";
    meta = with pkgs.lib.maintainers; {
      maintainers = [ jfroche ];
    };

    nodes.server =
      {
        config,
        pkgs,
        modulesPath,
        ...
      }:
      {
        imports = [
          "${modulesPath}/../tests/common/auto-format-root-device.nix"
        ];
        virtualisation = {
          emptyDiskImages = [ 512 ];
          useBootLoader = true;
          useEFIBoot = true;
          # This requires to have access
          # to a host Nix store as
          # the new root device is /dev/vdb
          # an empty 512MiB drive, containing no Nix store.
          mountHostNixStore = true;
        };

        boot.loader.systemd-boot.enable = true;

        networking.interfaces.eth1.ipv4.addresses = [
          {
            address = "192.168.0.1";
            prefixLength = 24;
          }
        ];

        environment.systemPackages = with pkgs; [
          clevis
          tang
          cryptsetup
        ];
        services.tang = {
          enable = true;
          ipAddressAllow = [ "127.0.0.1/32" ];
        };
      };
    testScript = ''
      start_all()
      machine.wait_for_unit("sockets.target")

      with subtest("Check keys are generated"):
        machine.wait_until_succeeds("curl -v http://127.0.0.1:7654/adv")
        key = machine.wait_until_succeeds("tang-show-keys 7654")

      with subtest("Check systemd access list"):
        machine.succeed("ping -c 3 192.168.0.1")
        machine.fail("curl -v --connect-timeout 3 http://192.168.0.1:7654/adv")

      with subtest("Check basic encrypt and decrypt message"):
        machine.wait_until_succeeds(f"""echo 'Hello World' | clevis encrypt tang '{{ "url": "http://127.0.0.1:7654", "thp":"{key}"}}' > /tmp/encrypted""")
        decrypted = machine.wait_until_succeeds("clevis decrypt < /tmp/encrypted")
        assert decrypted.strip() == "Hello World"
        machine.wait_until_succeeds("tang-show-keys 7654")

      with subtest("Check encrypt and decrypt disk"):
        machine.succeed("cryptsetup luksFormat --force-password --batch-mode /dev/vdb <<<'password'")
        machine.succeed(f"""clevis luks bind -s1 -y -f -d /dev/vdb tang '{{ "url": "http://127.0.0.1:7654", "thp":"{key}" }}' <<< 'password' """)
        clevis_luks = machine.succeed("clevis luks list -d /dev/vdb")
        assert clevis_luks.strip() == """1: tang '{"url":"http://127.0.0.1:7654"}'"""
        machine.succeed("clevis luks unlock -d /dev/vdb")
        machine.succeed("find /dev/mapper -name 'luks*' -exec cryptsetup close {} +")
        machine.succeed("clevis luks unlock -d /dev/vdb")
        machine.succeed("find /dev/mapper -name 'luks*' -exec cryptsetup close {} +")
        # without tang available, unlock should fail
        machine.succeed("systemctl stop tangd.socket")
        machine.fail("clevis luks unlock -d /dev/vdb")
        machine.succeed("systemctl start tangd.socket")

      with subtest("Rotate server keys"):
        machine.succeed("${pkgs.tang}/libexec/tangd-rotate-keys -d /var/lib/tang")
        machine.succeed("clevis luks unlock -d /dev/vdb")
        machine.succeed("find /dev/mapper -name 'luks*' -exec cryptsetup close {} +")

      with subtest("Test systemd service security"):
          output = machine.succeed("systemd-analyze security tangd@.service")
          machine.log(output)
          assert output[-9:-1] == "SAFE :-}"
    '';
  }
)