python312Packages.millheater: 0.11.8 -> 0.12.0
[NixPkgs.git] / nixos / tests / public-inbox.nix
blob4d06d3e1738eed9a78ed106f6af84ef5e459316b
1 import ./make-test-python.nix ({ pkgs, lib, ... }:
2 let
3   orga = "example";
4   domain = "${orga}.localdomain";
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   '';
13   name = "public-inbox";
15   meta.maintainers = with pkgs.lib.maintainers; [ julm ];
17   nodes.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;
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     #'';
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     };
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     };
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 }
131           a { color:#00f; text-decoration:none }
132           a:visited { color:#808 }
134           *.q { color:#008 }
136           *.add { color:#060 }
137           *.del {color:#900 }
138           *.head { color:#000 }
139           *.hunk { color:#960 }
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 */
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     };
160     services.postfix = {
161       enable = true;
162       setSendmail = true;
163       #sslCert = "${tls-cert}/cert.pem";
164       #sslKey = "${tls-cert}/key.pem";
165       recipientDelimiter = "+";
166     };
168     environment.systemPackages = [
169       pkgs.mailutils
170       pkgs.openssl
171     ];
173   };
175   testScript = ''
176     start_all()
177     machine.wait_for_unit("multi-user.target")
178     machine.wait_for_unit("public-inbox-init.service")
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")
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")
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
202       This is a testing mail.
203     ''}")
204     machine.sleep(10)
205     machine.succeed("curl -L 'https://machine.${domain}/inbox/repo1/repo1@root-1/T/#u' | grep 'This is a testing mail.'")
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>'")
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")
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.${domain}/inbox/repo1/repo1@root-1/raw | sudo -u public-inbox public-inbox-learn rm --all")
225     machine.fail("curl -L https://machine.${domain}/inbox/repo1/repo1@root-1/T/#u | grep 'This is a testing mail.'")
227     # Compact the database
228     machine.succeed("sudo -u public-inbox public-inbox-compact --all")
229   '';