about summary refs log tree commit diff
path: root/nixos-tests/webmention-test.nix
blob: 2161e88eb2a3a9582cc2f042dd13a2d3ef931143 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
kittybox:
{ lib, ... }: let
  hosts = ''
    192.168.2.101 kittybox.test
    192.168.2.102 another.test
  '';
in {
  name = "nixos-kittybox";

  nodes = {
    kittybox = { config, pkgs, lib, ... }: {
      imports = [ kittybox.nixosModules.default ];

      services.postgresql = {
        enable = true;
        ensureDatabases = ["kittybox"];
        ensureUsers = [ {
          name = "kittybox";
          ensurePermissions = {
            "DATABASE kittybox" = "ALL PRIVILEGES";
          };
        } ];
      };

      networking = {
        interfaces.eth1 = {
          ipv4.addresses = [
            { address = "192.168.2.101"; prefixLength = 24; }
          ];
        };
        extraHosts = hosts;
        firewall.allowedTCPPorts = [ 443 ];
        firewall.allowedUDPPorts = [ 443 ];
      };

      
      services.kittybox = {
        enable = true;
        logLevel = "info,kittybox=debug,retainer::cache=warn,h2=warn,rustls=warn";
        backendUri = "postgres://localhost?host=/run/postgresql&dbname=kittybox";
        jobQueueUri = config.services.kittybox.backendUri;
      };

      systemd.services.kittybox.wants = [ "postgresql.service" ];
      systemd.services.kittybox.after = [ "postgresql.service" ];
      systemd.services.kittybox.environment = {
        "KITTYBOX_CUSTOM_PKI_ROOTS" = ./tls/rootCA.pem;
      };

      environment.systemPackages = with pkgs; [
        xh
      ];

      services.nginx = {
        enable = true;
        recommendedProxySettings = true;
        virtualHosts = {
          "kittybox.test" = {
            forceSSL = true;
            sslCertificate = ./tls/kittybox.test.pem;
            sslCertificateKey = ./tls/kittybox.test-key.pem;
            locations = {
              "/" = {
                proxyPass = "http://localhost:8080";
              };
            };
          };
        };
      };

      security.pki.certificates = [
        (builtins.readFile ./tls/rootCA.pem)
      ];
    };

    another = { config, pkgs, lib, ... }: {
      networking = {
        interfaces.eth1 = {
          ipv4.addresses = [
            { address = "192.168.2.102"; prefixLength = 24; }
          ];
        };
        extraHosts = hosts;
        firewall.allowedTCPPorts = [ 443 ];
        firewall.allowedUDPPorts = [ 443 ];
      };

      services.nginx = {
        enable = true;
        virtualHosts = {
          "another.test" = {
            forceSSL = true;
            sslCertificate = ./tls/another.test.pem;
            sslCertificateKey = ./tls/another.test-key.pem;
            locations = {
              "/" = {
                root = ./webmention-test;
              };
            };
          };
        };
      };

      environment.systemPackages = with pkgs; [
        xh
      ];

      security.pki.certificates = [
        (builtins.readFile ./tls/rootCA.pem)
      ];
    };
  };

  testScript = ''
    import json
    import shlex
    import time

    post_mf2 = {
        "type": ["h-entry"],
        "properties": {
            "uid": ["https://kittybox.test/posts/test-post"],
            "url": ["https://kittybox.test/posts/test-post"],
            "published": ["2023-07-22T14:04:53+0300"],
            "content": [{"html": "<p>Hello! This is a test post.</p>"}],
            "author": ["https://kittybox.test/"],
        }
    }

    start_all()

    with subtest("Verify that Kittybox started correctly..."):
        kittybox.wait_for_unit("default.target")
        kittybox.succeed("xh --no-check-status https://kittybox.test/.kittybox/micropub")

    with subtest("Onboarding should correctly work..."):
        kittybox.copy_from_host("${./onboarding.json}", "/root/onboarding.json")
        kittybox.succeed("xh --follow https://kittybox.test/.kittybox/onboarding -j @/root/onboarding.json")
        # Testing for a known string is the easiest way to determine that the onboarding worked
        kittybox.succeed("xh https://kittybox.test/ | grep 'vestige of the past long gone'")

    with subtest("The other host should also be reachable..."):
        another.wait_for_unit("default.target")
        another.succeed("xh https://another.test/ | grep 'This is a test webmention.'")

    with subtest("Kittybox accepts a webmention to a valid post..."):
        # Note: we don't really have a way to "authenticate" here.
        # Let's insert the post manually.
        print(kittybox.succeed("sudo -u postgres psql kittybox -c \"INSERT INTO kittybox.mf2_json (uid, mf2, owner) VALUES ('https://kittybox.test/posts/test-post', '" + json.dumps(post_mf2).replace("\"", "\\\"").replace("'", "'" * 2) + "', 'kittybox.test') RETURNING uid\""))
        print(kittybox.succeed("sudo -u postgres psql -A kittybox -c \"SELECT mf2 FROM kittybox.mf2_json WHERE uid = 'https://kittybox.test/posts/test-post'\""))
        kittybox.succeed("xh --verify ${./tls/rootCA.pem} https://kittybox.test/posts/test-post")

        another.succeed("xh --verify ${./tls/rootCA.pem} https://kittybox.test/.kittybox/webmention --form source=https://another.test/index.html target=https://kittybox.test/posts/test-post")
        # Wait a while to let the async tasks settle...
        time.sleep(2)
        # Ensure the webmention has propagated
        # Kittybox doesn't fully render them yet, but the counters are there
        kittybox.succeed("xh --verify ${./tls/rootCA.pem} https://kittybox.test/posts/test-post | grep " + shlex.quote('<span class="icon" aria-label="replies">💬</span><span class="counter">1</span>'))
        
'';
}