carlos / movement Public

Clone
git clone https://amadan.net/carlos/movement

Plain git — no account needed to clone.

Download

Download this file

1package movement
2
3import (
4 "strings"
5 "testing"
6)
7
8// setEnv installs a complete, valid environment and lets a caller override
9// pieces of it, so each test says only what it is actually about.
10func setEnv(t *testing.T, over map[string]string) {
11 t.Helper()
12 base := map[string]string{
13 "MOVEMENT_ORIGIN": "https://" + CanonicalHost,
14 "MOVEMENT_INSTANCE_KEY": strings.Repeat("a", 64),
15 "MOVEMENT_ADMINS": "",
16 "CARLOS_SMTP_HOST": "smtp.example.com",
17 "CARLOS_SMTP_FROM": "movement@example.com",
18 }
19 for k, v := range over {
20 base[k] = v
21 }
22 for k, v := range base {
23 t.Setenv(k, v)
24 }
25}
26
27func TestLoadEnvRefusesMissingOriginAndKey(t *testing.T) {
28 setEnv(t, map[string]string{"MOVEMENT_ORIGIN": "", "MOVEMENT_INSTANCE_KEY": ""})
29
30 _, err := LoadEnv()
31 if err == nil {
32 t.Fatal("expected a refusal with no origin and no instance key")
33 }
34 // Both names, so an operator fixes it in one pass rather than two.
35 for _, want := range []string{"MOVEMENT_ORIGIN", "MOVEMENT_INSTANCE_KEY"} {
36 if !strings.Contains(err.Error(), want) {
37 t.Errorf("refusal should name %s, got: %v", want, err)
38 }
39 }
40}
41
42func TestLoadEnvRefusesUnconfiguredMailOnPublicOrigin(t *testing.T) {
43 setEnv(t, map[string]string{"CARLOS_SMTP_HOST": "", "CARLOS_SMTP_FROM": ""})
44
45 // mail.Logged would write the confirmation token and the address into
46 // carlos logs, which cannot be grepped clean afterwards.
47 if _, err := LoadEnv(); err == nil {
48 t.Fatal("expected a refusal: the mail.Logged fallback leaks into carlos logs")
49 }
50}
51
52func TestLoadEnvAllowsUnconfiguredMailOnLoopback(t *testing.T) {
53 setEnv(t, map[string]string{
54 "MOVEMENT_ORIGIN": "http://127.0.0.1:8080",
55 "CARLOS_SMTP_HOST": "",
56 "CARLOS_SMTP_FROM": "",
57 })
58
59 if _, err := LoadEnv(); err != nil {
60 t.Fatalf("loopback development should warn, not refuse: %v", err)
61 }
62}
63
64func TestAdminAllowlistIsEmptyByDefaultAndCaseInsensitive(t *testing.T) {
65 setEnv(t, map[string]string{"MOVEMENT_ADMINS": ""})
66 env, err := LoadEnv()
67 if err != nil {
68 t.Fatal(err)
69 }
70 // The fail-closed state: nobody is an admin, and the routes 404.
71 if env.IsAdmin("paul@keymail.dev") {
72 t.Fatal("an empty allowlist must admit nobody")
73 }
74
75 setEnv(t, map[string]string{"MOVEMENT_ADMINS": " Paul@Keymail.dev , other@example.com "})
76 env, err = LoadEnv()
77 if err != nil {
78 t.Fatal(err)
79 }
80 if !env.IsAdmin("PAUL@keymail.DEV") {
81 t.Fatal("the allowlist must match regardless of case or surrounding space")
82 }
83 if env.IsAdmin("stranger@example.com") {
84 t.Fatal("a stranger must not be admitted")
85 }
86 if env.IsAdmin("") {
87 t.Fatal("an empty address must never be admitted")
88 }
89}
90