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