better defaults

1bba52e · gmorell · 2026-05-21 01:08

33 files +667 -30

Files changed

modified config/runtime.exs
+25 −4
@@ -40,11 +40,32 @@ if net = System.get_env("IRC_NETWORK_NAME") do
40 40 config :oh_my_ex_oh_ircd, OhMyExOhIrcd.IRC.Listener, network_name: net
41 41 end
42 42
43 −# Only override allow_anonymous when explicitly set, so compile-time config
44 −# (config/dev.exs etc.) wins by default.
45 −if anon = System.get_env("IRC_ALLOW_ANONYMOUS") do
43 +# Anonymous IRC access — default ON in prod releases (set
44 +# IRC_ALLOW_ANONYMOUS=false to lock it down). Dev/test compile-time
45 +# config wins outside prod.
46 +if config_env() == :prod do
47 + allow_anonymous =
48 + case System.get_env("IRC_ALLOW_ANONYMOUS") do
49 + nil -> true
50 + val -> val in ~w(1 true yes on)
51 + end
52 +
46 53 config :oh_my_ex_oh_ircd, OhMyExOhIrcd.IRC.Listener,
47 − allow_anonymous: anon in ~w(1 true yes on)
54 + allow_anonymous: allow_anonymous
55 +end
56 +
57 +# Web user registration mode. Default invite-only at runtime (prod
58 +# releases). Explicit env-gating so dev/test configs win when set.
59 +# Mint invite tokens with `mix invites.create` (or `bin/… eval` in a
60 +# running release).
61 +if config_env() == :prod do
62 + registration_mode =
63 + case System.get_env("REGISTRATION_MODE") do
64 + "open" -> :open
65 + _ -> :invite_only
66 + end
67 +
68 + config :oh_my_ex_oh_ircd, :registration_mode, registration_mode
48 69 end
49 70
50 71 # TLS listener cert paths from env. In the :kubernetes build these point at
modified config/test.exs
+5 −0
@@ -3,6 +3,11 @@ import Config
3 3 # Only in tests, remove the complexity from the password hashing algorithm
4 4 config :bcrypt_elixir, :log_rounds, 1
5 5
6 +# Keep existing user-registration tests working — runtime.exs defaults
7 +# to `:invite_only`, but the test suite was written against open signup.
8 +# Tests that exercise the invite gate can `Application.put_env/3` per-test.
9 +config :oh_my_ex_oh_ircd, :registration_mode, :open
10 +
6 11 # Bind the app-level IRC listener to an ephemeral port during tests so
7 12 # `mix test` never fights with whatever's on 6667 (or a previous test run
8 13 # that leaked the socket). Real assertions all spin up their own listener
added deploy/argo/neiam-ircd/app.yml
+212 −0
@@ -0,0 +1,212 @@
1 +apiVersion: apps/v1
2 +kind: Deployment
3 +metadata:
4 + name: ircd
5 + namespace: neiam-ircd
6 + labels:
7 + name: ircd
8 + keel.sh/policy: force
9 + keel.sh/trigger: poll
10 +spec:
11 + replicas: 3
12 + selector:
13 + matchLabels:
14 + app: ircd
15 + strategy:
16 + type: RollingUpdate
17 + rollingUpdate:
18 + maxUnavailable: 0
19 + maxSurge: 1
20 + template:
21 + metadata:
22 + labels:
23 + app: ircd
24 + spec:
25 + serviceAccountName: ircd
26 + terminationGracePeriodSeconds: 30
27 + containers:
28 + - name: ircd
29 + image: r.g.gmp.io/neiam/ohmyxo:kubernetes-master
30 + imagePullPolicy: Always
31 + ports:
32 + - { name: http, containerPort: 4000 }
33 + - { name: irc, containerPort: 6667 }
34 + - { name: ircs, containerPort: 6697 }
35 + - { name: epmd, containerPort: 4369 }
36 + - { name: dist, containerPort: 9100 }
37 + env:
38 + # Phoenix bring-up
39 + - { name: PHX_SERVER, value: "true" }
40 + - { name: PHX_HOST, value: "irc.skyjeep.club" }
41 + - { name: PORT, value: "4000" }
42 +
43 + # IRC config
44 + - { name: IRC_PORT, value: "6667" }
45 + - { name: IRC_SERVER_NAME, value: "irc.skyjeep.club" }
46 + - { name: IRC_NETWORK_NAME, value: "SkyjeepIRC" }
47 + # Defaults in runtime.exs: anonymous IRC ON, web registration
48 + # invite-only. Uncomment to override:
49 + # - { name: IRC_ALLOW_ANONYMOUS, value: "false" }
50 + # - { name: REGISTRATION_MODE, value: "open" }
51 +
52 + # TLS — cert files come from the cert-manager Secret below.
53 + - { name: IRC_TLS_ENABLED, value: "true" }
54 + - { name: IRC_TLS_PORT, value: "6697" }
55 + - { name: IRC_TLS_CERT_PATH, value: "/etc/tls/tls.crt" }
56 + - { name: IRC_TLS_KEY_PATH, value: "/etc/tls/tls.key" }
57 +
58 + # BEAM cluster
59 + - { name: CLUSTER_STRATEGY, value: "kubernetes" }
60 + - { name: CLUSTER_K8S_NAMESPACE, value: "neiam-ircd" }
61 + - { name: CLUSTER_K8S_SERVICE, value: "ircd-headless" }
62 + - { name: CLUSTER_K8S_APP_NAME, value: "ircd" }
63 + - { name: CLUSTER_K8S_SELECTOR, value: "app=ircd" }
64 + - name: POD_IP
65 + valueFrom: { fieldRef: { fieldPath: status.podIP } }
66 +
67 + # StackGres-generated DB credentials
68 + - name: POSTGRES_USER
69 + valueFrom:
70 + secretKeyRef: { name: postgres-ircd, key: superuser-username }
71 + - name: POSTGRES_PASSWORD
72 + valueFrom:
73 + secretKeyRef: { name: postgres-ircd, key: superuser-password }
74 + - { name: POSTGRES_HOST, value: "postgres-ircd" }
75 + - { name: POSTGRES_PORT, value: "5432" }
76 + - name: DATABASE_URL
77 + value: ecto://$(POSTGRES_USER):$(POSTGRES_PASSWORD)@$(POSTGRES_HOST):$(POSTGRES_PORT)/ircd
78 +
79 + # App secrets
80 + - name: SECRET_KEY_BASE
81 + valueFrom: { secretKeyRef: { name: ircd-secrets, key: SECRET_KEY_BASE } }
82 + - name: RELEASE_COOKIE
83 + valueFrom: { secretKeyRef: { name: ircd-secrets, key: RELEASE_COOKIE } }
84 +
85 + volumeMounts:
86 + - { name: tls, mountPath: /etc/tls, readOnly: true }
87 +
88 + readinessProbe:
89 + httpGet: { path: /, port: http }
90 + initialDelaySeconds: 10
91 + periodSeconds: 5
92 + livenessProbe:
93 + tcpSocket: { port: irc }
94 + initialDelaySeconds: 30
95 + periodSeconds: 15
96 +
97 + resources:
98 + requests: { cpu: 100m, memory: 256Mi }
99 + limits: { cpu: 1, memory: 1Gi }
100 +
101 + imagePullSecrets:
102 + - name: gitlabgmp
103 + volumes:
104 + - name: tls
105 + secret:
106 + secretName: ircd-tls
107 +---
108 +# Headless Service for libcluster pod discovery.
109 +apiVersion: v1
110 +kind: Service
111 +metadata:
112 + name: ircd-headless
113 + namespace: neiam-ircd
114 +spec:
115 + clusterIP: None
116 + publishNotReadyAddresses: true
117 + selector:
118 + app: ircd
119 + ports:
120 + - { name: epmd, port: 4369, targetPort: 4369 }
121 + - { name: dist, port: 9100, targetPort: 9100 }
122 +---
123 +# Web UI service, fronted by Traefik via the Ingress below.
124 +apiVersion: v1
125 +kind: Service
126 +metadata:
127 + name: ircd-web
128 + namespace: neiam-ircd
129 +spec:
130 + selector:
131 + app: ircd
132 + ports:
133 + - { name: http, port: 80, targetPort: 4000 }
134 +---
135 +# Plain + TLS IRC service. Traefik routes TCP from public entryPoints
136 +# to these ports via the IngressRouteTCPs below.
137 +apiVersion: v1
138 +kind: Service
139 +metadata:
140 + name: ircd-irc
141 + namespace: neiam-ircd
142 +spec:
143 + selector:
144 + app: ircd
145 + ports:
146 + - { name: irc, port: 6667, targetPort: 6667 }
147 + - { name: ircs, port: 6697, targetPort: 6697 }
148 +---
149 +# HTTPS Ingress for the Phoenix LiveView / web UI.
150 +apiVersion: networking.k8s.io/v1
151 +kind: Ingress
152 +metadata:
153 + name: ircd-web
154 + namespace: neiam-ircd
155 + annotations:
156 + cert-manager.io/cluster-issuer: letsencrypt-prod
157 + kubernetes.io/ingress.class: traefik
158 +spec:
159 + tls:
160 + - hosts: [irc.skyjeep.club]
161 + secretName: ircd-tls
162 + rules:
163 + - host: irc.skyjeep.club
164 + http:
165 + paths:
166 + - path: /
167 + pathType: Prefix
168 + backend:
169 + service:
170 + name: ircd-web
171 + port: { number: 80 }
172 +---
173 +# Traefik raw-TCP routing for the IRC plain port. Assumes a Traefik
174 +# entryPoint named `irc` listening on 6667 — add to your Traefik
175 +# static config:
176 +#
177 +# entryPoints:
178 +# irc:
179 +# address: ":6667"
180 +apiVersion: traefik.io/v1alpha1
181 +kind: IngressRouteTCP
182 +metadata:
183 + name: ircd-irc
184 + namespace: neiam-ircd
185 +spec:
186 + entryPoints: [ircd]
187 + routes:
188 + - match: HostSNI(`*`)
189 + services:
190 + - name: ircd-irc
191 + port: 6667
192 +---
193 +# Traefik TLS-passthrough for IRC-over-TLS. Termination happens inside
194 +# the IRC pod using the cert-manager-issued cert. Add to Traefik:
195 +#
196 +# entryPoints:
197 +# ircs:
198 +# address: ":6697"
199 +apiVersion: traefik.io/v1alpha1
200 +kind: IngressRouteTCP
201 +metadata:
202 + name: ircd-ircs
203 + namespace: neiam-ircd
204 +spec:
205 + entryPoints: [ircds]
206 + routes:
207 + - match: HostSNI(`*`)
208 + services:
209 + - name: ircd-irc
210 + port: 6697
211 + tls:
212 + passthrough: true
added deploy/argo/neiam-ircd/cert.yml
+19 −0
@@ -0,0 +1,19 @@
1 +# cert-manager Certificate — both the Ingress (web UI) and the IRC TLS
2 +# listener mount the resulting `ircd-tls` Secret. cert-manager rotates
3 +# in place; kubelet refreshes the projected volume; `:ssl` re-reads the
4 +# files on every new handshake.
5 +apiVersion: cert-manager.io/v1
6 +kind: Certificate
7 +metadata:
8 + name: ircd-tls
9 + namespace: neiam-ircd
10 +spec:
11 + secretName: ircd-tls
12 + duration: 2160h # 90d
13 + renewBefore: 360h # 15d
14 + issuerRef:
15 + name: letsencrypt-prod
16 + kind: ClusterIssuer
17 + commonName: irc.skyjeep.club
18 + dnsNames:
19 + - irc.skyjeep.club
added deploy/argo/neiam-ircd/ns.yml
+4 −0
@@ -0,0 +1,4 @@
1 +apiVersion: v1
2 +kind: Namespace
3 +metadata:
4 + name: neiam-ircd
added deploy/argo/neiam-ircd/pg.yml
+14 −0

Click to load diff…

added deploy/argo/neiam-ircd/rbac.yml
+31 −0

Click to load diff…

added deploy/argo/neiam-ircd/secrets.example.yml
+20 −0

Click to load diff…

added lib/mix/tasks/invites.ex
+77 −0

Click to load diff…

modified lib/oh_my_ex_oh_ircd/accounts.ex
+61 −0

Click to load diff…

added lib/oh_my_ex_oh_ircd/accounts/invite.ex
+46 −0

Click to load diff…

modified lib/oh_my_ex_oh_ircd_web/live/user_live/registration.ex
+77 −26

Click to load diff…

added priv/repo/migrations/20260525000000_create_user_invites.exs
+19 −0

Click to load diff…

added test/oh_my_ex_oh_ircd_web/live/user_live/registration_invite_test.exs
+57 −0

Click to load diff…

Parents: 0429b57