at 23.05-pre 7.7 kB view raw
1import ./make-test-python.nix ({ pkgs, lib, ... }: 2let 3 orga = "example"; 4 domain = "${orga}.localdomain"; 5 6 tls-cert = pkgs.runCommand "selfSignedCert" { buildInputs = [ pkgs.openssl ]; } '' 7 openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -nodes -days 36500 \ 8 -subj '/CN=machine.${domain}' 9 install -D -t $out key.pem cert.pem 10 ''; 11in 12{ 13 name = "public-inbox"; 14 15 meta.maintainers = with pkgs.lib.maintainers; [ julm ]; 16 17 machine = { config, pkgs, nodes, ... }: let 18 inherit (config.services) gitolite public-inbox; 19 # Git repositories paths in Gitolite. 20 # Only their baseNameOf is used for configuring public-inbox. 21 repositories = [ 22 "user/repo1" 23 "user/repo2" 24 ]; 25 in 26 { 27 virtualisation.diskSize = 1 * 1024; 28 virtualisation.memorySize = 1 * 1024; 29 networking.domain = domain; 30 31 security.pki.certificateFiles = [ "${tls-cert}/cert.pem" ]; 32 # If using security.acme: 33 #security.acme.certs."${domain}".postRun = '' 34 # systemctl try-restart public-inbox-nntpd public-inbox-imapd 35 #''; 36 37 services.public-inbox = { 38 enable = true; 39 postfix.enable = true; 40 openFirewall = true; 41 settings.publicinbox = { 42 css = [ "href=https://machine.${domain}/style/light.css" ]; 43 nntpserver = [ "nntps://machine.${domain}" ]; 44 wwwlisting = "match=domain"; 45 }; 46 mda = { 47 enable = true; 48 args = [ "--no-precheck" ]; # Allow Bcc: 49 }; 50 http = { 51 enable = true; 52 port = "/run/public-inbox-http.sock"; 53 #port = 8080; 54 args = ["-W0"]; 55 mounts = [ 56 "https://machine.${domain}/inbox" 57 ]; 58 }; 59 nntp = { 60 enable = true; 61 #port = 563; 62 args = ["-W0"]; 63 cert = "${tls-cert}/cert.pem"; 64 key = "${tls-cert}/key.pem"; 65 }; 66 imap = { 67 enable = true; 68 #port = 993; 69 args = ["-W0"]; 70 cert = "${tls-cert}/cert.pem"; 71 key = "${tls-cert}/key.pem"; 72 }; 73 inboxes = lib.recursiveUpdate (lib.genAttrs (map baseNameOf repositories) (repo: { 74 address = [ 75 # Routed to the "public-inbox:" transport in services.postfix.transport 76 "${repo}@${domain}" 77 ]; 78 description = '' 79 ${repo}@${domain} : 80 discussions about ${repo}. 81 ''; 82 url = "https://machine.${domain}/inbox/${repo}"; 83 newsgroup = "inbox.comp.${orga}.${repo}"; 84 coderepo = [ repo ]; 85 })) 86 { 87 repo2 = { 88 hide = [ 89 "imap" # FIXME: doesn't work for IMAP as of public-inbox 1.6.1 90 "manifest" 91 "www" 92 ]; 93 }; 94 }; 95 settings.coderepo = lib.listToAttrs (map (path: lib.nameValuePair (baseNameOf path) { 96 dir = "/var/lib/gitolite/repositories/${path}.git"; 97 cgitUrl = "https://git.${domain}/${path}.git"; 98 }) repositories); 99 }; 100 101 # Use gitolite to store Git repositories listed in coderepo entries 102 services.gitolite = { 103 enable = true; 104 adminPubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJmoTOQnGqX+//us5oye8UuE+tQBx9QEM7PN13jrwgqY root@localhost"; 105 }; 106 systemd.services.public-inbox-httpd = { 107 serviceConfig.SupplementaryGroups = [ gitolite.group ]; 108 }; 109 110 # Use nginx as a reverse proxy for public-inbox-httpd 111 services.nginx = { 112 enable = true; 113 recommendedGzipSettings = true; 114 recommendedOptimisation = true; 115 recommendedTlsSettings = true; 116 recommendedProxySettings = true; 117 virtualHosts."machine.${domain}" = { 118 forceSSL = true; 119 sslCertificate = "${tls-cert}/cert.pem"; 120 sslCertificateKey = "${tls-cert}/key.pem"; 121 locations."/".return = "302 /inbox"; 122 locations."= /inbox".return = "302 /inbox/"; 123 locations."/inbox".proxyPass = "http://unix:${public-inbox.http.port}:/inbox"; 124 # If using TCP instead of a Unix socket: 125 #locations."/inbox".proxyPass = "http://127.0.0.1:${toString public-inbox.http.port}/inbox"; 126 # Referred to by settings.publicinbox.css 127 # See http://public-inbox.org/meta/_/text/color/ 128 locations."= /style/light.css".alias = pkgs.writeText "light.css" '' 129 * { background:#fff; color:#000 } 130 131 a { color:#00f; text-decoration:none } 132 a:visited { color:#808 } 133 134 *.q { color:#008 } 135 136 *.add { color:#060 } 137 *.del {color:#900 } 138 *.head { color:#000 } 139 *.hunk { color:#960 } 140 141 .hl.num { color:#f30 } /* number */ 142 .hl.esc { color:#f0f } /* escape character */ 143 .hl.str { color:#f30 } /* string */ 144 .hl.ppc { color:#c3c } /* preprocessor */ 145 .hl.pps { color:#f30 } /* preprocessor string */ 146 .hl.slc { color:#099 } /* single-line comment */ 147 .hl.com { color:#099 } /* multi-line comment */ 148 /* .hl.opt { color:#ccc } */ /* operator */ 149 /* .hl.ipl { color:#ccc } */ /* interpolation */ 150 151 /* keyword groups kw[a-z] */ 152 .hl.kwa { color:#f90 } 153 .hl.kwb { color:#060 } 154 .hl.kwc { color:#f90 } 155 /* .hl.kwd { color:#ccc } */ 156 ''; 157 }; 158 }; 159 160 services.postfix = { 161 enable = true; 162 setSendmail = true; 163 #sslCert = "${tls-cert}/cert.pem"; 164 #sslKey = "${tls-cert}/key.pem"; 165 recipientDelimiter = "+"; 166 }; 167 168 environment.systemPackages = [ 169 pkgs.mailutils 170 pkgs.openssl 171 ]; 172 173 }; 174 175 testScript = '' 176 start_all() 177 machine.wait_for_unit("multi-user.target") 178 machine.wait_for_unit("public-inbox-init.service") 179 180 # Very basic check that Gitolite can work; 181 # Gitolite is not needed for the rest of this testScript 182 machine.wait_for_unit("gitolite-init.service") 183 184 # List inboxes through public-inbox-httpd 185 machine.wait_for_unit("nginx.service") 186 machine.succeed("curl -L https://machine.${domain} | grep repo1@${domain}") 187 # The repo2 inbox is hidden 188 machine.fail("curl -L https://machine.${domain} | grep repo2@${domain}") 189 machine.wait_for_unit("public-inbox-httpd.service") 190 191 # Send a mail and read it through public-inbox-httpd 192 # Must work too when using a recipientDelimiter. 193 machine.wait_for_unit("postfix.service") 194 machine.succeed("mail -t <${pkgs.writeText "mail" '' 195 Subject: Testing mail 196 From: root@localhost 197 To: repo1+extension@${domain} 198 Message-ID: <repo1@root-1> 199 Content-Type: text/plain; charset=utf-8 200 Content-Disposition: inline 201 202 This is a testing mail. 203 ''}") 204 machine.sleep(5) 205 machine.succeed("curl -L 'https://machine.${domain}/inbox/repo1/repo1@root-1/T/#u' | grep 'This is a testing mail.'") 206 207 # Read a mail through public-inbox-imapd 208 machine.wait_for_open_port(993) 209 machine.wait_for_unit("public-inbox-imapd.service") 210 machine.succeed("openssl s_client -ign_eof -crlf -connect machine.${domain}:993 <${pkgs.writeText "imap-commands" '' 211 tag login anonymous@${domain} anonymous 212 tag SELECT INBOX.comp.${orga}.repo1.0 213 tag FETCH 1 (BODY[HEADER]) 214 tag LOGOUT 215 ''} | grep '^Message-ID: <repo1@root-1>'") 216 217 # TODO: Read a mail through public-inbox-nntpd 218 #machine.wait_for_open_port(563) 219 #machine.wait_for_unit("public-inbox-nntpd.service") 220 221 # Delete a mail. 222 # Note that the use of an extension not listed in the addresses 223 # require to use --all 224 machine.succeed("curl -L https://machine.example.localdomain/inbox/repo1/repo1@root-1/raw | sudo -u public-inbox public-inbox-learn rm --all") 225 machine.fail("curl -L https://machine.example.localdomain/inbox/repo1/repo1@root-1/T/#u | grep 'This is a testing mail.'") 226 ''; 227})