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": "

Hello! This is a test post.

"}], "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('💬1')) ''; }