1/*
2 Pleroma E2E VM test.
3
4 Abstract:
5 =========
6 Using pleroma, postgresql, a local CA cert, a nginx reverse proxy
7 and a toot-based client, we're going to:
8
9 1. Provision a pleroma service from scratch (pleroma config + postgres db).
10 2. Create a "jamy" admin user.
11 3. Send a toot from this user.
12 4. Send a upload from this user.
13 5. Check the toot is part of the server public timeline
14
15 Notes:
16 - We need a fully functional TLS setup without having any access to
17 the internet. We do that by issuing a self-signed cert, add this
18 self-cert to the hosts pki trust store and finally spoof the
19 hostnames using /etc/hosts.
20 - For this NixOS test, we *had* to store some DB-related and
21 pleroma-related secrets to the store. Keep in mind the store is
22 world-readable, it's the worst place possible to store *any*
23 secret. **DO NOT DO THIS IN A REAL WORLD DEPLOYMENT**.
24*/
25
26import ./make-test-python.nix (
27 { pkgs, ... }:
28 let
29 send-toot = pkgs.writeScriptBin "send-toot" ''
30 set -eux
31 # toot is using the requests library internally. This library
32 # sadly embed its own certificate store instead of relying on the
33 # system one. Overriding this pretty bad default behaviour.
34 export REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
35
36 toot login_cli -i "pleroma.nixos.test" -e "jamy@nixos.test" -p 'jamy-password'
37 echo "Login OK"
38
39 # Send a toot then verify it's part of the public timeline
40 toot post "hello world Jamy here"
41 echo "Send toot OK"
42 toot timeline -1 | grep -F -q "hello world Jamy here"
43 echo "Get toot from timeline OK"
44
45 # Test file upload
46 echo "y" | ${pkgs.toot}/bin/toot upload <(dd if=/dev/zero bs=1024 count=1024 status=none) \
47 | grep -F -q "https://pleroma.nixos.test/media"
48
49 echo "====================================================="
50 echo "= SUCCESS ="
51 echo "= ="
52 echo "= We were able to sent a toot + a upload and ="
53 echo "= retrieve both of them in the public timeline. ="
54 echo "====================================================="
55 '';
56
57 provision-db = pkgs.writeScriptBin "provision-db" ''
58 set -eux
59 sudo -u postgres psql -f ${db-seed}
60 '';
61
62 test-db-passwd = "SccZOvTGM//BMrpoQj68JJkjDkMGb4pHv2cECWiI+XhVe3uGJTLI0vFV/gDlZ5jJ";
63
64 /*
65 For this NixOS test, we *had* to store this secret to the store.
66 Keep in mind the store is world-readable, it's the worst place
67 possible to store *any* secret. **DO NOT DO THIS IN A REAL WORLD
68 DEPLOYMENT**.
69 */
70 db-seed = pkgs.writeText "provision.psql" ''
71 CREATE USER pleroma WITH ENCRYPTED PASSWORD '${test-db-passwd}';
72 CREATE DATABASE pleroma OWNER pleroma;
73 \c pleroma;
74 --Extensions made by ecto.migrate that need superuser access
75 CREATE EXTENSION IF NOT EXISTS citext;
76 CREATE EXTENSION IF NOT EXISTS pg_trgm;
77 CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
78 '';
79
80 pleroma-conf = ''
81 import Config
82
83 config :pleroma, Pleroma.Web.Endpoint,
84 url: [host: "pleroma.nixos.test", scheme: "https", port: 443],
85 http: [ip: {127, 0, 0, 1}, port: 4000]
86
87 config :pleroma, :instance,
88 name: "NixOS test pleroma server",
89 email: "pleroma@nixos.test",
90 notify_email: "pleroma@nixos.test",
91 limit: 5000,
92 registrations_open: true
93
94 config :pleroma, :media_proxy,
95 enabled: false,
96 redirect_on_failure: true
97 #base_url: "https://cache.pleroma.social"
98
99 config :pleroma, Pleroma.Repo,
100 adapter: Ecto.Adapters.Postgres,
101 username: "pleroma",
102 password: "${test-db-passwd}",
103 database: "pleroma",
104 hostname: "localhost",
105 pool_size: 10,
106 prepare: :named,
107 parameters: [
108 plan_cache_mode: "force_custom_plan"
109 ]
110
111 config :pleroma, :database, rum_enabled: false
112 config :pleroma, :instance, static_dir: "/var/lib/pleroma/static"
113 config :pleroma, Pleroma.Uploaders.Local, uploads: "/var/lib/pleroma/uploads"
114 config :pleroma, configurable_from_database: false
115 '';
116
117 /*
118 For this NixOS test, we *had* to store this secret to the store.
119 Keep in mind the store is world-readable, it's the worst place
120 possible to store *any* secret. **DO NOT DO THIS IN A REAL WORLD
121 DEPLOYMENT**.
122 In a real-word deployment, you'd handle this either by:
123 - manually upload your pleroma secrets to /var/lib/pleroma/secrets.exs
124 - use a deployment tool such as morph or NixOps to deploy your secrets.
125 */
126 pleroma-conf-secret = pkgs.writeText "secrets.exs" ''
127 import Config
128
129 config :joken, default_signer: "PS69/wMW7X6FIQPABt9lwvlZvgrJIncfiAMrK9J5mjVus/7/NJJi1DsDA1OghBE5"
130
131 config :pleroma, Pleroma.Web.Endpoint,
132 secret_key_base: "NvfmU7lYaQrmmxt4NACm0AaAfN9t6WxsrX0NCB4awkGHvr1S7jyshlEmrjaPFhhq",
133 signing_salt: "3L41+BuJ"
134
135 config :web_push_encryption, :vapid_details,
136 subject: "mailto:pleroma@nixos.test",
137 public_key: "BKjfNX9-UqAcncaNqERQtF7n9pKrB0-MO-juv6U5E5XQr_Tg5D-f8AlRjduAguDpyAngeDzG8MdrTejMSL4VF30",
138 private_key: "k7o9onKMQrgMjMb6l4fsxSaXO0BTNAer5MVSje3q60k"
139 '';
140
141 /*
142 For this NixOS test, we *had* to store this secret to the store.
143 Keep in mind the store is world-readable, it's the worst place
144 possible to store *any* secret. **DO NOT DO THIS IN A REAL WORLD
145 DEPLOYMENT**.
146 In a real-word deployment, you'd handle this either by:
147 - manually upload your pleroma secrets to /var/lib/pleroma/secrets.exs
148 - use a deployment tool such as morph or NixOps to deploy your secrets.
149 */
150 provision-secrets = pkgs.writeScriptBin "provision-secrets" ''
151 set -eux
152 cp "${pleroma-conf-secret}" "/var/lib/pleroma/secrets.exs"
153 chown pleroma:pleroma /var/lib/pleroma/secrets.exs
154 '';
155
156 /*
157 For this NixOS test, we *had* to store this secret to the store.
158 Keep in mind the store is world-readable, it's the worst place
159 possible to store *any* secret. **DO NOT DO THIS IN A REAL WORLD
160 DEPLOYMENT**.
161 */
162 provision-user = pkgs.writeScriptBin "provision-user" ''
163 set -eux
164
165 # Waiting for pleroma to be up.
166 timeout 5m bash -c 'while [[ "$(curl -s -o /dev/null -w '%{http_code}' https://pleroma.nixos.test/api/v1/instance)" != "200" ]]; do sleep 2; done'
167 # Toremove the RELEASE_COOKIE bit when https://github.com/NixOS/nixpkgs/issues/166229 gets fixed.
168 RELEASE_COOKIE="/var/lib/pleroma/.cookie" \
169 pleroma_ctl user new jamy jamy@nixos.test --password 'jamy-password' --moderator --admin -y
170 '';
171
172 tls-cert = pkgs.runCommand "selfSignedCerts" { buildInputs = [ pkgs.openssl ]; } ''
173 mkdir -p $out
174 openssl req -x509 \
175 -subj '/CN=pleroma.nixos.test/' -days 49710 \
176 -addext 'subjectAltName = DNS:pleroma.nixos.test' \
177 -keyout "$out/key.pem" -newkey ed25519 \
178 -out "$out/cert.pem" -noenc
179 '';
180
181 hosts = nodes: ''
182 ${nodes.pleroma.networking.primaryIPAddress} pleroma.nixos.test
183 ${nodes.client.networking.primaryIPAddress} client.nixos.test
184 '';
185 in
186 {
187 name = "pleroma";
188 nodes = {
189 client =
190 {
191 nodes,
192 pkgs,
193 config,
194 ...
195 }:
196 {
197 security.pki.certificateFiles = [ "${tls-cert}/cert.pem" ];
198 networking.extraHosts = hosts nodes;
199 environment.systemPackages = [
200 pkgs.toot
201 send-toot
202 ];
203 };
204 pleroma =
205 {
206 nodes,
207 pkgs,
208 config,
209 ...
210 }:
211 {
212 security.pki.certificateFiles = [ "${tls-cert}/cert.pem" ];
213 networking.extraHosts = hosts nodes;
214 networking.firewall.enable = false;
215 environment.systemPackages = [
216 provision-db
217 provision-secrets
218 provision-user
219 ];
220 services = {
221 pleroma = {
222 enable = true;
223 configs = [
224 pleroma-conf
225 ];
226 };
227 postgresql = {
228 enable = true;
229 package = pkgs.postgresql_13;
230 };
231 nginx = {
232 enable = true;
233 virtualHosts."pleroma.nixos.test" = {
234 addSSL = true;
235 sslCertificate = "${tls-cert}/cert.pem";
236 sslCertificateKey = "${tls-cert}/key.pem";
237 locations."/" = {
238 proxyPass = "http://127.0.0.1:4000";
239 extraConfig = ''
240 add_header 'Access-Control-Allow-Origin' '*' always;
241 add_header 'Access-Control-Allow-Methods' 'POST, PUT, DELETE, GET, PATCH, OPTIONS' always;
242 add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, Idempotency-Key' always;
243 add_header 'Access-Control-Expose-Headers' 'Link, X-RateLimit-Reset, X-RateLimit-Limit, X-RateLimit-Remaining, X-Request-Id' always;
244 if ($request_method = OPTIONS) {
245 return 204;
246 }
247 add_header X-Permitted-Cross-Domain-Policies none;
248 add_header X-Frame-Options DENY;
249 add_header X-Content-Type-Options nosniff;
250 add_header Referrer-Policy same-origin;
251 add_header X-Download-Options noopen;
252 proxy_http_version 1.1;
253 proxy_set_header Upgrade $http_upgrade;
254 proxy_set_header Connection "upgrade";
255 proxy_set_header Host $host;
256 client_max_body_size 16m;
257 '';
258 };
259 };
260 };
261 };
262 };
263 };
264
265 testScript =
266 { nodes, ... }:
267 ''
268 pleroma.wait_for_unit("postgresql.target")
269 pleroma.wait_until_succeeds("ls /var/lib/pleroma")
270 pleroma.succeed("provision-db")
271 pleroma.wait_for_file("/var/lib/pleroma")
272 pleroma.succeed("provision-secrets")
273 pleroma.systemctl("restart pleroma-migrations.service")
274 pleroma.systemctl("restart pleroma.service")
275 pleroma.wait_for_unit("pleroma.service")
276 pleroma.succeed("provision-user")
277 client.succeed("send-toot")
278 '';
279
280 meta.timeout = 600;
281 }
282)