at master 4.3 kB view raw
1{ pkgs, lib, ... }: 2let 3 uiPort = 1234; 4 backendPort = 5678; 5 lemmyNodeName = "server"; 6in 7{ 8 name = "lemmy"; 9 meta = with lib.maintainers; { 10 maintainers = [ mightyiam ]; 11 }; 12 13 nodes = { 14 client = { }; 15 16 "${lemmyNodeName}" = { 17 services.lemmy = { 18 enable = true; 19 ui.port = uiPort; 20 database.createLocally = true; 21 settings = { 22 hostname = "http://${lemmyNodeName}"; 23 port = backendPort; 24 # Without setup, the /feeds/* and /nodeinfo/* API endpoints won't return 200 25 setup = { 26 admin_username = "mightyiam"; 27 site_name = "Lemmy FTW"; 28 admin_email = "mightyiam@example.com"; 29 }; 30 }; 31 adminPasswordFile = /etc/lemmy-admin-password.txt; 32 caddy.enable = true; 33 }; 34 35 environment.etc."lemmy-admin-password.txt".text = "ThisIsWhatIUseEverywhereTryIt"; 36 37 networking.firewall.allowedTCPPorts = [ 80 ]; 38 39 # pict-rs seems to need more than 1025114112 bytes 40 virtualisation.memorySize = 2000; 41 }; 42 }; 43 44 testScript = '' 45 server = ${lemmyNodeName} 46 47 with subtest("the merged config is secure"): 48 server.wait_for_unit("lemmy.service") 49 config_permissions = server.succeed("stat --format %A /run/lemmy/config.hjson").rstrip() 50 assert config_permissions == "-rw-------", f"merged config permissions {config_permissions} are insecure" 51 directory_permissions = server.succeed("stat --format %A /run/lemmy").rstrip() 52 assert directory_permissions[5] == directory_permissions[8] == "-", "merged config can be replaced" 53 54 with subtest("the backend starts and responds"): 55 server.wait_for_open_port(${toString backendPort}) 56 # wait until succeeds, it just needs few seconds for migrations, but lets give it 50s max 57 server.wait_until_succeeds("curl --fail localhost:${toString backendPort}/api/v3/site", 50) 58 59 with subtest("the UI starts and responds"): 60 server.wait_for_unit("lemmy-ui.service") 61 server.wait_for_open_port(${toString uiPort}) 62 server.succeed("curl --fail localhost:${toString uiPort}") 63 64 with subtest("Lemmy-UI responds through the caddy reverse proxy"): 65 server.systemctl("start network-online.target") 66 server.wait_for_unit("network-online.target") 67 server.wait_for_unit("caddy.service") 68 server.wait_for_open_port(80) 69 body = server.execute("curl --fail --location ${lemmyNodeName}")[1] 70 assert "Lemmy" in body, f"String Lemmy not found in response for ${lemmyNodeName}: \n{body}" 71 72 with subtest("the server is exposed externally"): 73 client.systemctl("start network-online.target") 74 client.wait_for_unit("network-online.target") 75 client.succeed("curl -v --fail ${lemmyNodeName}") 76 77 with subtest("caddy correctly routes backend requests"): 78 # Make sure we are not hitting frontend 79 server.execute("systemctl stop lemmy-ui.service") 80 81 def assert_http_code(url, expected_http_code, extra_curl_args=""): 82 _, http_code = server.execute(f'curl --location --silent -o /dev/null {extra_curl_args} --fail --write-out "%{{http_code}}" {url}') 83 assert http_code == str(expected_http_code), f"expected http code {expected_http_code}, got {http_code}" 84 85 # Caddy responds with HTTP code 502 if it cannot handle the requested path 86 assert_http_code("${lemmyNodeName}/obviously-wrong-path/", 502) 87 88 assert_http_code("${lemmyNodeName}/static/js/client.js", 200) 89 assert_http_code("${lemmyNodeName}/api/v3/site", 200) 90 91 # A 404 confirms that the request goes to the backend 92 # No path can return 200 until after we upload an image to pict-rs 93 assert_http_code("${lemmyNodeName}/pictrs/", 404) 94 95 assert_http_code("${lemmyNodeName}/feeds/all.xml", 200) 96 assert_http_code("${lemmyNodeName}/nodeinfo/2.0.json", 200) 97 98 assert_http_code("${lemmyNodeName}/some-other-made-up-path/", 404, "-X POST") 99 assert_http_code("${lemmyNodeName}/some-other-path", 404, "-H 'Accept: application/activity+json'") 100 assert_http_code("${lemmyNodeName}/some-other-path", 404, "-H 'Accept: application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"'") 101 ''; 102}