From 60b730fd944b6e42bc185dd92ed8cb71e48d795b Mon Sep 17 00:00:00 2001 From: Félix Baylac-Jacqué Date: Sun, 8 Nov 2020 15:10:14 +0100 Subject: nixos/pleroma: add NixOS VM test. --- nixos/tests/pleroma.nix | 265 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 265 insertions(+) create mode 100644 nixos/tests/pleroma.nix (limited to 'nixos/tests/pleroma.nix') diff --git a/nixos/tests/pleroma.nix b/nixos/tests/pleroma.nix new file mode 100644 index 00000000000..797cac44f95 --- /dev/null +++ b/nixos/tests/pleroma.nix @@ -0,0 +1,265 @@ +/* + Pleroma E2E VM test. + + Abstract: + ========= + Using pleroma, postgresql, a local CA cert, a nginx reverse proxy + and a toot-based client, we're going to: + + 1. Provision a pleroma service from scratch (pleroma config + postgres db). + 2. Create a "jamy" admin user. + 3. Send a toot from this user. + 4. Send a upload from this user. + 5. Check the toot is part of the server public timeline + + Notes: + - We need a fully functional TLS setup without having any access to + the internet. We do that by issuing a self-signed cert, add this + self-cert to the hosts pki trust store and finally spoof the + hostnames using /etc/hosts. + - For this NixOS test, we *had* to store some DB-related and + pleroma-related secrets to the store. Keep in mind the store is + world-readable, it's the worst place possible to store *any* + secret. **DO NOT DO THIS IN A REAL WORLD DEPLOYMENT**. +*/ + +import ./make-test-python.nix ({ pkgs, ... }: + let + send-toot = pkgs.writeScriptBin "send-toot" '' + set -eux + # toot is using the requests library internally. This library + # sadly embed its own certificate store instead of relying on the + # system one. Overriding this pretty bad default behaviour. + export REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt + + export TOOT_LOGIN_CLI_PASSWORD="jamy-password" + toot login_cli -i "pleroma.nixos.test" -e "jamy@nixos.test" + echo "Login OK" + + # Send a toot then verify it's part of the public timeline + echo "y" | toot post "hello world Jamy here" + echo "Send toot OK" + echo "y" | toot timeline | grep -c "hello world Jamy here" + echo "Get toot from timeline OK" + + # Test file upload + echo "y" | toot upload ${db-seed} | grep -c "https://pleroma.nixos.test/media" + echo "File upload OK" + + echo "=====================================================" + echo "= SUCCESS =" + echo "= =" + echo "= We were able to sent a toot + a upload and =" + echo "= retrieve both of them in the public timeline. =" + echo "=====================================================" + ''; + + provision-db = pkgs.writeScriptBin "provision-db" '' + set -eux + sudo -u postgres psql -f ${db-seed} + ''; + + test-db-passwd = "SccZOvTGM//BMrpoQj68JJkjDkMGb4pHv2cECWiI+XhVe3uGJTLI0vFV/gDlZ5jJ"; + + /* For this NixOS test, we *had* to store this secret to the store. + Keep in mind the store is world-readable, it's the worst place + possible to store *any* secret. **DO NOT DO THIS IN A REAL WORLD + DEPLOYMENT**.*/ + db-seed = pkgs.writeText "provision.psql" '' + CREATE USER pleroma WITH ENCRYPTED PASSWORD '${test-db-passwd}'; + CREATE DATABASE pleroma OWNER pleroma; + \c pleroma; + --Extensions made by ecto.migrate that need superuser access + CREATE EXTENSION IF NOT EXISTS citext; + CREATE EXTENSION IF NOT EXISTS pg_trgm; + CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; + ''; + + pleroma-conf = '' + import Config + + config :pleroma, Pleroma.Web.Endpoint, + url: [host: "pleroma.nixos.test", scheme: "https", port: 443], + http: [ip: {127, 0, 0, 1}, port: 4000] + + config :pleroma, :instance, + name: "NixOS test pleroma server", + email: "pleroma@nixos.test", + notify_email: "pleroma@nixos.test", + limit: 5000, + registrations_open: true + + config :pleroma, :media_proxy, + enabled: false, + redirect_on_failure: true + #base_url: "https://cache.pleroma.social" + + config :pleroma, Pleroma.Repo, + adapter: Ecto.Adapters.Postgres, + username: "pleroma", + password: "${test-db-passwd}", + database: "pleroma", + hostname: "localhost", + pool_size: 10, + prepare: :named, + parameters: [ + plan_cache_mode: "force_custom_plan" + ] + + config :pleroma, :database, rum_enabled: false + config :pleroma, :instance, static_dir: "/var/lib/pleroma/static" + config :pleroma, Pleroma.Uploaders.Local, uploads: "/var/lib/pleroma/uploads" + config :pleroma, configurable_from_database: false + ''; + + /* For this NixOS test, we *had* to store this secret to the store. + Keep in mind the store is world-readable, it's the worst place + possible to store *any* secret. **DO NOT DO THIS IN A REAL WORLD + DEPLOYMENT**. + In a real-word deployment, you'd handle this either by: + - manually upload your pleroma secrets to /var/lib/pleroma/secrets.exs + - use a deployment tool such as morph or NixOps to deploy your secrets. + */ + pleroma-conf-secret = pkgs.writeText "secrets.exs" '' + import Config + + config :joken, default_signer: "PS69/wMW7X6FIQPABt9lwvlZvgrJIncfiAMrK9J5mjVus/7/NJJi1DsDA1OghBE5" + + config :pleroma, Pleroma.Web.Endpoint, + secret_key_base: "NvfmU7lYaQrmmxt4NACm0AaAfN9t6WxsrX0NCB4awkGHvr1S7jyshlEmrjaPFhhq", + signing_salt: "3L41+BuJ" + + config :web_push_encryption, :vapid_details, + subject: "mailto:pleroma@nixos.test", + public_key: "BKjfNX9-UqAcncaNqERQtF7n9pKrB0-MO-juv6U5E5XQr_Tg5D-f8AlRjduAguDpyAngeDzG8MdrTejMSL4VF30", + private_key: "k7o9onKMQrgMjMb6l4fsxSaXO0BTNAer5MVSje3q60k" + ''; + + /* For this NixOS test, we *had* to store this secret to the store. + Keep in mind the store is world-readable, it's the worst place + possible to store *any* secret. **DO NOT DO THIS IN A REAL WORLD + DEPLOYMENT**. + In a real-word deployment, you'd handle this either by: + - manually upload your pleroma secrets to /var/lib/pleroma/secrets.exs + - use a deployment tool such as morph or NixOps to deploy your secrets. + */ + provision-secrets = pkgs.writeScriptBin "provision-secrets" '' + set -eux + cp "${pleroma-conf-secret}" "/var/lib/pleroma/secrets.exs" + chown pleroma:pleroma /var/lib/pleroma/secrets.exs + ''; + + /* For this NixOS test, we *had* to store this secret to the store. + Keep in mind the store is world-readable, it's the worst place + possible to store *any* secret. **DO NOT DO THIS IN A REAL WORLD + DEPLOYMENT**. + */ + provision-user = pkgs.writeScriptBin "provision-user" '' + set -eux + + # Waiting for pleroma to be up. + 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' + pleroma_ctl user new jamy jamy@nixos.test --password 'jamy-password' --moderator --admin -y + ''; + + tls-cert = pkgs.runCommandNoCC "selfSignedCerts" { buildInputs = [ pkgs.openssl ]; } '' + openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -nodes -subj '/CN=pleroma.nixos.test' + mkdir -p $out + cp key.pem cert.pem $out + ''; + + /* Toot is preventing users from feeding login_cli a password non + interactively. While it makes sense most of the times, it's + preventing us to login in this non-interactive test. This patch + introduce a TOOT_LOGIN_CLI_PASSWORD env variable allowing us to + provide a password to toot login_cli + + If https://github.com/ihabunek/toot/pull/180 gets merged at some + point, feel free to remove this patch. */ + custom-toot = pkgs.toot.overrideAttrs(old:{ + patches = [ (pkgs.fetchpatch { + url = "https://github.com/NinjaTrappeur/toot/commit/b4a4c30f41c0cb7e336714c2c4af9bc9bfa0c9f2.patch"; + sha256 = "sha256-0xxNwjR/fStLjjUUhwzCCfrghRVts+fc+fvVJqVcaFg="; + }) ]; + }); + + hosts = nodes: '' + ${nodes.pleroma.config.networking.primaryIPAddress} pleroma.nixos.test + ${nodes.client.config.networking.primaryIPAddress} client.nixos.test + ''; + in { + name = "pleroma"; + nodes = { + client = { nodes, pkgs, config, ... }: { + security.pki.certificateFiles = [ "${tls-cert}/cert.pem" ]; + networking.extraHosts = hosts nodes; + environment.systemPackages = with pkgs; [ + custom-toot + send-toot + ]; + }; + pleroma = { nodes, pkgs, config, ... }: { + security.pki.certificateFiles = [ "${tls-cert}/cert.pem" ]; + networking.extraHosts = hosts nodes; + networking.firewall.enable = false; + environment.systemPackages = with pkgs; [ + provision-db + provision-secrets + provision-user + ]; + services = { + pleroma = { + enable = true; + configs = [ + pleroma-conf + ]; + }; + postgresql = { + enable = true; + package = pkgs.postgresql_12; + }; + nginx = { + enable = true; + virtualHosts."pleroma.nixos.test" = { + addSSL = true; + sslCertificate = "${tls-cert}/cert.pem"; + sslCertificateKey = "${tls-cert}/key.pem"; + locations."/" = { + proxyPass = "http://127.0.0.1:4000"; + extraConfig = '' + add_header 'Access-Control-Allow-Origin' '*' always; + add_header 'Access-Control-Allow-Methods' 'POST, PUT, DELETE, GET, PATCH, OPTIONS' always; + add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, Idempotency-Key' always; + add_header 'Access-Control-Expose-Headers' 'Link, X-RateLimit-Reset, X-RateLimit-Limit, X-RateLimit-Remaining, X-Request-Id' always; + if ($request_method = OPTIONS) { + return 204; + } + add_header X-XSS-Protection "1; mode=block"; + add_header X-Permitted-Cross-Domain-Policies none; + add_header X-Frame-Options DENY; + add_header X-Content-Type-Options nosniff; + add_header Referrer-Policy same-origin; + add_header X-Download-Options noopen; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $host; + client_max_body_size 16m; + ''; + }; + }; + }; + }; + }; + }; + + testScript = { nodes, ... }: '' + pleroma.wait_for_unit("postgresql.service") + pleroma.succeed("provision-db") + pleroma.succeed("provision-secrets") + pleroma.systemctl("restart pleroma.service") + pleroma.wait_for_unit("pleroma.service") + pleroma.succeed("provision-user") + client.succeed("send-toot") + ''; +}) -- cgit 1.4.1