1{ lib, ... }:
2
3let
4 domain = "http://glitchtip.local:8000";
5in
6
7{
8 name = "glitchtip";
9 meta.maintainers = with lib.maintainers; [
10 defelo
11 felbinger
12 ];
13
14 nodes.machine =
15 { pkgs, ... }:
16 {
17 services.glitchtip = {
18 enable = true;
19 port = 8000;
20 settings.GLITCHTIP_DOMAIN = domain;
21 environmentFiles = [
22 (builtins.toFile "glitchtip.env" ''
23 SECRET_KEY=8Hz7YCGzo7fiicHb8Qr22ZqwoIB7lSRx
24 '')
25 ];
26 };
27
28 environment.systemPackages = [ pkgs.sentry-cli ];
29
30 networking.hosts."127.0.0.1" = [ "glitchtip.local" ];
31 };
32
33 interactive.nodes.machine = {
34 services.glitchtip.listenAddress = "0.0.0.0";
35 networking.firewall.allowedTCPPorts = [ 8000 ];
36 virtualisation.forwardPorts = [
37 {
38 from = "host";
39 host.port = 8000;
40 guest.port = 8000;
41 }
42 ];
43 };
44
45 testScript =
46 { nodes, ... }: # python
47 ''
48 import json
49 import re
50 import time
51
52 machine.wait_for_unit("glitchtip.service")
53 machine.wait_for_unit("glitchtip-worker.service")
54 machine.wait_for_open_port(8000)
55
56 origin_url = "${domain}"
57 cookie_jar_path = "/tmp/cookies.txt"
58 curl = f"curl -b {cookie_jar_path} -c {cookie_jar_path} -fS -H 'Origin: {origin_url}'"
59
60 # create superuser account
61 machine.succeed("DJANGO_SUPERUSER_PASSWORD=password glitchtip-manage createsuperuser --no-input --email=admin@example.com")
62
63 # login
64 machine.fail(f"{curl} -s {origin_url}/_allauth/browser/v1/auth/session") # get the csrf token, returns a 401
65 csrf_token = machine.succeed(f"grep csrftoken {cookie_jar_path} | cut -f7").rstrip()
66 machine.succeed(f"{curl} {origin_url}/_allauth/browser/v1/auth/login -s -H 'X-Csrftoken: {csrf_token}' -H 'Content-Type: application/json' -d '{{\"email\": \"admin@example.com\", \"password\": \"password\"}}'")
67
68 resp = json.loads(machine.succeed(f"{curl} {origin_url}/api/0/users/me/"))
69 assert resp["email"] == "admin@example.com"
70 assert resp["isSuperuser"] is True
71
72 # create organization
73 csrf_token = machine.succeed(f"grep csrftoken {cookie_jar_path} | cut -f7").rstrip()
74 machine.succeed(f"{curl} {origin_url}/api/0/organizations/ -s -H 'X-Csrftoken: {csrf_token}' -H 'Content-Type: application/json' -d '{{\"name\": \"main\"}}'")
75
76 resp = json.loads(machine.succeed(f"{curl} {origin_url}/api/0/organizations/"))
77 assert len(resp) == 1
78 assert resp[0]["name"] == "main"
79 assert resp[0]["slug"] == "main"
80
81 # create team
82 csrf_token = machine.succeed(f"grep csrftoken {cookie_jar_path} | cut -f7").rstrip()
83 machine.succeed(f"{curl} {origin_url}/api/0/organizations/main/teams/ -s -H 'X-Csrftoken: {csrf_token}' -H 'Content-Type: application/json' -d '{{\"slug\": \"test\"}}'")
84
85 # create project
86 csrf_token = machine.succeed(f"grep csrftoken {cookie_jar_path} | cut -f7").rstrip()
87 machine.succeed(f"{curl} {origin_url}/api/0/teams/main/test/projects/ -s -H 'X-Csrftoken: {csrf_token}' -H 'Content-Type: application/json' -d '{{\"name\": \"test\"}}'")
88
89 # fetch dsn
90 resp = json.loads(machine.succeed(f"{curl} {origin_url}/api/0/projects/main/test/keys/"))
91 assert len(resp) == 1
92 assert re.match(r"^http://[\da-f]+@glitchtip\.local:8000/\d+$", dsn := resp[0]["dsn"]["public"])
93
94 # send event
95 machine.succeed(f"SENTRY_DSN={dsn} sentry-cli send-event -m 'hello world'")
96
97 for _ in range(20):
98 resp = json.loads(machine.succeed(f"{curl} {origin_url}/api/0/organizations/main/issues/?query=is:unresolved"))
99 if len(resp) != 0: break
100 time.sleep(1)
101 assert len(resp) == 1
102 assert resp[0]["title"] == "hello world"
103 assert int(resp[0]["count"]) == 1
104
105 # create api token
106 csrf_token = machine.succeed(f"grep csrftoken {cookie_jar_path} | cut -f7").rstrip()
107 resp = json.loads(machine.succeed(f"{curl} {origin_url}/api/0/api-tokens/ -s -H 'X-Csrftoken: {csrf_token}' -H 'Content-Type: application/json' -d '{{\"label\":\"token\",\"scopes\":[\"project:write\"]}}'"))
108 token = resp["token"]
109
110 # upload sourcemaps
111 machine.succeed(f"sentry-cli --url {origin_url} --auth-token {token} sourcemaps upload --org main --project test ${nodes.machine.services.glitchtip.package.frontend}/*.map")
112 assert machine.succeed("ls /var/lib/glitchtip/uploads/file_blobs/").strip()
113 '';
114}