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 ({ pkgs, ... }:
27 let
28 send-toot = pkgs.writeScriptBin "send-toot" ''
29 set -eux
30 # toot is using the requests library internally. This library
31 # sadly embed its own certificate store instead of relying on the
32 # system one. Overriding this pretty bad default behaviour.
33 export REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
34
35 export TOOT_LOGIN_CLI_PASSWORD="jamy-password"
36 toot login_cli -i "pleroma.nixos.test" -e "jamy@nixos.test"
37 echo "Login OK"
38
39 # Send a toot then verify it's part of the public timeline
40 echo "y" | toot post "hello world Jamy here"
41 echo "Send toot OK"
42 echo "y" | toot timeline | grep -c "hello world Jamy here"
43 echo "Get toot from timeline OK"
44
45 # Test file upload
46 echo "y" | toot upload ${db-seed} | grep -c "https://pleroma.nixos.test/media"
47 echo "File upload OK"
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 /* For this NixOS test, we *had* to store this secret to the store.
65 Keep in mind the store is world-readable, it's the worst place
66 possible to store *any* secret. **DO NOT DO THIS IN A REAL WORLD
67 DEPLOYMENT**.*/
68 db-seed = pkgs.writeText "provision.psql" ''
69 CREATE USER pleroma WITH ENCRYPTED PASSWORD '${test-db-passwd}';
70 CREATE DATABASE pleroma OWNER pleroma;
71 \c pleroma;
72 --Extensions made by ecto.migrate that need superuser access
73 CREATE EXTENSION IF NOT EXISTS citext;
74 CREATE EXTENSION IF NOT EXISTS pg_trgm;
75 CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
76 '';
77
78 pleroma-conf = ''
79 import Config
80
81 config :pleroma, Pleroma.Web.Endpoint,
82 url: [host: "pleroma.nixos.test", scheme: "https", port: 443],
83 http: [ip: {127, 0, 0, 1}, port: 4000]
84
85 config :pleroma, :instance,
86 name: "NixOS test pleroma server",
87 email: "pleroma@nixos.test",
88 notify_email: "pleroma@nixos.test",
89 limit: 5000,
90 registrations_open: true
91
92 config :pleroma, :media_proxy,
93 enabled: false,
94 redirect_on_failure: true
95 #base_url: "https://cache.pleroma.social"
96
97 config :pleroma, Pleroma.Repo,
98 adapter: Ecto.Adapters.Postgres,
99 username: "pleroma",
100 password: "${test-db-passwd}",
101 database: "pleroma",
102 hostname: "localhost",
103 pool_size: 10,
104 prepare: :named,
105 parameters: [
106 plan_cache_mode: "force_custom_plan"
107 ]
108
109 config :pleroma, :database, rum_enabled: false
110 config :pleroma, :instance, static_dir: "/var/lib/pleroma/static"
111 config :pleroma, Pleroma.Uploaders.Local, uploads: "/var/lib/pleroma/uploads"
112 config :pleroma, configurable_from_database: false
113 '';
114
115 /* For this NixOS test, we *had* to store this secret to the store.
116 Keep in mind the store is world-readable, it's the worst place
117 possible to store *any* secret. **DO NOT DO THIS IN A REAL WORLD
118 DEPLOYMENT**.
119 In a real-word deployment, you'd handle this either by:
120 - manually upload your pleroma secrets to /var/lib/pleroma/secrets.exs
121 - use a deployment tool such as morph or NixOps to deploy your secrets.
122 */
123 pleroma-conf-secret = pkgs.writeText "secrets.exs" ''
124 import Config
125
126 config :joken, default_signer: "PS69/wMW7X6FIQPABt9lwvlZvgrJIncfiAMrK9J5mjVus/7/NJJi1DsDA1OghBE5"
127
128 config :pleroma, Pleroma.Web.Endpoint,
129 secret_key_base: "NvfmU7lYaQrmmxt4NACm0AaAfN9t6WxsrX0NCB4awkGHvr1S7jyshlEmrjaPFhhq",
130 signing_salt: "3L41+BuJ"
131
132 config :web_push_encryption, :vapid_details,
133 subject: "mailto:pleroma@nixos.test",
134 public_key: "BKjfNX9-UqAcncaNqERQtF7n9pKrB0-MO-juv6U5E5XQr_Tg5D-f8AlRjduAguDpyAngeDzG8MdrTejMSL4VF30",
135 private_key: "k7o9onKMQrgMjMb6l4fsxSaXO0BTNAer5MVSje3q60k"
136 '';
137
138 /* For this NixOS test, we *had* to store this secret to the store.
139 Keep in mind the store is world-readable, it's the worst place
140 possible to store *any* secret. **DO NOT DO THIS IN A REAL WORLD
141 DEPLOYMENT**.
142 In a real-word deployment, you'd handle this either by:
143 - manually upload your pleroma secrets to /var/lib/pleroma/secrets.exs
144 - use a deployment tool such as morph or NixOps to deploy your secrets.
145 */
146 provision-secrets = pkgs.writeScriptBin "provision-secrets" ''
147 set -eux
148 cp "${pleroma-conf-secret}" "/var/lib/pleroma/secrets.exs"
149 chown pleroma:pleroma /var/lib/pleroma/secrets.exs
150 '';
151
152 /* For this NixOS test, we *had* to store this secret to the store.
153 Keep in mind the store is world-readable, it's the worst place
154 possible to store *any* secret. **DO NOT DO THIS IN A REAL WORLD
155 DEPLOYMENT**.
156 */
157 provision-user = pkgs.writeScriptBin "provision-user" ''
158 set -eux
159
160 # Waiting for pleroma to be up.
161 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'
162 pleroma_ctl user new jamy jamy@nixos.test --password 'jamy-password' --moderator --admin -y
163 '';
164
165 tls-cert = pkgs.runCommand "selfSignedCerts" { buildInputs = [ pkgs.openssl ]; } ''
166 openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -nodes -subj '/CN=pleroma.nixos.test' -days 36500
167 mkdir -p $out
168 cp key.pem cert.pem $out
169 '';
170
171 /* Toot is preventing users from feeding login_cli a password non
172 interactively. While it makes sense most of the times, it's
173 preventing us to login in this non-interactive test. This patch
174 introduce a TOOT_LOGIN_CLI_PASSWORD env variable allowing us to
175 provide a password to toot login_cli
176
177 If https://github.com/ihabunek/toot/pull/180 gets merged at some
178 point, feel free to remove this patch. */
179 custom-toot = pkgs.toot.overrideAttrs(old:{
180 patches = [ (pkgs.fetchpatch {
181 url = "https://github.com/NinjaTrappeur/toot/commit/b4a4c30f41c0cb7e336714c2c4af9bc9bfa0c9f2.patch";
182 sha256 = "sha256-0xxNwjR/fStLjjUUhwzCCfrghRVts+fc+fvVJqVcaFg=";
183 }) ];
184 });
185
186 hosts = nodes: ''
187 ${nodes.pleroma.config.networking.primaryIPAddress} pleroma.nixos.test
188 ${nodes.client.config.networking.primaryIPAddress} client.nixos.test
189 '';
190 in {
191 name = "pleroma";
192 nodes = {
193 client = { nodes, pkgs, config, ... }: {
194 security.pki.certificateFiles = [ "${tls-cert}/cert.pem" ];
195 networking.extraHosts = hosts nodes;
196 environment.systemPackages = with pkgs; [
197 custom-toot
198 send-toot
199 ];
200 };
201 pleroma = { nodes, pkgs, config, ... }: {
202 security.pki.certificateFiles = [ "${tls-cert}/cert.pem" ];
203 networking.extraHosts = hosts nodes;
204 networking.firewall.enable = false;
205 environment.systemPackages = with pkgs; [
206 provision-db
207 provision-secrets
208 provision-user
209 ];
210 services = {
211 pleroma = {
212 enable = true;
213 configs = [
214 pleroma-conf
215 ];
216 };
217 postgresql = {
218 enable = true;
219 package = pkgs.postgresql_12;
220 };
221 nginx = {
222 enable = true;
223 virtualHosts."pleroma.nixos.test" = {
224 addSSL = true;
225 sslCertificate = "${tls-cert}/cert.pem";
226 sslCertificateKey = "${tls-cert}/key.pem";
227 locations."/" = {
228 proxyPass = "http://127.0.0.1:4000";
229 extraConfig = ''
230 add_header 'Access-Control-Allow-Origin' '*' always;
231 add_header 'Access-Control-Allow-Methods' 'POST, PUT, DELETE, GET, PATCH, OPTIONS' always;
232 add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, Idempotency-Key' always;
233 add_header 'Access-Control-Expose-Headers' 'Link, X-RateLimit-Reset, X-RateLimit-Limit, X-RateLimit-Remaining, X-Request-Id' always;
234 if ($request_method = OPTIONS) {
235 return 204;
236 }
237 add_header X-XSS-Protection "1; mode=block";
238 add_header X-Permitted-Cross-Domain-Policies none;
239 add_header X-Frame-Options DENY;
240 add_header X-Content-Type-Options nosniff;
241 add_header Referrer-Policy same-origin;
242 add_header X-Download-Options noopen;
243 proxy_http_version 1.1;
244 proxy_set_header Upgrade $http_upgrade;
245 proxy_set_header Connection "upgrade";
246 proxy_set_header Host $host;
247 client_max_body_size 16m;
248 '';
249 };
250 };
251 };
252 };
253 };
254 };
255
256 testScript = { nodes, ... }: ''
257 pleroma.wait_for_unit("postgresql.service")
258 pleroma.succeed("provision-db")
259 pleroma.succeed("provision-secrets")
260 pleroma.systemctl("restart pleroma.service")
261 pleroma.wait_for_unit("pleroma.service")
262 pleroma.succeed("provision-user")
263 client.succeed("send-toot")
264 '';
265})