]> Git — Sourcephile - sourcephile-nix.git/blob - nixpkgs/patches/sourcehut.diff
sourcehut: update patch from nixpkgs#133984
[sourcephile-nix.git] / nixpkgs / patches / sourcehut.diff
1 diff --git a/nixos/lib/make-options-doc/options-to-docbook.xsl b/nixos/lib/make-options-doc/options-to-docbook.xsl
2 index da4cd164bf2..30190788f33 100644
3 --- a/nixos/lib/make-options-doc/options-to-docbook.xsl
4 +++ b/nixos/lib/make-options-doc/options-to-docbook.xsl
5 @@ -20,7 +20,7 @@
6 <title>Configuration Options</title>
7 <variablelist xml:id="configuration-variable-list">
8 <xsl:for-each select="attrs">
9 - <xsl:variable name="id" select="concat('opt-', str:replace(str:replace(str:replace(attr[@name = 'name']/string/@value, '*', '_'), '&lt;', '_'), '>', '_'))" />
10 + <xsl:variable name="id" select="concat('opt-', str:replace(str:replace(str:replace(str:replace(attr[@name = 'name']/string/@value, '*', '_'), '&lt;', '_'), '>', '_'), ':', '_'))" />
11 <varlistentry>
12 <term xlink:href="#{$id}">
13 <xsl:attribute name="xml:id"><xsl:value-of select="$id"/></xsl:attribute>
14 diff --git a/nixos/modules/services/databases/redis.nix b/nixos/modules/services/databases/redis.nix
15 index 578d9d9ec8d..e7ca0d4e34c 100644
16 --- a/nixos/modules/services/databases/redis.nix
17 +++ b/nixos/modules/services/databases/redis.nix
18 @@ -5,17 +5,18 @@ with lib;
19 let
20 cfg = config.services.redis;
21
22 - ulimitNofile = cfg.maxclients + 32;
23 -
24 mkValueString = value:
25 if value == true then "yes"
26 else if value == false then "no"
27 else generators.mkValueStringDefault { } value;
28
29 - redisConfig = pkgs.writeText "redis.conf" (generators.toKeyValue {
30 + redisConfig = settings: pkgs.writeText "redis.conf" (generators.toKeyValue {
31 listsAsDuplicateKeys = true;
32 mkKeyValue = generators.mkKeyValueDefault { inherit mkValueString; } " ";
33 - } cfg.settings);
34 + } settings);
35 +
36 + redisName = name: "redis" + optionalString (name != "") ("-"+name);
37 + enabledServers = filterAttrs (name: conf: conf.enable) config.services.redis.servers;
38
39 in {
40 imports = [
41 @@ -25,6 +26,27 @@ in {
42 (mkRemovedOptionModule [ "services" "redis" "appendOnlyFilename" ] "This option was never used.")
43 (mkRemovedOptionModule [ "services" "redis" "pidFile" ] "This option was removed.")
44 (mkRemovedOptionModule [ "services" "redis" "extraConfig" ] "Use services.redis.settings instead.")
45 + (mkRenamedOptionModule [ "services" "redis" "enable"] [ "services" "redis" "servers" "" "enable" ])
46 + (mkRenamedOptionModule [ "services" "redis" "port"] [ "services" "redis" "servers" "" "port" ])
47 + (mkRenamedOptionModule [ "services" "redis" "openFirewall"] [ "services" "redis" "servers" "" "openFirewall" ])
48 + (mkRenamedOptionModule [ "services" "redis" "bind"] [ "services" "redis" "servers" "" "bind" ])
49 + (mkRenamedOptionModule [ "services" "redis" "unixSocket"] [ "services" "redis" "servers" "" "unixSocket" ])
50 + (mkRenamedOptionModule [ "services" "redis" "unixSocketPerm"] [ "services" "redis" "servers" "" "unixSocketPerm" ])
51 + (mkRenamedOptionModule [ "services" "redis" "logLevel"] [ "services" "redis" "servers" "" "logLevel" ])
52 + (mkRenamedOptionModule [ "services" "redis" "logfile"] [ "services" "redis" "servers" "" "logfile" ])
53 + (mkRenamedOptionModule [ "services" "redis" "syslog"] [ "services" "redis" "servers" "" "syslog" ])
54 + (mkRenamedOptionModule [ "services" "redis" "databases"] [ "services" "redis" "servers" "" "databases" ])
55 + (mkRenamedOptionModule [ "services" "redis" "maxclients"] [ "services" "redis" "servers" "" "maxclients" ])
56 + (mkRenamedOptionModule [ "services" "redis" "save"] [ "services" "redis" "servers" "" "save" ])
57 + (mkRenamedOptionModule [ "services" "redis" "slaveOf"] [ "services" "redis" "servers" "" "slaveOf" ])
58 + (mkRenamedOptionModule [ "services" "redis" "masterAuth"] [ "services" "redis" "servers" "" "masterAuth" ])
59 + (mkRenamedOptionModule [ "services" "redis" "requirePass"] [ "services" "redis" "servers" "" "requirePass" ])
60 + (mkRenamedOptionModule [ "services" "redis" "requirePassFile"] [ "services" "redis" "servers" "" "requirePassFile" ])
61 + (mkRenamedOptionModule [ "services" "redis" "appendOnly"] [ "services" "redis" "servers" "" "appendOnly" ])
62 + (mkRenamedOptionModule [ "services" "redis" "appendFsync"] [ "services" "redis" "servers" "" "appendFsync" ])
63 + (mkRenamedOptionModule [ "services" "redis" "slowLogLogSlowerThan"] [ "services" "redis" "servers" "" "slowLogLogSlowerThan" ])
64 + (mkRenamedOptionModule [ "services" "redis" "slowLogMaxLen"] [ "services" "redis" "servers" "" "slowLogMaxLen" ])
65 + (mkRenamedOptionModule [ "services" "redis" "settings"] [ "services" "redis" "servers" "" "settings" ])
66 ];
67
68 ###### interface
69 @@ -32,18 +54,6 @@ in {
70 options = {
71
72 services.redis = {
73 -
74 - enable = mkOption {
75 - type = types.bool;
76 - default = false;
77 - description = ''
78 - Whether to enable the Redis server. Note that the NixOS module for
79 - Redis disables kernel support for Transparent Huge Pages (THP),
80 - because this features causes major performance problems for Redis,
81 - e.g. (https://redis.io/topics/latency).
82 - '';
83 - };
84 -
85 package = mkOption {
86 type = types.package;
87 default = pkgs.redis;
88 @@ -51,176 +61,226 @@ in {
89 description = "Which Redis derivation to use.";
90 };
91
92 - port = mkOption {
93 - type = types.port;
94 - default = 6379;
95 - description = "The port for Redis to listen to.";
96 - };
97 + vmOverCommit = mkEnableOption ''
98 + setting of vm.overcommit_memory to 1
99 + (Suggested for Background Saving: http://redis.io/topics/faq)
100 + '';
101
102 - vmOverCommit = mkOption {
103 - type = types.bool;
104 - default = false;
105 - description = ''
106 - Set vm.overcommit_memory to 1 (Suggested for Background Saving: http://redis.io/topics/faq)
107 - '';
108 - };
109 -
110 - openFirewall = mkOption {
111 - type = types.bool;
112 - default = false;
113 - description = ''
114 - Whether to open ports in the firewall for the server.
115 - '';
116 - };
117 -
118 - bind = mkOption {
119 - type = with types; nullOr str;
120 - default = "127.0.0.1";
121 - description = ''
122 - The IP interface to bind to.
123 - <literal>null</literal> means "all interfaces".
124 - '';
125 - example = "192.0.2.1";
126 - };
127 -
128 - unixSocket = mkOption {
129 - type = with types; nullOr path;
130 - default = null;
131 - description = "The path to the socket to bind to.";
132 - example = "/run/redis/redis.sock";
133 - };
134 -
135 - unixSocketPerm = mkOption {
136 - type = types.int;
137 - default = 750;
138 - description = "Change permissions for the socket";
139 - example = 700;
140 - };
141 -
142 - logLevel = mkOption {
143 - type = types.str;
144 - default = "notice"; # debug, verbose, notice, warning
145 - example = "debug";
146 - description = "Specify the server verbosity level, options: debug, verbose, notice, warning.";
147 - };
148 -
149 - logfile = mkOption {
150 - type = types.str;
151 - default = "/dev/null";
152 - description = "Specify the log file name. Also 'stdout' can be used to force Redis to log on the standard output.";
153 - example = "/var/log/redis.log";
154 - };
155 -
156 - syslog = mkOption {
157 - type = types.bool;
158 - default = true;
159 - description = "Enable logging to the system logger.";
160 - };
161 -
162 - databases = mkOption {
163 - type = types.int;
164 - default = 16;
165 - description = "Set the number of databases.";
166 - };
167 -
168 - maxclients = mkOption {
169 - type = types.int;
170 - default = 10000;
171 - description = "Set the max number of connected clients at the same time.";
172 - };
173 -
174 - save = mkOption {
175 - type = with types; listOf (listOf int);
176 - default = [ [900 1] [300 10] [60 10000] ];
177 - description = "The schedule in which data is persisted to disk, represented as a list of lists where the first element represent the amount of seconds and the second the number of changes.";
178 - };
179 -
180 - slaveOf = mkOption {
181 - type = with types; nullOr (submodule ({ ... }: {
182 + servers = mkOption {
183 + type = with types; attrsOf (submodule ({config, name, ...}@args: {
184 options = {
185 - ip = mkOption {
186 - type = str;
187 - description = "IP of the Redis master";
188 - example = "192.168.1.100";
189 + enable = mkEnableOption ''
190 + Redis server.
191 +
192 + Note that the NixOS module for Redis disables kernel support
193 + for Transparent Huge Pages (THP),
194 + because this features causes major performance problems for Redis,
195 + e.g. (https://redis.io/topics/latency).
196 + '';
197 +
198 + user = mkOption {
199 + type = types.str;
200 + default = redisName name;
201 + defaultText = "\"redis\" or \"redis-\${name}\" if name != \"\"";
202 + description = "The username and groupname for redis-server.";
203 };
204
205 port = mkOption {
206 - type = port;
207 - description = "port of the Redis master";
208 + type = types.port;
209 default = 6379;
210 + description = "The port for Redis to listen to.";
211 + };
212 +
213 + openFirewall = mkOption {
214 + type = types.bool;
215 + default = false;
216 + description = ''
217 + Whether to open ports in the firewall for the server.
218 + '';
219 + };
220 +
221 + bind = mkOption {
222 + type = with types; nullOr str;
223 + default = if name == "" then "127.0.0.1" else null;
224 + defaultText = "127.0.0.1 or null if name != \"\"";
225 + description = ''
226 + The IP interface to bind to.
227 + <literal>null</literal> means "all interfaces".
228 + '';
229 + example = "192.0.2.1";
230 + };
231 +
232 + unixSocket = mkOption {
233 + type = with types; nullOr path;
234 + default = "/run/${redisName name}/redis.sock";
235 + defaultText = "\"/run/redis/redis.sock\" or \"/run/redis-\${name}/redis.sock\" if name != \"\"";
236 + description = "The path to the socket to bind to.";
237 + };
238 +
239 + unixSocketPerm = mkOption {
240 + type = types.int;
241 + default = 660;
242 + description = "Change permissions for the socket";
243 + example = 600;
244 + };
245 +
246 + logLevel = mkOption {
247 + type = types.str;
248 + default = "notice"; # debug, verbose, notice, warning
249 + example = "debug";
250 + description = "Specify the server verbosity level, options: debug, verbose, notice, warning.";
251 + };
252 +
253 + logfile = mkOption {
254 + type = types.str;
255 + default = "/dev/null";
256 + description = "Specify the log file name. Also 'stdout' can be used to force Redis to log on the standard output.";
257 + example = "/var/log/redis.log";
258 + };
259 +
260 + syslog = mkOption {
261 + type = types.bool;
262 + default = true;
263 + description = "Enable logging to the system logger.";
264 + };
265 +
266 + databases = mkOption {
267 + type = types.int;
268 + default = 16;
269 + description = "Set the number of databases.";
270 + };
271 +
272 + maxclients = mkOption {
273 + type = types.int;
274 + default = 10000;
275 + description = "Set the max number of connected clients at the same time.";
276 + };
277 +
278 + save = mkOption {
279 + type = with types; listOf (listOf int);
280 + default = [ [900 1] [300 10] [60 10000] ];
281 + description = "The schedule in which data is persisted to disk, represented as a list of lists where the first element represent the amount of seconds and the second the number of changes.";
282 + };
283 +
284 + slaveOf = mkOption {
285 + type = with types; nullOr (submodule ({ ... }: {
286 + options = {
287 + ip = mkOption {
288 + type = str;
289 + description = "IP of the Redis master";
290 + example = "192.168.1.100";
291 + };
292 +
293 + port = mkOption {
294 + type = port;
295 + description = "port of the Redis master";
296 + default = 6379;
297 + };
298 + };
299 + }));
300 +
301 + default = null;
302 + description = "IP and port to which this redis instance acts as a slave.";
303 + example = { ip = "192.168.1.100"; port = 6379; };
304 + };
305 +
306 + masterAuth = mkOption {
307 + type = with types; nullOr str;
308 + default = null;
309 + description = ''If the master is password protected (using the requirePass configuration)
310 + it is possible to tell the slave to authenticate before starting the replication synchronization
311 + process, otherwise the master will refuse the slave request.
312 + (STORED PLAIN TEXT, WORLD-READABLE IN NIX STORE)'';
313 + };
314 +
315 + requirePass = mkOption {
316 + type = with types; nullOr str;
317 + default = null;
318 + description = ''
319 + Password for database (STORED PLAIN TEXT, WORLD-READABLE IN NIX STORE).
320 + Use requirePassFile to store it outside of the nix store in a dedicated file.
321 + '';
322 + example = "letmein!";
323 + };
324 +
325 + requirePassFile = mkOption {
326 + type = with types; nullOr path;
327 + default = null;
328 + description = "File with password for the database.";
329 + example = "/run/keys/redis-password";
330 + };
331 +
332 + appendOnly = mkOption {
333 + type = types.bool;
334 + default = false;
335 + description = "By default data is only periodically persisted to disk, enable this option to use an append-only file for improved persistence.";
336 + };
337 +
338 + appendFsync = mkOption {
339 + type = types.str;
340 + default = "everysec"; # no, always, everysec
341 + description = "How often to fsync the append-only log, options: no, always, everysec.";
342 + };
343 +
344 + slowLogLogSlowerThan = mkOption {
345 + type = types.int;
346 + default = 10000;
347 + description = "Log queries whose execution take longer than X in milliseconds.";
348 + example = 1000;
349 + };
350 +
351 + slowLogMaxLen = mkOption {
352 + type = types.int;
353 + default = 128;
354 + description = "Maximum number of items to keep in slow log.";
355 + };
356 +
357 + settings = mkOption {
358 + # TODO: this should be converted to freeformType
359 + type = with types; attrsOf (oneOf [ bool int str (listOf str) ]);
360 + default = {};
361 + description = ''
362 + Redis configuration. Refer to
363 + <link xlink:href="https://redis.io/topics/config"/>
364 + for details on supported values.
365 + '';
366 + example = literalExpression ''
367 + {
368 + loadmodule = [ "/path/to/my_module.so" "/path/to/other_module.so" ];
369 + }
370 + '';
371 };
372 };
373 + config.settings = mkMerge [
374 + {
375 + port = if config.bind == null then 0 else config.port;
376 + daemonize = false;
377 + supervised = "systemd";
378 + loglevel = config.logLevel;
379 + logfile = config.logfile;
380 + syslog-enabled = config.syslog;
381 + databases = config.databases;
382 + maxclients = config.maxclients;
383 + save = map (d: "${toString (builtins.elemAt d 0)} ${toString (builtins.elemAt d 1)}") config.save;
384 + dbfilename = "dump.rdb";
385 + dir = "/var/lib/${redisName name}";
386 + appendOnly = config.appendOnly;
387 + appendfsync = config.appendFsync;
388 + slowlog-log-slower-than = config.slowLogLogSlowerThan;
389 + slowlog-max-len = config.slowLogMaxLen;
390 + }
391 + (mkIf (config.bind != null) { bind = config.bind; })
392 + (mkIf (config.unixSocket != null) {
393 + unixsocket = config.unixSocket;
394 + unixsocketperm = toString config.unixSocketPerm;
395 + })
396 + (mkIf (config.slaveOf != null) { slaveof = "${config.slaveOf.ip} ${toString config.slaveOf.port}"; })
397 + (mkIf (config.masterAuth != null) { masterauth = config.masterAuth; })
398 + (mkIf (config.requirePass != null) { requirepass = config.requirePass; })
399 + ];
400 }));
401 -
402 - default = null;
403 - description = "IP and port to which this redis instance acts as a slave.";
404 - example = { ip = "192.168.1.100"; port = 6379; };
405 - };
406 -
407 - masterAuth = mkOption {
408 - type = with types; nullOr str;
409 - default = null;
410 - description = ''If the master is password protected (using the requirePass configuration)
411 - it is possible to tell the slave to authenticate before starting the replication synchronization
412 - process, otherwise the master will refuse the slave request.
413 - (STORED PLAIN TEXT, WORLD-READABLE IN NIX STORE)'';
414 - };
415 -
416 - requirePass = mkOption {
417 - type = with types; nullOr str;
418 - default = null;
419 - description = ''
420 - Password for database (STORED PLAIN TEXT, WORLD-READABLE IN NIX STORE).
421 - Use requirePassFile to store it outside of the nix store in a dedicated file.
422 - '';
423 - example = "letmein!";
424 - };
425 -
426 - requirePassFile = mkOption {
427 - type = with types; nullOr path;
428 - default = null;
429 - description = "File with password for the database.";
430 - example = "/run/keys/redis-password";
431 - };
432 -
433 - appendOnly = mkOption {
434 - type = types.bool;
435 - default = false;
436 - description = "By default data is only periodically persisted to disk, enable this option to use an append-only file for improved persistence.";
437 - };
438 -
439 - appendFsync = mkOption {
440 - type = types.str;
441 - default = "everysec"; # no, always, everysec
442 - description = "How often to fsync the append-only log, options: no, always, everysec.";
443 - };
444 -
445 - slowLogLogSlowerThan = mkOption {
446 - type = types.int;
447 - default = 10000;
448 - description = "Log queries whose execution take longer than X in milliseconds.";
449 - example = 1000;
450 - };
451 -
452 - slowLogMaxLen = mkOption {
453 - type = types.int;
454 - default = 128;
455 - description = "Maximum number of items to keep in slow log.";
456 - };
457 -
458 - settings = mkOption {
459 - type = with types; attrsOf (oneOf [ bool int str (listOf str) ]);
460 + description = "Configuration of multiple <literal>redis-server</literal> instances.";
461 default = {};
462 - description = ''
463 - Redis configuration. Refer to
464 - <link xlink:href="https://redis.io/topics/config"/>
465 - for details on supported values.
466 - '';
467 - example = literalExpression ''
468 - {
469 - loadmodule = [ "/path/to/my_module.so" "/path/to/other_module.so" ];
470 - }
471 - '';
472 };
473 };
474
475 @@ -229,78 +289,61 @@ in {
476
477 ###### implementation
478
479 - config = mkIf config.services.redis.enable {
480 - assertions = [{
481 - assertion = cfg.requirePass != null -> cfg.requirePassFile == null;
482 - message = "You can only set one services.redis.requirePass or services.redis.requirePassFile";
483 - }];
484 - boot.kernel.sysctl = (mkMerge [
485 + config = mkIf (enabledServers != {}) {
486 +
487 + assertions = attrValues (mapAttrs (name: conf: {
488 + assertion = conf.requirePass != null -> conf.requirePassFile == null;
489 + message = ''
490 + You can only set one services.redis.servers.${name}.requirePass
491 + or services.redis.servers.${name}.requirePassFile
492 + '';
493 + }) enabledServers);
494 +
495 + boot.kernel.sysctl = mkMerge [
496 { "vm.nr_hugepages" = "0"; }
497 ( mkIf cfg.vmOverCommit { "vm.overcommit_memory" = "1"; } )
498 - ]);
499 + ];
500
501 - networking.firewall = mkIf cfg.openFirewall {
502 - allowedTCPPorts = [ cfg.port ];
503 - };
504 -
505 - users.users.redis = {
506 - description = "Redis database user";
507 - group = "redis";
508 - isSystemUser = true;
509 - };
510 - users.groups.redis = {};
511 + networking.firewall.allowedTCPPorts = concatMap (conf:
512 + optional conf.openFirewall conf.port
513 + ) (attrValues enabledServers);
514
515 environment.systemPackages = [ cfg.package ];
516
517 - services.redis.settings = mkMerge [
518 - {
519 - port = cfg.port;
520 - daemonize = false;
521 - supervised = "systemd";
522 - loglevel = cfg.logLevel;
523 - logfile = cfg.logfile;
524 - syslog-enabled = cfg.syslog;
525 - databases = cfg.databases;
526 - maxclients = cfg.maxclients;
527 - save = map (d: "${toString (builtins.elemAt d 0)} ${toString (builtins.elemAt d 1)}") cfg.save;
528 - dbfilename = "dump.rdb";
529 - dir = "/var/lib/redis";
530 - appendOnly = cfg.appendOnly;
531 - appendfsync = cfg.appendFsync;
532 - slowlog-log-slower-than = cfg.slowLogLogSlowerThan;
533 - slowlog-max-len = cfg.slowLogMaxLen;
534 - }
535 - (mkIf (cfg.bind != null) { bind = cfg.bind; })
536 - (mkIf (cfg.unixSocket != null) { unixsocket = cfg.unixSocket; unixsocketperm = "${toString cfg.unixSocketPerm}"; })
537 - (mkIf (cfg.slaveOf != null) { slaveof = "${cfg.slaveOf.ip} ${toString cfg.slaveOf.port}"; })
538 - (mkIf (cfg.masterAuth != null) { masterauth = cfg.masterAuth; })
539 - (mkIf (cfg.requirePass != null) { requirepass = cfg.requirePass; })
540 - ];
541 + users.users = mapAttrs' (name: conf: nameValuePair (redisName name) {
542 + description = "System user for the redis-server instance ${name}";
543 + isSystemUser = true;
544 + group = redisName name;
545 + }) enabledServers;
546 + users.groups = mapAttrs' (name: conf: nameValuePair (redisName name) {
547 + }) enabledServers;
548
549 - systemd.services.redis = {
550 - description = "Redis Server";
551 + systemd.services = mapAttrs' (name: conf: nameValuePair (redisName name) {
552 + description = "Redis Server - ${redisName name}";
553
554 wantedBy = [ "multi-user.target" ];
555 after = [ "network.target" ];
556
557 - preStart = ''
558 - install -m 600 ${redisConfig} /run/redis/redis.conf
559 - '' + optionalString (cfg.requirePassFile != null) ''
560 - password=$(cat ${escapeShellArg cfg.requirePassFile})
561 - echo "requirePass $password" >> /run/redis/redis.conf
562 - '';
563 -
564 serviceConfig = {
565 - ExecStart = "${cfg.package}/bin/redis-server /run/redis/redis.conf";
566 + ExecStart = "${cfg.package}/bin/redis-server /run/${redisName name}/redis.conf";
567 + ExecStartPre = [("+"+pkgs.writeShellScript "${redisName name}-credentials" (''
568 + install -o '${conf.user}' -m 600 ${redisConfig conf.settings} /run/${redisName name}/redis.conf
569 + '' + optionalString (conf.requirePassFile != null) ''
570 + {
571 + printf requirePass' '
572 + cat ${escapeShellArg conf.requirePassFile}
573 + } >>/run/${redisName name}/redis.conf
574 + '')
575 + )];
576 Type = "notify";
577 # User and group
578 - User = "redis";
579 - Group = "redis";
580 + User = conf.user;
581 + Group = conf.user;
582 # Runtime directory and mode
583 - RuntimeDirectory = "redis";
584 + RuntimeDirectory = redisName name;
585 RuntimeDirectoryMode = "0750";
586 # State directory and mode
587 - StateDirectory = "redis";
588 + StateDirectory = redisName name;
589 StateDirectoryMode = "0700";
590 # Access write directories
591 UMask = "0077";
592 @@ -309,7 +352,7 @@ in {
593 # Security
594 NoNewPrivileges = true;
595 # Process Properties
596 - LimitNOFILE = "${toString ulimitNofile}";
597 + LimitNOFILE = mkDefault "${toString (conf.maxclients + 32)}";
598 # Sandboxing
599 ProtectSystem = "strict";
600 ProtectHome = true;
601 @@ -322,7 +365,9 @@ in {
602 ProtectKernelModules = true;
603 ProtectKernelTunables = true;
604 ProtectControlGroups = true;
605 - RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ];
606 + RestrictAddressFamilies =
607 + optionals (conf.bind != null) ["AF_INET" "AF_INET6"] ++
608 + optional (conf.unixSocket != null) "AF_UNIX";
609 RestrictNamespaces = true;
610 LockPersonality = true;
611 MemoryDenyWriteExecute = true;
612 @@ -333,6 +378,7 @@ in {
613 SystemCallArchitectures = "native";
614 SystemCallFilter = "~@cpu-emulation @debug @keyring @memlock @mount @obsolete @privileged @resources @setuid";
615 };
616 - };
617 + }) enabledServers;
618 +
619 };
620 }
621 diff --git a/nixos/modules/services/misc/sourcehut/builds.nix b/nixos/modules/services/misc/sourcehut/builds.nix
622 deleted file mode 100644
623 index f806e8c51b9..00000000000
624 --- a/nixos/modules/services/misc/sourcehut/builds.nix
625 +++ /dev/null
626 @@ -1,234 +0,0 @@
627 -{ config, lib, pkgs, ... }:
628 -
629 -with lib;
630 -let
631 - cfg = config.services.sourcehut;
632 - scfg = cfg.builds;
633 - rcfg = config.services.redis;
634 - iniKey = "builds.sr.ht";
635 -
636 - drv = pkgs.sourcehut.buildsrht;
637 -in
638 -{
639 - options.services.sourcehut.builds = {
640 - user = mkOption {
641 - type = types.str;
642 - default = "buildsrht";
643 - description = ''
644 - User for builds.sr.ht.
645 - '';
646 - };
647 -
648 - port = mkOption {
649 - type = types.port;
650 - default = 5002;
651 - description = ''
652 - Port on which the "builds" module should listen.
653 - '';
654 - };
655 -
656 - database = mkOption {
657 - type = types.str;
658 - default = "builds.sr.ht";
659 - description = ''
660 - PostgreSQL database name for builds.sr.ht.
661 - '';
662 - };
663 -
664 - statePath = mkOption {
665 - type = types.path;
666 - default = "${cfg.statePath}/buildsrht";
667 - description = ''
668 - State path for builds.sr.ht.
669 - '';
670 - };
671 -
672 - enableWorker = mkOption {
673 - type = types.bool;
674 - default = false;
675 - description = ''
676 - Run workers for builds.sr.ht.
677 - '';
678 - };
679 -
680 - images = mkOption {
681 - type = types.attrsOf (types.attrsOf (types.attrsOf types.package));
682 - default = { };
683 - example = lib.literalExpression ''(let
684 - # Pinning unstable to allow usage with flakes and limit rebuilds.
685 - pkgs_unstable = builtins.fetchGit {
686 - url = "https://github.com/NixOS/nixpkgs";
687 - rev = "ff96a0fa5635770390b184ae74debea75c3fd534";
688 - ref = "nixos-unstable";
689 - };
690 - image_from_nixpkgs = pkgs_unstable: (import ("${pkgs.sourcehut.buildsrht}/lib/images/nixos/image.nix") {
691 - pkgs = (import pkgs_unstable {});
692 - });
693 - in
694 - {
695 - nixos.unstable.x86_64 = image_from_nixpkgs pkgs_unstable;
696 - }
697 - )'';
698 - description = ''
699 - Images for builds.sr.ht. Each package should be distro.release.arch and point to a /nix/store/package/root.img.qcow2.
700 - '';
701 - };
702 -
703 - };
704 -
705 - config = with scfg; let
706 - image_dirs = lib.lists.flatten (
707 - lib.attrsets.mapAttrsToList
708 - (distro: revs:
709 - lib.attrsets.mapAttrsToList
710 - (rev: archs:
711 - lib.attrsets.mapAttrsToList
712 - (arch: image:
713 - pkgs.runCommand "buildsrht-images" { } ''
714 - mkdir -p $out/${distro}/${rev}/${arch}
715 - ln -s ${image}/*.qcow2 $out/${distro}/${rev}/${arch}/root.img.qcow2
716 - '')
717 - archs)
718 - revs)
719 - scfg.images);
720 - image_dir_pre = pkgs.symlinkJoin {
721 - name = "builds.sr.ht-worker-images-pre";
722 - paths = image_dirs ++ [
723 - "${pkgs.sourcehut.buildsrht}/lib/images"
724 - ];
725 - };
726 - image_dir = pkgs.runCommand "builds.sr.ht-worker-images" { } ''
727 - mkdir -p $out/images
728 - cp -Lr ${image_dir_pre}/* $out/images
729 - '';
730 - in
731 - lib.mkIf (cfg.enable && elem "builds" cfg.services) {
732 - users = {
733 - users = {
734 - "${user}" = {
735 - isSystemUser = true;
736 - group = user;
737 - extraGroups = lib.optionals cfg.builds.enableWorker [ "docker" ];
738 - description = "builds.sr.ht user";
739 - };
740 - };
741 -
742 - groups = {
743 - "${user}" = { };
744 - };
745 - };
746 -
747 - services.postgresql = {
748 - authentication = ''
749 - local ${database} ${user} trust
750 - '';
751 - ensureDatabases = [ database ];
752 - ensureUsers = [
753 - {
754 - name = user;
755 - ensurePermissions = { "DATABASE \"${database}\"" = "ALL PRIVILEGES"; };
756 - }
757 - ];
758 - };
759 -
760 - systemd = {
761 - tmpfiles.rules = [
762 - "d ${statePath} 0755 ${user} ${user} -"
763 - ] ++ (lib.optionals cfg.builds.enableWorker
764 - [ "d ${statePath}/logs 0775 ${user} ${user} - -" ]
765 - );
766 -
767 - services = {
768 - buildsrht = import ./service.nix { inherit config pkgs lib; } scfg drv iniKey
769 - {
770 - after = [ "postgresql.service" "network.target" ];
771 - requires = [ "postgresql.service" ];
772 - wantedBy = [ "multi-user.target" ];
773 -
774 - description = "builds.sr.ht website service";
775 -
776 - serviceConfig.ExecStart = "${cfg.python}/bin/gunicorn ${drv.pname}.app:app -b ${cfg.address}:${toString port}";
777 -
778 - # Hack to bypass this hack: https://git.sr.ht/~sircmpwn/core.sr.ht/tree/master/item/srht-update-profiles#L6
779 - } // { preStart = " "; };
780 -
781 - buildsrht-worker = {
782 - enable = scfg.enableWorker;
783 - after = [ "postgresql.service" "network.target" ];
784 - requires = [ "postgresql.service" ];
785 - wantedBy = [ "multi-user.target" ];
786 - partOf = [ "buildsrht.service" ];
787 - description = "builds.sr.ht worker service";
788 - path = [ pkgs.openssh pkgs.docker ];
789 - preStart = let qemuPackage = pkgs.qemu_kvm;
790 - in ''
791 - if [[ "$(docker images -q qemu:latest 2> /dev/null)" == "" || "$(cat ${statePath}/docker-image-qemu 2> /dev/null || true)" != "${qemuPackage.version}" ]]; then
792 - # Create and import qemu:latest image for docker
793 - ${
794 - pkgs.dockerTools.streamLayeredImage {
795 - name = "qemu";
796 - tag = "latest";
797 - contents = [ qemuPackage ];
798 - }
799 - } | docker load
800 - # Mark down current package version
801 - printf "%s" "${qemuPackage.version}" > ${statePath}/docker-image-qemu
802 - fi
803 - '';
804 - serviceConfig = {
805 - Type = "simple";
806 - User = user;
807 - Group = "nginx";
808 - Restart = "always";
809 - };
810 - serviceConfig.ExecStart = "${pkgs.sourcehut.buildsrht}/bin/builds.sr.ht-worker";
811 - };
812 - };
813 - };
814 -
815 - services.sourcehut.settings = {
816 - # URL builds.sr.ht is being served at (protocol://domain)
817 - "builds.sr.ht".origin = mkDefault "http://builds.${cfg.originBase}";
818 - # Address and port to bind the debug server to
819 - "builds.sr.ht".debug-host = mkDefault "0.0.0.0";
820 - "builds.sr.ht".debug-port = mkDefault port;
821 - # Configures the SQLAlchemy connection string for the database.
822 - "builds.sr.ht".connection-string = mkDefault "postgresql:///${database}?user=${user}&host=/var/run/postgresql";
823 - # Set to "yes" to automatically run migrations on package upgrade.
824 - "builds.sr.ht".migrate-on-upgrade = mkDefault "yes";
825 - # builds.sr.ht's OAuth client ID and secret for meta.sr.ht
826 - # Register your client at meta.example.org/oauth
827 - "builds.sr.ht".oauth-client-id = mkDefault null;
828 - "builds.sr.ht".oauth-client-secret = mkDefault null;
829 - # The redis connection used for the celery worker
830 - "builds.sr.ht".redis = mkDefault "redis://${rcfg.bind}:${toString rcfg.port}/3";
831 - # The shell used for ssh
832 - "builds.sr.ht".shell = mkDefault "runner-shell";
833 - # Register the builds.sr.ht dispatcher
834 - "git.sr.ht::dispatch".${builtins.unsafeDiscardStringContext "${pkgs.sourcehut.buildsrht}/bin/buildsrht-keys"} = mkDefault "${user}:${user}";
835 -
836 - # Location for build logs, images, and control command
837 - } // lib.attrsets.optionalAttrs scfg.enableWorker {
838 - # Default worker stores logs that are accessible via this address:port
839 - "builds.sr.ht::worker".name = mkDefault "127.0.0.1:5020";
840 - "builds.sr.ht::worker".buildlogs = mkDefault "${scfg.statePath}/logs";
841 - "builds.sr.ht::worker".images = mkDefault "${image_dir}/images";
842 - "builds.sr.ht::worker".controlcmd = mkDefault "${image_dir}/images/control";
843 - "builds.sr.ht::worker".timeout = mkDefault "3m";
844 - };
845 -
846 - services.nginx.virtualHosts."logs.${cfg.originBase}" =
847 - if scfg.enableWorker then {
848 - listen = with builtins; let address = split ":" cfg.settings."builds.sr.ht::worker".name;
849 - in [{ addr = elemAt address 0; port = lib.toInt (elemAt address 2); }];
850 - locations."/logs".root = "${scfg.statePath}";
851 - } else { };
852 -
853 - services.nginx.virtualHosts."builds.${cfg.originBase}" = {
854 - forceSSL = true;
855 - locations."/".proxyPass = "http://${cfg.address}:${toString port}";
856 - locations."/query".proxyPass = "http://${cfg.address}:${toString (port + 100)}";
857 - locations."/static".root = "${pkgs.sourcehut.buildsrht}/${pkgs.sourcehut.python.sitePackages}/buildsrht";
858 - };
859 - };
860 -}
861 diff --git a/nixos/modules/services/misc/sourcehut/default.nix b/nixos/modules/services/misc/sourcehut/default.nix
862 index 9c812d6b043..f482c352397 100644
863 --- a/nixos/modules/services/misc/sourcehut/default.nix
864 +++ b/nixos/modules/services/misc/sourcehut/default.nix
865 @@ -1,14 +1,90 @@
866 { config, pkgs, lib, ... }:
867 -
868 with lib;
869 let
870 + inherit (config.services) nginx postfix postgresql redis;
871 + inherit (config.users) users groups;
872 cfg = config.services.sourcehut;
873 - cfgIni = cfg.settings;
874 - settingsFormat = pkgs.formats.ini { };
875 + domain = cfg.settings."sr.ht".global-domain;
876 + settingsFormat = pkgs.formats.ini {
877 + listToValue = concatMapStringsSep "," (generators.mkValueStringDefault {});
878 + mkKeyValue = k: v:
879 + if v == null then ""
880 + else generators.mkKeyValueDefault {
881 + mkValueString = v:
882 + if v == true then "yes"
883 + else if v == false then "no"
884 + else generators.mkValueStringDefault {} v;
885 + } "=" k v;
886 + };
887 + configIniOfService = srv: settingsFormat.generate "sourcehut-${srv}-config.ini"
888 + # Each service needs access to only a subset of sections (and secrets).
889 + (filterAttrs (k: v: v != null)
890 + (mapAttrs (section: v:
891 + let srvMatch = builtins.match "^([a-z]*)\\.sr\\.ht(::.*)?$" section; in
892 + if srvMatch == null # Include sections shared by all services
893 + || head srvMatch == srv # Include sections for the service being configured
894 + then v
895 + # Enable Web links and integrations between services.
896 + else if tail srvMatch == [ null ] && elem (head srvMatch) cfg.services
897 + then {
898 + inherit (v) origin;
899 + # mansrht crashes without it
900 + oauth-client-id = v.oauth-client-id or null;
901 + }
902 + # Drop sub-sections of other services
903 + else null)
904 + (recursiveUpdate cfg.settings {
905 + # Those paths are mounted using BindPaths= or BindReadOnlyPaths=
906 + # for services needing access to them.
907 + "builds.sr.ht::worker".buildlogs = "/var/log/sourcehut/buildsrht/logs";
908 + "git.sr.ht".post-update-script = "/usr/bin/gitsrht-update-hook";
909 + "git.sr.ht".repos = "/var/lib/sourcehut/gitsrht/repos";
910 + "hg.sr.ht".changegroup-script = "/usr/bin/hgsrht-hook-changegroup";
911 + "hg.sr.ht".repos = "/var/lib/sourcehut/hgsrht/repos";
912 + # Making this a per service option despite being in a global section,
913 + # so that it uses the redis-server used by the service.
914 + "sr.ht".redis-host = cfg.${srv}.redis.host;
915 + })));
916 + commonServiceSettings = srv: {
917 + origin = mkOption {
918 + description = "URL ${srv}.sr.ht is being served at (protocol://domain)";
919 + type = types.str;
920 + default = "https://${srv}.${domain}";
921 + defaultText = "https://${srv}.example.com";
922 + };
923 + debug-host = mkOption {
924 + description = "Address to bind the debug server to.";
925 + type = with types; nullOr str;
926 + default = null;
927 + };
928 + debug-port = mkOption {
929 + description = "Port to bind the debug server to.";
930 + type = with types; nullOr str;
931 + default = null;
932 + };
933 + connection-string = mkOption {
934 + description = "SQLAlchemy connection string for the database.";
935 + type = types.str;
936 + default = "postgresql:///localhost?user=${srv}srht&host=/run/postgresql";
937 + };
938 + migrate-on-upgrade = mkEnableOption "automatic migrations on package upgrade" // { default = true; };
939 + oauth-client-id = mkOption {
940 + description = "${srv}.sr.ht's OAuth client id for meta.sr.ht.";
941 + type = types.str;
942 + };
943 + oauth-client-secret = mkOption {
944 + description = "${srv}.sr.ht's OAuth client secret for meta.sr.ht.";
945 + type = types.path;
946 + apply = s: "<" + toString s;
947 + };
948 + };
949
950 # Specialized python containing all the modules
951 python = pkgs.sourcehut.python.withPackages (ps: with ps; [
952 gunicorn
953 + eventlet
954 + # For monitoring Celery: sudo -u listssrht celery --app listssrht.process -b redis+socket:///run/redis-sourcehut/redis.sock?virtual_host=5 flower
955 + flower
956 # Sourcehut services
957 srht
958 buildsrht
959 @@ -19,69 +95,37 @@ let
960 listssrht
961 mansrht
962 metasrht
963 + # Not a python package
964 + #pagessrht
965 pastesrht
966 todosrht
967 ]);
968 + mkOptionNullOrStr = description: mkOption {
969 + inherit description;
970 + type = with types; nullOr str;
971 + default = null;
972 + };
973 in
974 {
975 - imports =
976 - [
977 - ./git.nix
978 - ./hg.nix
979 - ./hub.nix
980 - ./todo.nix
981 - ./man.nix
982 - ./meta.nix
983 - ./paste.nix
984 - ./builds.nix
985 - ./lists.nix
986 - ./dispatch.nix
987 - (mkRemovedOptionModule [ "services" "sourcehut" "nginx" "enable" ] ''
988 - The sourcehut module supports `nginx` as a local reverse-proxy by default and doesn't
989 - support other reverse-proxies officially.
990 -
991 - However it's possible to use an alternative reverse-proxy by
992 -
993 - * disabling nginx
994 - * adjusting the relevant settings for server addresses and ports directly
995 -
996 - Further details about this can be found in the `Sourcehut`-section of the NixOS-manual.
997 - '')
998 - ];
999 -
1000 options.services.sourcehut = {
1001 - enable = mkOption {
1002 - type = types.bool;
1003 - default = false;
1004 - description = ''
1005 - Enable sourcehut - git hosting, continuous integration, mailing list, ticket tracking,
1006 - task dispatching, wiki and account management services
1007 - '';
1008 - };
1009 + enable = mkEnableOption ''
1010 + sourcehut - git hosting, continuous integration, mailing list, ticket tracking,
1011 + task dispatching, wiki and account management services
1012 + '';
1013
1014 services = mkOption {
1015 - type = types.nonEmptyListOf (types.enum [ "builds" "dispatch" "git" "hub" "hg" "lists" "man" "meta" "paste" "todo" ]);
1016 - default = [ "man" "meta" "paste" ];
1017 - example = [ "builds" "dispatch" "git" "hub" "hg" "lists" "man" "meta" "paste" "todo" ];
1018 + type = with types; listOf (enum
1019 + [ "builds" "dispatch" "git" "hg" "hub" "lists" "man" "meta" "pages" "paste" "todo" ]);
1020 + defaultText = "locally enabled services";
1021 description = ''
1022 - Services to enable on the sourcehut network.
1023 + Services that may be displayed as links in the title bar of the Web interface.
1024 '';
1025 };
1026
1027 - originBase = mkOption {
1028 + listenAddress = mkOption {
1029 type = types.str;
1030 - default = with config.networking; hostName + lib.optionalString (domain != null) ".${domain}";
1031 - description = ''
1032 - Host name used by reverse-proxy and for default settings. Will host services at git."''${originBase}". For example: git.sr.ht
1033 - '';
1034 - };
1035 -
1036 - address = mkOption {
1037 - type = types.str;
1038 - default = "127.0.0.1";
1039 - description = ''
1040 - Address to bind to.
1041 - '';
1042 + default = "localhost";
1043 + description = "Address to bind to.";
1044 };
1045
1046 python = mkOption {
1047 @@ -94,105 +138,1235 @@ in
1048 '';
1049 };
1050
1051 - statePath = mkOption {
1052 - type = types.path;
1053 - default = "/var/lib/sourcehut";
1054 - description = ''
1055 - Root state path for the sourcehut network. If left as the default value
1056 - this directory will automatically be created before the sourcehut server
1057 - starts, otherwise the sysadmin is responsible for ensuring the
1058 - directory exists with appropriate ownership and permissions.
1059 - '';
1060 + minio = {
1061 + enable = mkEnableOption ''local minio integration'';
1062 + };
1063 +
1064 + nginx = {
1065 + enable = mkEnableOption ''local nginx integration'';
1066 + virtualHost = mkOption {
1067 + type = types.attrs;
1068 + default = {};
1069 + description = "Virtual-host configuration merged with all Sourcehut's virtual-hosts.";
1070 + };
1071 + };
1072 +
1073 + postfix = {
1074 + enable = mkEnableOption ''local postfix integration'';
1075 + };
1076 +
1077 + postgresql = {
1078 + enable = mkEnableOption ''local postgresql integration'';
1079 + };
1080 +
1081 + redis = {
1082 + enable = mkEnableOption ''local redis integration in a dedicated redis-server'';
1083 };
1084
1085 settings = mkOption {
1086 type = lib.types.submodule {
1087 freeformType = settingsFormat.type;
1088 + options."sr.ht" = {
1089 + global-domain = mkOption {
1090 + description = "Global domain name.";
1091 + type = types.str;
1092 + example = "example.com";
1093 + };
1094 + environment = mkOption {
1095 + description = "Values other than \"production\" adds a banner to each page.";
1096 + type = types.enum [ "development" "production" ];
1097 + default = "development";
1098 + };
1099 + network-key = mkOption {
1100 + description = ''
1101 + An absolute file path (which should be outside the Nix-store)
1102 + to a secret key to encrypt internal messages with. Use <code>srht-keygen network</code> to
1103 + generate this key. It must be consistent between all services and nodes.
1104 + '';
1105 + type = types.path;
1106 + apply = s: "<" + toString s;
1107 + };
1108 + owner-email = mkOption {
1109 + description = "Owner's email.";
1110 + type = types.str;
1111 + default = "contact@example.com";
1112 + };
1113 + owner-name = mkOption {
1114 + description = "Owner's name.";
1115 + type = types.str;
1116 + default = "John Doe";
1117 + };
1118 + site-blurb = mkOption {
1119 + description = "Blurb for your site.";
1120 + type = types.str;
1121 + default = "the hacker's forge";
1122 + };
1123 + site-info = mkOption {
1124 + description = "The top-level info page for your site.";
1125 + type = types.str;
1126 + default = "https://sourcehut.org";
1127 + };
1128 + service-key = mkOption {
1129 + description = ''
1130 + An absolute file path (which should be outside the Nix-store)
1131 + to a key used for encrypting session cookies. Use <code>srht-keygen service</code> to
1132 + generate the service key. This must be shared between each node of the same
1133 + service (e.g. git1.sr.ht and git2.sr.ht), but different services may use
1134 + different keys. If you configure all of your services with the same
1135 + config.ini, you may use the same service-key for all of them.
1136 + '';
1137 + type = types.path;
1138 + apply = s: "<" + toString s;
1139 + };
1140 + site-name = mkOption {
1141 + description = "The name of your network of sr.ht-based sites.";
1142 + type = types.str;
1143 + default = "sourcehut";
1144 + };
1145 + source-url = mkOption {
1146 + description = "The source code for your fork of sr.ht.";
1147 + type = types.str;
1148 + default = "https://git.sr.ht/~sircmpwn/srht";
1149 + };
1150 + };
1151 + options.mail = {
1152 + smtp-host = mkOptionNullOrStr "Outgoing SMTP host.";
1153 + smtp-port = mkOption {
1154 + description = "Outgoing SMTP port.";
1155 + type = with types; nullOr port;
1156 + default = null;
1157 + };
1158 + smtp-user = mkOptionNullOrStr "Outgoing SMTP user.";
1159 + smtp-password = mkOptionNullOrStr "Outgoing SMTP password.";
1160 + smtp-from = mkOptionNullOrStr "Outgoing SMTP FROM.";
1161 + error-to = mkOptionNullOrStr "Address receiving application exceptions";
1162 + error-from = mkOptionNullOrStr "Address sending application exceptions";
1163 + pgp-privkey = mkOptionNullOrStr ''
1164 + An absolute file path (which should be outside the Nix-store)
1165 + to an OpenPGP private key.
1166 +
1167 + Your PGP key information (DO NOT mix up pub and priv here)
1168 + You must remove the password from your secret key, if present.
1169 + You can do this with <code>gpg --edit-key [key-id]</code>,
1170 + then use the <code>passwd</code> command and do not enter a new password.
1171 + '';
1172 + pgp-pubkey = mkOptionNullOrStr "OpenPGP public key.";
1173 + pgp-key-id = mkOptionNullOrStr "OpenPGP key identifier.";
1174 + };
1175 + options.objects = {
1176 + s3-upstream = mkOption {
1177 + description = "Configure the S3-compatible object storage service.";
1178 + type = with types; nullOr str;
1179 + default = null;
1180 + };
1181 + s3-access-key = mkOption {
1182 + description = "Access key to the S3-compatible object storage service";
1183 + type = with types; nullOr str;
1184 + default = null;
1185 + };
1186 + s3-secret-key = mkOption {
1187 + description = ''
1188 + An absolute file path (which should be outside the Nix-store)
1189 + to the secret key of the S3-compatible object storage service.
1190 + '';
1191 + type = with types; nullOr path;
1192 + default = null;
1193 + apply = mapNullable (s: "<" + toString s);
1194 + };
1195 + };
1196 + options.webhooks = {
1197 + private-key = mkOption {
1198 + description = ''
1199 + An absolute file path (which should be outside the Nix-store)
1200 + to a base64-encoded Ed25519 key for signing webhook payloads.
1201 + This should be consistent for all *.sr.ht sites,
1202 + as this key will be used to verify signatures
1203 + from other sites in your network.
1204 + Use the <code>srht-keygen webhook</code> command to generate a key.
1205 + '';
1206 + type = types.path;
1207 + apply = s: "<" + toString s;
1208 + };
1209 + };
1210 +
1211 + options."dispatch.sr.ht" = commonServiceSettings "dispatch" // {
1212 + };
1213 + options."dispatch.sr.ht::github" = {
1214 + oauth-client-id = mkOptionNullOrStr "OAuth client id.";
1215 + oauth-client-secret = mkOptionNullOrStr "OAuth client secret.";
1216 + };
1217 + options."dispatch.sr.ht::gitlab" = {
1218 + enabled = mkEnableOption "GitLab integration";
1219 + canonical-upstream = mkOption {
1220 + type = types.str;
1221 + description = "Canonical upstream.";
1222 + default = "gitlab.com";
1223 + };
1224 + repo-cache = mkOption {
1225 + type = types.str;
1226 + description = "Repository cache directory.";
1227 + default = "./repo-cache";
1228 + };
1229 + "gitlab.com" = mkOption {
1230 + type = with types; nullOr str;
1231 + description = "GitLab id and secret.";
1232 + default = null;
1233 + example = "GitLab:application id:secret";
1234 + };
1235 + };
1236 +
1237 + options."builds.sr.ht" = commonServiceSettings "builds" // {
1238 + allow-free = mkEnableOption "nonpaying users to submit builds";
1239 + redis = mkOption {
1240 + description = "The Redis connection used for the Celery worker.";
1241 + type = types.str;
1242 + default = "redis+socket:///run/redis-sourcehut-buildsrht/redis.sock?virtual_host=2";
1243 + };
1244 + shell = mkOption {
1245 + description = ''
1246 + Scripts used to launch on SSH connection.
1247 + <literal>/usr/bin/master-shell</literal> on master,
1248 + <literal>/usr/bin/runner-shell</literal> on runner.
1249 + If master and worker are on the same system
1250 + set to <literal>/usr/bin/runner-shell</literal>.
1251 + '';
1252 + type = types.enum ["/usr/bin/master-shell" "/usr/bin/runner-shell"];
1253 + default = "/usr/bin/master-shell";
1254 + };
1255 + };
1256 + options."builds.sr.ht::worker" = {
1257 + bind-address = mkOption {
1258 + description = ''
1259 + HTTP bind address for serving local build information/monitoring.
1260 + '';
1261 + type = types.str;
1262 + default = "localhost:8080";
1263 + };
1264 + buildlogs = mkOption {
1265 + description = "Path to write build logs.";
1266 + type = types.str;
1267 + default = "/var/log/sourcehut/buildsrht";
1268 + };
1269 + name = mkOption {
1270 + description = ''
1271 + Listening address and listening port
1272 + of the build runner (with HTTP port if not 80).
1273 + '';
1274 + type = types.str;
1275 + default = "localhost:5020";
1276 + };
1277 + timeout = mkOption {
1278 + description = ''
1279 + Max build duration.
1280 + See <link xlink:href="https://golang.org/pkg/time/#ParseDuration"/>.
1281 + '';
1282 + type = types.str;
1283 + default = "3m";
1284 + };
1285 + };
1286 +
1287 + options."git.sr.ht" = commonServiceSettings "git" // {
1288 + outgoing-domain = mkOption {
1289 + description = "Outgoing domain.";
1290 + type = types.str;
1291 + default = "https://git.localhost.localdomain";
1292 + };
1293 + post-update-script = mkOption {
1294 + description = ''
1295 + A post-update script which is installed in every git repo.
1296 + This setting is propagated to newer and existing repositories.
1297 + '';
1298 + type = types.path;
1299 + default = "${pkgs.sourcehut.gitsrht}/bin/gitsrht-update-hook";
1300 + defaultText = "\${pkgs.sourcehut.gitsrht}/bin/gitsrht-update-hook";
1301 + };
1302 + repos = mkOption {
1303 + description = ''
1304 + Path to git repositories on disk.
1305 + If changing the default, you must ensure that
1306 + the gitsrht's user as read and write access to it.
1307 + '';
1308 + type = types.str;
1309 + default = "/var/lib/sourcehut/gitsrht/repos";
1310 + };
1311 + webhooks = mkOption {
1312 + description = "The Redis connection used for the webhooks worker.";
1313 + type = types.str;
1314 + default = "redis+socket:///run/redis-sourcehut-gitsrht/redis.sock?virtual_host=1";
1315 + };
1316 + };
1317 + options."git.sr.ht::api" = {
1318 + internal-ipnet = mkOption {
1319 + description = ''
1320 + Set of IP subnets which are permitted to utilize internal API
1321 + authentication. This should be limited to the subnets
1322 + from which your *.sr.ht services are running.
1323 + See <xref linkend="opt-services.sourcehut.listenAddress"/>.
1324 + '';
1325 + type = with types; listOf str;
1326 + default = [ "127.0.0.0/8" "::1/128" ];
1327 + };
1328 + };
1329 +
1330 + options."hg.sr.ht" = commonServiceSettings "hg" // {
1331 + changegroup-script = mkOption {
1332 + description = ''
1333 + A changegroup script which is installed in every mercurial repo.
1334 + This setting is propagated to newer and existing repositories.
1335 + '';
1336 + type = types.str;
1337 + default = "${cfg.python}/bin/hgsrht-hook-changegroup";
1338 + defaultText = "\${cfg.python}/bin/hgsrht-hook-changegroup";
1339 + };
1340 + repos = mkOption {
1341 + description = ''
1342 + Path to mercurial repositories on disk.
1343 + If changing the default, you must ensure that
1344 + the hgsrht's user as read and write access to it.
1345 + '';
1346 + type = types.str;
1347 + default = "/var/lib/sourcehut/hgsrht/repos";
1348 + };
1349 + srhtext = mkOptionNullOrStr ''
1350 + Path to the srht mercurial extension
1351 + (defaults to where the hgsrht code is)
1352 + '';
1353 + clone_bundle_threshold = mkOption {
1354 + description = ".hg/store size (in MB) past which the nightly job generates clone bundles.";
1355 + type = types.ints.unsigned;
1356 + default = 50;
1357 + };
1358 + hg_ssh = mkOption {
1359 + description = "Path to hg-ssh (if not in $PATH).";
1360 + type = types.str;
1361 + default = "${pkgs.mercurial}/bin/hg-ssh";
1362 + defaultText = "\${pkgs.mercurial}/bin/hg-ssh";
1363 + };
1364 + webhooks = mkOption {
1365 + description = "The Redis connection used for the webhooks worker.";
1366 + type = types.str;
1367 + default = "redis+socket:///run/redis-sourcehut-hgsrht/redis.sock?virtual_host=1";
1368 + };
1369 + };
1370 +
1371 + options."hub.sr.ht" = commonServiceSettings "hub" // {
1372 + };
1373 +
1374 + options."lists.sr.ht" = commonServiceSettings "lists" // {
1375 + allow-new-lists = mkEnableOption "Allow creation of new lists.";
1376 + notify-from = mkOption {
1377 + description = "Outgoing email for notifications generated by users.";
1378 + type = types.str;
1379 + default = "lists-notify@localhost.localdomain";
1380 + };
1381 + posting-domain = mkOption {
1382 + description = "Posting domain.";
1383 + type = types.str;
1384 + default = "lists.localhost.localdomain";
1385 + };
1386 + redis = mkOption {
1387 + description = "The Redis connection used for the Celery worker.";
1388 + type = types.str;
1389 + default = "redis+socket:///run/redis-sourcehut-listssrht/redis.sock?virtual_host=2";
1390 + };
1391 + webhooks = mkOption {
1392 + description = "The Redis connection used for the webhooks worker.";
1393 + type = types.str;
1394 + default = "redis+socket:///run/redis-sourcehut-listssrht/redis.sock?virtual_host=1";
1395 + };
1396 + };
1397 + options."lists.sr.ht::worker" = {
1398 + reject-mimetypes = mkOption {
1399 + description = ''
1400 + Comma-delimited list of Content-Types to reject. Messages with Content-Types
1401 + included in this list are rejected. Multipart messages are always supported,
1402 + and each part is checked against this list.
1403 +
1404 + Uses fnmatch for wildcard expansion.
1405 + '';
1406 + type = with types; listOf str;
1407 + default = ["text/html"];
1408 + };
1409 + reject-url = mkOption {
1410 + description = "Reject URL.";
1411 + type = types.str;
1412 + default = "https://man.sr.ht/lists.sr.ht/etiquette.md";
1413 + };
1414 + sock = mkOption {
1415 + description = ''
1416 + Path for the lmtp daemon's unix socket. Direct incoming mail to this socket.
1417 + Alternatively, specify IP:PORT and an SMTP server will be run instead.
1418 + '';
1419 + type = types.str;
1420 + default = "/tmp/lists.sr.ht-lmtp.sock";
1421 + };
1422 + sock-group = mkOption {
1423 + description = ''
1424 + The lmtp daemon will make the unix socket group-read/write
1425 + for users in this group.
1426 + '';
1427 + type = types.str;
1428 + default = "postfix";
1429 + };
1430 + };
1431 +
1432 + options."man.sr.ht" = commonServiceSettings "man" // {
1433 + };
1434 +
1435 + options."meta.sr.ht" =
1436 + removeAttrs (commonServiceSettings "meta")
1437 + ["oauth-client-id" "oauth-client-secret"] // {
1438 + api-origin = mkOption {
1439 + description = "Origin URL for API, 100 more than web.";
1440 + type = types.str;
1441 + default = "http://${cfg.listenAddress}:${toString (cfg.meta.port + 100)}";
1442 + defaultText = ''http://<xref linkend="opt-services.sourcehut.listenAddress"/>:''${toString (<xref linkend="opt-services.sourcehut.meta.port"/> + 100)}'';
1443 + };
1444 + webhooks = mkOption {
1445 + description = "The Redis connection used for the webhooks worker.";
1446 + type = types.str;
1447 + default = "redis+socket:///run/redis-sourcehut-metasrht/redis.sock?virtual_host=1";
1448 + };
1449 + welcome-emails = mkEnableOption "sending stock sourcehut welcome emails after signup";
1450 + };
1451 + options."meta.sr.ht::api" = {
1452 + internal-ipnet = mkOption {
1453 + description = ''
1454 + Set of IP subnets which are permitted to utilize internal API
1455 + authentication. This should be limited to the subnets
1456 + from which your *.sr.ht services are running.
1457 + See <xref linkend="opt-services.sourcehut.listenAddress"/>.
1458 + '';
1459 + type = with types; listOf str;
1460 + default = [ "127.0.0.0/8" "::1/128" ];
1461 + };
1462 + };
1463 + options."meta.sr.ht::aliases" = mkOption {
1464 + description = "Aliases for the client IDs of commonly used OAuth clients.";
1465 + type = with types; attrsOf int;
1466 + default = {};
1467 + example = { "git.sr.ht" = 12345; };
1468 + };
1469 + options."meta.sr.ht::billing" = {
1470 + enabled = mkEnableOption "the billing system";
1471 + stripe-public-key = mkOptionNullOrStr "Public key for Stripe. Get your keys at https://dashboard.stripe.com/account/apikeys";
1472 + stripe-secret-key = mkOptionNullOrStr ''
1473 + An absolute file path (which should be outside the Nix-store)
1474 + to a secret key for Stripe. Get your keys at https://dashboard.stripe.com/account/apikeys
1475 + '' // {
1476 + apply = mapNullable (s: "<" + toString s);
1477 + };
1478 + };
1479 + options."meta.sr.ht::settings" = {
1480 + registration = mkEnableOption "public registration";
1481 + onboarding-redirect = mkOption {
1482 + description = "Where to redirect new users upon registration.";
1483 + type = types.str;
1484 + default = "https://meta.localhost.localdomain";
1485 + };
1486 + user-invites = mkOption {
1487 + description = ''
1488 + How many invites each user is issued upon registration
1489 + (only applicable if open registration is disabled).
1490 + '';
1491 + type = types.ints.unsigned;
1492 + default = 5;
1493 + };
1494 + };
1495 +
1496 + options."pages.sr.ht" = commonServiceSettings "pages" // {
1497 + gemini-certs = mkOption {
1498 + description = ''
1499 + An absolute file path (which should be outside the Nix-store)
1500 + to Gemini certificates.
1501 + '';
1502 + type = with types; nullOr path;
1503 + default = null;
1504 + };
1505 + max-site-size = mkOption {
1506 + description = "Maximum size of any given site (post-gunzip), in MiB.";
1507 + type = types.int;
1508 + default = 1024;
1509 + };
1510 + user-domain = mkOption {
1511 + description = ''
1512 + Configures the user domain, if enabled.
1513 + All users are given &lt;username&gt;.this.domain.
1514 + '';
1515 + type = with types; nullOr str;
1516 + default = null;
1517 + };
1518 + };
1519 + options."pages.sr.ht::api" = {
1520 + internal-ipnet = mkOption {
1521 + description = ''
1522 + Set of IP subnets which are permitted to utilize internal API
1523 + authentication. This should be limited to the subnets
1524 + from which your *.sr.ht services are running.
1525 + See <xref linkend="opt-services.sourcehut.listenAddress"/>.
1526 + '';
1527 + type = with types; listOf str;
1528 + default = [ "127.0.0.0/8" "::1/128" ];
1529 + };
1530 + };
1531 +
1532 + options."paste.sr.ht" = commonServiceSettings "paste" // {
1533 + };
1534 +
1535 + options."todo.sr.ht" = commonServiceSettings "todo" // {
1536 + notify-from = mkOption {
1537 + description = "Outgoing email for notifications generated by users.";
1538 + type = types.str;
1539 + default = "todo-notify@localhost.localdomain";
1540 + };
1541 + webhooks = mkOption {
1542 + description = "The Redis connection used for the webhooks worker.";
1543 + type = types.str;
1544 + default = "redis+socket:///run/redis-sourcehut-todosrht/redis.sock?virtual_host=1";
1545 + };
1546 + };
1547 + options."todo.sr.ht::mail" = {
1548 + posting-domain = mkOption {
1549 + description = "Posting domain.";
1550 + type = types.str;
1551 + default = "todo.localhost.localdomain";
1552 + };
1553 + sock = mkOption {
1554 + description = ''
1555 + Path for the lmtp daemon's unix socket. Direct incoming mail to this socket.
1556 + Alternatively, specify IP:PORT and an SMTP server will be run instead.
1557 + '';
1558 + type = types.str;
1559 + default = "/tmp/todo.sr.ht-lmtp.sock";
1560 + };
1561 + sock-group = mkOption {
1562 + description = ''
1563 + The lmtp daemon will make the unix socket group-read/write
1564 + for users in this group.
1565 + '';
1566 + type = types.str;
1567 + default = "postfix";
1568 + };
1569 + };
1570 };
1571 default = { };
1572 description = ''
1573 The configuration for the sourcehut network.
1574 '';
1575 };
1576 - };
1577
1578 - config = mkIf cfg.enable {
1579 - assertions =
1580 - [
1581 - {
1582 - assertion = with cfgIni.webhooks; private-key != null && stringLength private-key == 44;
1583 - message = "The webhook's private key must be defined and of a 44 byte length.";
1584 - }
1585 + builds = {
1586 + enableWorker = mkEnableOption "worker for builds.sr.ht";
1587
1588 - {
1589 - assertion = hasAttrByPath [ "meta.sr.ht" "origin" ] cfgIni && cfgIni."meta.sr.ht".origin != null;
1590 - message = "meta.sr.ht's origin must be defined.";
1591 - }
1592 - ];
1593 + images = mkOption {
1594 + type = with types; attrsOf (attrsOf (attrsOf package));
1595 + default = { };
1596 + example = lib.literalExpression ''(let
1597 + # Pinning unstable to allow usage with flakes and limit rebuilds.
1598 + pkgs_unstable = builtins.fetchGit {
1599 + url = "https://github.com/NixOS/nixpkgs";
1600 + rev = "ff96a0fa5635770390b184ae74debea75c3fd534";
1601 + ref = "nixos-unstable";
1602 + };
1603 + image_from_nixpkgs = (import ("${pkgs.sourcehut.buildsrht}/lib/images/nixos/image.nix") {
1604 + pkgs = (import pkgs_unstable {});
1605 + });
1606 + in
1607 + {
1608 + nixos.unstable.x86_64 = image_from_nixpkgs;
1609 + }
1610 + )'';
1611 + description = ''
1612 + Images for builds.sr.ht. Each package should be distro.release.arch and point to a /nix/store/package/root.img.qcow2.
1613 + '';
1614 + };
1615 + };
1616
1617 - virtualisation.docker.enable = true;
1618 - environment.etc."sr.ht/config.ini".source =
1619 - settingsFormat.generate "sourcehut-config.ini" (mapAttrsRecursive
1620 - (
1621 - path: v: if v == null then "" else v
1622 - )
1623 - cfg.settings);
1624 + git = {
1625 + package = mkOption {
1626 + type = types.package;
1627 + default = pkgs.git;
1628 + example = literalExpression "pkgs.gitFull";
1629 + description = ''
1630 + Git package for git.sr.ht. This can help silence collisions.
1631 + '';
1632 + };
1633 + fcgiwrap.preforkProcess = mkOption {
1634 + description = "Number of fcgiwrap processes to prefork.";
1635 + type = types.int;
1636 + default = 4;
1637 + };
1638 + };
1639
1640 - environment.systemPackages = [ pkgs.sourcehut.coresrht ];
1641 + hg = {
1642 + package = mkOption {
1643 + type = types.package;
1644 + default = pkgs.mercurial;
1645 + description = ''
1646 + Mercurial package for hg.sr.ht. This can help silence collisions.
1647 + '';
1648 + };
1649 + cloneBundles = mkOption {
1650 + type = types.bool;
1651 + default = false;
1652 + description = ''
1653 + Generate clonebundles (which require more disk space but dramatically speed up cloning large repositories).
1654 + '';
1655 + };
1656 + };
1657
1658 - # PostgreSQL server
1659 - services.postgresql.enable = mkOverride 999 true;
1660 - # Mail server
1661 - services.postfix.enable = mkOverride 999 true;
1662 - # Cron daemon
1663 - services.cron.enable = mkOverride 999 true;
1664 - # Redis server
1665 - services.redis.enable = mkOverride 999 true;
1666 - services.redis.bind = mkOverride 999 "127.0.0.1";
1667 -
1668 - services.sourcehut.settings = {
1669 - # The name of your network of sr.ht-based sites
1670 - "sr.ht".site-name = mkDefault "sourcehut";
1671 - # The top-level info page for your site
1672 - "sr.ht".site-info = mkDefault "https://sourcehut.org";
1673 - # {{ site-name }}, {{ site-blurb }}
1674 - "sr.ht".site-blurb = mkDefault "the hacker's forge";
1675 - # If this != production, we add a banner to each page
1676 - "sr.ht".environment = mkDefault "development";
1677 - # Contact information for the site owners
1678 - "sr.ht".owner-name = mkDefault "Drew DeVault";
1679 - "sr.ht".owner-email = mkDefault "sir@cmpwn.com";
1680 - # The source code for your fork of sr.ht
1681 - "sr.ht".source-url = mkDefault "https://git.sr.ht/~sircmpwn/srht";
1682 - # A secret key to encrypt session cookies with
1683 - "sr.ht".secret-key = mkDefault null;
1684 - "sr.ht".global-domain = mkDefault null;
1685 -
1686 - # Outgoing SMTP settings
1687 - mail.smtp-host = mkDefault null;
1688 - mail.smtp-port = mkDefault null;
1689 - mail.smtp-user = mkDefault null;
1690 - mail.smtp-password = mkDefault null;
1691 - mail.smtp-from = mkDefault null;
1692 - # Application exceptions are emailed to this address
1693 - mail.error-to = mkDefault null;
1694 - mail.error-from = mkDefault null;
1695 - # Your PGP key information (DO NOT mix up pub and priv here)
1696 - # You must remove the password from your secret key, if present.
1697 - # You can do this with gpg --edit-key [key-id], then use the passwd
1698 - # command and do not enter a new password.
1699 - mail.pgp-privkey = mkDefault null;
1700 - mail.pgp-pubkey = mkDefault null;
1701 - mail.pgp-key-id = mkDefault null;
1702 -
1703 - # base64-encoded Ed25519 key for signing webhook payloads. This should be
1704 - # consistent for all *.sr.ht sites, as we'll use this key to verify signatures
1705 - # from other sites in your network.
1706 - #
1707 - # Use the srht-webhook-keygen command to generate a key.
1708 - webhooks.private-key = mkDefault null;
1709 + lists = {
1710 + process = {
1711 + extraArgs = mkOption {
1712 + type = with types; listOf str;
1713 + default = [ "--loglevel DEBUG" "--pool eventlet" "--without-heartbeat" ];
1714 + description = "Extra arguments passed to the Celery responsible for processing mails.";
1715 + };
1716 + celeryConfig = mkOption {
1717 + type = types.lines;
1718 + default = "";
1719 + description = "Content of the <literal>celeryconfig.py</literal> used by the Celery of <literal>listssrht-process</literal>.";
1720 + };
1721 + };
1722 };
1723 };
1724 +
1725 + config = mkIf cfg.enable (mkMerge [
1726 + {
1727 + environment.systemPackages = [ pkgs.sourcehut.coresrht ];
1728 +
1729 + services.sourcehut.settings = {
1730 + "git.sr.ht".outgoing-domain = mkDefault "https://git.${domain}";
1731 + "lists.sr.ht".notify-from = mkDefault "lists-notify@${domain}";
1732 + "lists.sr.ht".posting-domain = mkDefault "lists.${domain}";
1733 + "meta.sr.ht::settings".onboarding-redirect = mkDefault "https://meta.${domain}";
1734 + "todo.sr.ht".notify-from = mkDefault "todo-notify@${domain}";
1735 + "todo.sr.ht::mail".posting-domain = mkDefault "todo.${domain}";
1736 + };
1737 + }
1738 + (mkIf cfg.postgresql.enable {
1739 + assertions = [
1740 + { assertion = postgresql.enable;
1741 + message = "postgresql must be enabled and configured";
1742 + }
1743 + ];
1744 + })
1745 + (mkIf cfg.postfix.enable {
1746 + assertions = [
1747 + { assertion = postfix.enable;
1748 + message = "postfix must be enabled and configured";
1749 + }
1750 + ];
1751 + # Needed for sharing the LMTP sockets with JoinsNamespaceOf=
1752 + systemd.services.postfix.serviceConfig.PrivateTmp = true;
1753 + })
1754 + (mkIf cfg.redis.enable {
1755 + services.redis.vmOverCommit = mkDefault true;
1756 + })
1757 + (mkIf cfg.nginx.enable {
1758 + assertions = [
1759 + { assertion = nginx.enable;
1760 + message = "nginx must be enabled and configured";
1761 + }
1762 + ];
1763 + # For proxyPass= in virtual-hosts for Sourcehut services.
1764 + services.nginx.recommendedProxySettings = mkDefault true;
1765 + })
1766 + (mkIf (cfg.builds.enable || cfg.git.enable || cfg.hg.enable) {
1767 + services.openssh = {
1768 + # Note that sshd will continue to honor AuthorizedKeysFile.
1769 + # Note that you may want automatically rotate
1770 + # or link to /dev/null the following log files:
1771 + # - /var/log/gitsrht-dispatch
1772 + # - /var/log/{build,git,hg}srht-keys
1773 + # - /var/log/{git,hg}srht-shell
1774 + # - /var/log/gitsrht-update-hook
1775 + authorizedKeysCommand = ''/etc/ssh/sourcehut/subdir/srht-dispatch "%u" "%h" "%t" "%k"'';
1776 + # srht-dispatch will setuid/setgid according to [git.sr.ht::dispatch]
1777 + authorizedKeysCommandUser = "root";
1778 + extraConfig = ''
1779 + PermitUserEnvironment SRHT_*
1780 + '';
1781 + };
1782 + environment.etc."ssh/sourcehut/config.ini".source =
1783 + settingsFormat.generate "sourcehut-dispatch-config.ini"
1784 + (filterAttrs (k: v: k == "git.sr.ht::dispatch")
1785 + cfg.settings);
1786 + environment.etc."ssh/sourcehut/subdir/srht-dispatch" = {
1787 + # sshd_config(5): The program must be owned by root, not writable by group or others
1788 + mode = "0755";
1789 + source = pkgs.writeShellScript "srht-dispatch" ''
1790 + set -e
1791 + cd /etc/ssh/sourcehut/subdir
1792 + ${cfg.python}/bin/gitsrht-dispatch "$@"
1793 + '';
1794 + };
1795 + systemd.services.sshd = {
1796 + #path = optional cfg.git.enable [ cfg.git.package ];
1797 + serviceConfig = {
1798 + BindReadOnlyPaths =
1799 + # Note that those /usr/bin/* paths are hardcoded in multiple places in *.sr.ht,
1800 + # for instance to get the user from the [git.sr.ht::dispatch] settings.
1801 + # *srht-keys needs to:
1802 + # - access a redis-server in [sr.ht] redis-host,
1803 + # - access the PostgreSQL server in [*.sr.ht] connection-string,
1804 + # - query metasrht-api (through the HTTP API).
1805 + # Using this has the side effect of creating empty files in /usr/bin/
1806 + optionals cfg.builds.enable [
1807 + "${pkgs.writeShellScript "buildsrht-keys-wrapper" ''
1808 + set -e
1809 + cd /run/sourcehut/buildsrht/subdir
1810 + set -x
1811 + exec -a "$0" ${pkgs.sourcehut.buildsrht}/bin/buildsrht-keys "$@"
1812 + ''}:/usr/bin/buildsrht-keys"
1813 + "${pkgs.sourcehut.buildsrht}/bin/master-shell:/usr/bin/master-shell"
1814 + "${pkgs.sourcehut.buildsrht}/bin/runner-shell:/usr/bin/runner-shell"
1815 + ] ++
1816 + optionals cfg.git.enable [
1817 + # /path/to/gitsrht-keys calls /path/to/gitsrht-shell,
1818 + # or [git.sr.ht] shell= if set.
1819 + "${pkgs.writeShellScript "gitsrht-keys-wrapper" ''
1820 + set -e
1821 + cd /run/sourcehut/gitsrht/subdir
1822 + set -x
1823 + exec -a "$0" ${pkgs.sourcehut.gitsrht}/bin/gitsrht-keys "$@"
1824 + ''}:/usr/bin/gitsrht-keys"
1825 + "${pkgs.writeShellScript "gitsrht-shell-wrapper" ''
1826 + set -e
1827 + cd /run/sourcehut/gitsrht/subdir
1828 + set -x
1829 + exec -a "$0" ${pkgs.sourcehut.gitsrht}/bin/gitsrht-shell "$@"
1830 + ''}:/usr/bin/gitsrht-shell"
1831 + "${pkgs.writeShellScript "gitsrht-update-hook" ''
1832 + set -e
1833 + test -e "''${PWD%/*}"/config.ini ||
1834 + # Git hooks are run relative to their repository's directory,
1835 + # but gitsrht-update-hook looks up ../config.ini
1836 + ln -s /run/sourcehut/gitsrht/config.ini "''${PWD%/*}"/config.ini
1837 + # hooks/post-update calls /usr/bin/gitsrht-update-hook as hooks/stage-3
1838 + # but this wrapper being a bash script, it overrides $0 with /usr/bin/gitsrht-update-hook
1839 + # hence this hack to put hooks/stage-3 back into gitsrht-update-hook's $0
1840 + if test "''${STAGE3:+set}"
1841 + then
1842 + set -x
1843 + exec -a hooks/stage-3 ${pkgs.sourcehut.gitsrht}/bin/gitsrht-update-hook "$@"
1844 + else
1845 + export STAGE3=set
1846 + set -x
1847 + exec -a "$0" ${pkgs.sourcehut.gitsrht}/bin/gitsrht-update-hook "$@"
1848 + fi
1849 + ''}:/usr/bin/gitsrht-update-hook"
1850 + ] ++
1851 + optionals cfg.hg.enable [
1852 + # /path/to/hgsrht-keys calls /path/to/hgsrht-shell,
1853 + # or [hg.sr.ht] shell= if set.
1854 + "${pkgs.writeShellScript "hgsrht-keys-wrapper" ''
1855 + set -e
1856 + cd /run/sourcehut/hgsrht/subdir
1857 + set -x
1858 + exec -a "$0" ${pkgs.sourcehut.hgsrht}/bin/hgsrht-keys "$@"
1859 + ''}:/usr/bin/hgsrht-keys"
1860 + "${pkgs.writeShellScript "hgsrht-shell-wrapper" ''
1861 + set -e
1862 + cd /run/sourcehut/hgsrht/subdir
1863 + set -x
1864 + exec -a "$0" ${pkgs.sourcehut.hgsrht}/bin/hgsrht-shell "$@"
1865 + ''}:/usr/bin/hgsrht-shell"
1866 + # Mercurial's changegroup hooks are run relative to their repository's directory,
1867 + # but hgsrht-hook-changegroup looks up ./config.ini
1868 + "${pkgs.writeShellScript "hgsrht-hook-changegroup" ''
1869 + set -e
1870 + test -e "''$PWD"/config.ini ||
1871 + ln -s /run/sourcehut/hgsrht/config.ini "''$PWD"/config.ini
1872 + set -x
1873 + exec -a "$0" ${cfg.python}/bin/hgsrht-hook-changegroup "$@"
1874 + ''}:/usr/bin/hgsrht-hook-changegroup"
1875 + ];
1876 + };
1877 + };
1878 + })
1879 + ]);
1880 +
1881 + imports = [
1882 +
1883 + (import ./service.nix "builds" {
1884 + inherit configIniOfService;
1885 + srvsrht = "buildsrht";
1886 + port = 5002;
1887 + # TODO: a celery worker on the master and worker are apparently needed
1888 + extraServices.buildsrht-worker = let
1889 + qemuPackage = pkgs.qemu_kvm;
1890 + serviceName = "buildsrht-worker";
1891 + statePath = "/var/lib/sourcehut/${serviceName}";
1892 + in mkIf cfg.builds.enableWorker {
1893 + path = [ pkgs.openssh pkgs.docker ];
1894 + preStart = ''
1895 + set -x
1896 + if test -z "$(docker images -q qemu:latest 2>/dev/null)" \
1897 + || test "$(cat ${statePath}/docker-image-qemu)" != "${qemuPackage.version}"
1898 + then
1899 + # Create and import qemu:latest image for docker
1900 + ${pkgs.dockerTools.streamLayeredImage {
1901 + name = "qemu";
1902 + tag = "latest";
1903 + contents = [ qemuPackage ];
1904 + }} | docker load
1905 + # Mark down current package version
1906 + echo '${qemuPackage.version}' >${statePath}/docker-image-qemu
1907 + fi
1908 + '';
1909 + serviceConfig = {
1910 + ExecStart = "${pkgs.sourcehut.buildsrht}/bin/builds.sr.ht-worker";
1911 + RuntimeDirectory = [ "sourcehut/${serviceName}/subdir" ];
1912 + # builds.sr.ht-worker looks up ../config.ini
1913 + LogsDirectory = [ "sourcehut/${serviceName}" ];
1914 + StateDirectory = [ "sourcehut/${serviceName}" ];
1915 + WorkingDirectory = "-"+"/run/sourcehut/${serviceName}/subdir";
1916 + };
1917 + };
1918 + extraConfig = let
1919 + image_dirs = flatten (
1920 + mapAttrsToList (distro: revs:
1921 + mapAttrsToList (rev: archs:
1922 + mapAttrsToList (arch: image:
1923 + pkgs.runCommand "buildsrht-images" { } ''
1924 + mkdir -p $out/${distro}/${rev}/${arch}
1925 + ln -s ${image}/*.qcow2 $out/${distro}/${rev}/${arch}/root.img.qcow2
1926 + ''
1927 + ) archs
1928 + ) revs
1929 + ) cfg.builds.images
1930 + );
1931 + image_dir_pre = pkgs.symlinkJoin {
1932 + name = "builds.sr.ht-worker-images-pre";
1933 + paths = image_dirs;
1934 + # FIXME: not working, apparently because ubuntu/latest is a broken link
1935 + # ++ [ "${pkgs.sourcehut.buildsrht}/lib/images" ];
1936 + };
1937 + image_dir = pkgs.runCommand "builds.sr.ht-worker-images" { } ''
1938 + mkdir -p $out/images
1939 + cp -Lr ${image_dir_pre}/* $out/images
1940 + '';
1941 + in mkMerge [
1942 + {
1943 + users.users.${cfg.builds.user}.shell = pkgs.bash;
1944 +
1945 + virtualisation.docker.enable = true;
1946 +
1947 + services.sourcehut.settings = mkMerge [
1948 + { # Note that git.sr.ht::dispatch is not a typo,
1949 + # gitsrht-dispatch always use this section
1950 + "git.sr.ht::dispatch"."/usr/bin/buildsrht-keys" =
1951 + mkDefault "${cfg.builds.user}:${cfg.builds.group}";
1952 + }
1953 + (mkIf cfg.builds.enableWorker {
1954 + "builds.sr.ht::worker".shell = "/usr/bin/runner-shell";
1955 + "builds.sr.ht::worker".images = mkDefault "${image_dir}/images";
1956 + "builds.sr.ht::worker".controlcmd = mkDefault "${image_dir}/images/control";
1957 + })
1958 + ];
1959 + }
1960 + (mkIf cfg.builds.enableWorker {
1961 + users.groups = {
1962 + docker.members = [ cfg.builds.user ];
1963 + };
1964 + })
1965 + (mkIf (cfg.builds.enableWorker && cfg.nginx.enable) {
1966 + # Allow nginx access to buildlogs
1967 + users.users.${nginx.user}.extraGroups = [ cfg.builds.group ];
1968 + systemd.services.nginx = {
1969 + serviceConfig.BindReadOnlyPaths = [ "${cfg.settings."builds.sr.ht::worker".buildlogs}:/var/log/nginx/buildsrht/logs" ];
1970 + };
1971 + services.nginx.virtualHosts."logs.${domain}" = mkMerge [ {
1972 + /* FIXME: is a listen needed?
1973 + listen = with builtins;
1974 + # FIXME: not compatible with IPv6
1975 + let address = split ":" cfg.settings."builds.sr.ht::worker".name; in
1976 + [{ addr = elemAt address 0; port = lib.toInt (elemAt address 2); }];
1977 + */
1978 + locations."/logs/".alias = "/var/log/nginx/buildsrht/logs/";
1979 + } cfg.nginx.virtualHost ];
1980 + })
1981 + ];
1982 + })
1983 +
1984 + (import ./service.nix "dispatch" {
1985 + inherit configIniOfService;
1986 + port = 5005;
1987 + })
1988 +
1989 + (import ./service.nix "git" (let
1990 + baseService = {
1991 + path = [ cfg.git.package ];
1992 + serviceConfig.BindPaths = [ "${cfg.settings."git.sr.ht".repos}:/var/lib/sourcehut/gitsrht/repos" ];
1993 + };
1994 + in {
1995 + inherit configIniOfService;
1996 + mainService = mkMerge [ baseService {
1997 + serviceConfig.StateDirectory = [ "sourcehut/gitsrht" "sourcehut/gitsrht/repos" ];
1998 + preStart = mkIf (!versionAtLeast config.system.stateVersion "22.05") (mkBefore ''
1999 + # Fix Git hooks of repositories pre-dating https://github.com/NixOS/nixpkgs/pull/133984
2000 + (
2001 + set +f
2002 + shopt -s nullglob
2003 + for h in /var/lib/sourcehut/gitsrht/repos/~*/*/hooks/{pre-receive,update,post-update}
2004 + do ln -fnsv /usr/bin/gitsrht-update-hook "$h"; done
2005 + )
2006 + '');
2007 + } ];
2008 + port = 5001;
2009 + webhooks = true;
2010 + extraTimers.gitsrht-periodic = {
2011 + service = baseService;
2012 + timerConfig.OnCalendar = ["*:0/20"];
2013 + };
2014 + extraConfig = mkMerge [
2015 + {
2016 + # https://stackoverflow.com/questions/22314298/git-push-results-in-fatal-protocol-error-bad-line-length-character-this
2017 + # Probably could use gitsrht-shell if output is restricted to just parameters...
2018 + users.users.${cfg.git.user}.shell = pkgs.bash;
2019 + services.sourcehut.settings = {
2020 + "git.sr.ht::dispatch"."/usr/bin/gitsrht-keys" =
2021 + mkDefault "${cfg.git.user}:${cfg.git.group}";
2022 + };
2023 + systemd.services.sshd = baseService;
2024 + }
2025 + (mkIf cfg.nginx.enable {
2026 + services.nginx.virtualHosts."git.${domain}" = {
2027 + locations."/authorize" = {
2028 + proxyPass = "http://${cfg.listenAddress}:${toString cfg.git.port}";
2029 + extraConfig = ''
2030 + proxy_pass_request_body off;
2031 + proxy_set_header Content-Length "";
2032 + proxy_set_header X-Original-URI $request_uri;
2033 + '';
2034 + };
2035 + locations."~ ^/([^/]+)/([^/]+)/(HEAD|info/refs|objects/info/.*|git-upload-pack).*$" = {
2036 + root = "/var/lib/sourcehut/gitsrht/repos";
2037 + fastcgiParams = {
2038 + GIT_HTTP_EXPORT_ALL = "";
2039 + GIT_PROJECT_ROOT = "$document_root";
2040 + PATH_INFO = "$uri";
2041 + SCRIPT_FILENAME = "${cfg.git.package}/bin/git-http-backend";
2042 + };
2043 + extraConfig = ''
2044 + auth_request /authorize;
2045 + fastcgi_read_timeout 500s;
2046 + fastcgi_pass unix:/run/gitsrht-fcgiwrap.sock;
2047 + gzip off;
2048 + '';
2049 + };
2050 + };
2051 + systemd.sockets.gitsrht-fcgiwrap = {
2052 + before = [ "nginx.service" ];
2053 + wantedBy = [ "sockets.target" "gitsrht.service" ];
2054 + # This path remains accessible to nginx.service, which has no RootDirectory=
2055 + socketConfig.ListenStream = "/run/gitsrht-fcgiwrap.sock";
2056 + socketConfig.SocketUser = nginx.user;
2057 + socketConfig.SocketMode = "600";
2058 + };
2059 + })
2060 + ];
2061 + extraServices.gitsrht-fcgiwrap = mkIf cfg.nginx.enable {
2062 + serviceConfig = {
2063 + # Socket is passed by gitsrht-fcgiwrap.socket
2064 + ExecStart = "${pkgs.fcgiwrap}/sbin/fcgiwrap -c ${toString cfg.git.fcgiwrap.preforkProcess}";
2065 + # No need for config.ini
2066 + ExecStartPre = mkForce [];
2067 + User = null;
2068 + DynamicUser = true;
2069 + BindReadOnlyPaths = [ "${cfg.settings."git.sr.ht".repos}:/var/lib/sourcehut/gitsrht/repos" ];
2070 + IPAddressDeny = "any";
2071 + InaccessiblePaths = [ "-+/run/postgresql" "-+/run/redis-sourcehut" ];
2072 + PrivateNetwork = true;
2073 + RestrictAddressFamilies = mkForce [ "none" ];
2074 + SystemCallFilter = mkForce [
2075 + "@system-service"
2076 + "~@aio" "~@keyring" "~@memlock" "~@privileged" "~@resources" "~@setuid"
2077 + # @timer is needed for alarm()
2078 + ];
2079 + };
2080 + };
2081 + }))
2082 +
2083 + (import ./service.nix "hg" (let
2084 + baseService = {
2085 + path = [ cfg.hg.package ];
2086 + serviceConfig.BindPaths = [ "${cfg.settings."hg.sr.ht".repos}:/var/lib/sourcehut/hgsrht/repos" ];
2087 + };
2088 + in {
2089 + inherit configIniOfService;
2090 + mainService = mkMerge [ baseService {
2091 + serviceConfig.StateDirectory = [ "sourcehut/hgsrht" "sourcehut/hgsrht/repos" ];
2092 + } ];
2093 + port = 5010;
2094 + webhooks = true;
2095 + extraTimers.hgsrht-periodic = {
2096 + service = baseService;
2097 + timerConfig.OnCalendar = ["*:0/20"];
2098 + };
2099 + extraTimers.hgsrht-clonebundles = mkIf cfg.hg.cloneBundles {
2100 + service = baseService;
2101 + timerConfig.OnCalendar = ["daily"];
2102 + timerConfig.AccuracySec = "1h";
2103 + };
2104 + extraConfig = mkMerge [
2105 + {
2106 + users.users.${cfg.hg.user}.shell = pkgs.bash;
2107 + services.sourcehut.settings = {
2108 + # Note that git.sr.ht::dispatch is not a typo,
2109 + # gitsrht-dispatch always uses this section.
2110 + "git.sr.ht::dispatch"."/usr/bin/hgsrht-keys" =
2111 + mkDefault "${cfg.hg.user}:${cfg.hg.group}";
2112 + };
2113 + systemd.services.sshd = baseService;
2114 + }
2115 + (mkIf cfg.nginx.enable {
2116 + # Allow nginx access to repositories
2117 + users.users.${nginx.user}.extraGroups = [ cfg.hg.group ];
2118 + services.nginx.virtualHosts."hg.${domain}" = {
2119 + locations."/authorize" = {
2120 + proxyPass = "http://${cfg.listenAddress}:${toString cfg.hg.port}";
2121 + extraConfig = ''
2122 + proxy_pass_request_body off;
2123 + proxy_set_header Content-Length "";
2124 + proxy_set_header X-Original-URI $request_uri;
2125 + '';
2126 + };
2127 + # Let clients reach pull bundles. We don't really need to lock this down even for
2128 + # private repos because the bundles are named after the revision hashes...
2129 + # so someone would need to know or guess a SHA value to download anything.
2130 + # TODO: proxyPass to an hg serve service?
2131 + locations."~ ^/[~^][a-z0-9_]+/[a-zA-Z0-9_.-]+/\\.hg/bundles/.*$" = {
2132 + root = "/var/lib/nginx/hgsrht/repos";
2133 + extraConfig = ''
2134 + auth_request /authorize;
2135 + gzip off;
2136 + '';
2137 + };
2138 + };
2139 + systemd.services.nginx = {
2140 + serviceConfig.BindReadOnlyPaths = [ "${cfg.settings."hg.sr.ht".repos}:/var/lib/nginx/hgsrht/repos" ];
2141 + };
2142 + })
2143 + ];
2144 + }))
2145 +
2146 + (import ./service.nix "hub" {
2147 + inherit configIniOfService;
2148 + port = 5014;
2149 + extraConfig = {
2150 + services.nginx = mkIf cfg.nginx.enable {
2151 + virtualHosts."hub.${domain}" = mkMerge [ {
2152 + serverAliases = [ domain ];
2153 + } cfg.nginx.virtualHost ];
2154 + };
2155 + };
2156 + })
2157 +
2158 + (import ./service.nix "lists" (let
2159 + srvsrht = "listssrht";
2160 + in {
2161 + inherit configIniOfService;
2162 + port = 5006;
2163 + webhooks = true;
2164 + # Receive the mail from Postfix and enqueue them into Redis and PostgreSQL
2165 + extraServices.listssrht-lmtp = {
2166 + wants = [ "postfix.service" ];
2167 + unitConfig.JoinsNamespaceOf = optional cfg.postfix.enable "postfix.service";
2168 + serviceConfig.ExecStart = "${cfg.python}/bin/listssrht-lmtp";
2169 + # Avoid crashing: os.chown(sock, os.getuid(), sock_gid)
2170 + serviceConfig.PrivateUsers = mkForce false;
2171 + };
2172 + # Dequeue the mails from Redis and dispatch them
2173 + extraServices.listssrht-process = {
2174 + serviceConfig = {
2175 + preStart = ''
2176 + cp ${pkgs.writeText "${srvsrht}-webhooks-celeryconfig.py" cfg.lists.process.celeryConfig} \
2177 + /run/sourcehut/${srvsrht}-webhooks/celeryconfig.py
2178 + '';
2179 + ExecStart = "${cfg.python}/bin/celery --app listssrht.process worker --hostname listssrht-process@%%h " + concatStringsSep " " cfg.lists.process.extraArgs;
2180 + # Avoid crashing: os.getloadavg()
2181 + ProcSubset = mkForce "all";
2182 + };
2183 + };
2184 + extraConfig = mkIf cfg.postfix.enable {
2185 + users.groups.${postfix.group}.members = [ cfg.lists.user ];
2186 + services.sourcehut.settings."lists.sr.ht::mail".sock-group = postfix.group;
2187 + services.postfix = {
2188 + destination = [ "lists.${domain}" ];
2189 + # FIXME: an accurate recipient list should be queried
2190 + # from the lists.sr.ht PostgreSQL database to avoid backscattering.
2191 + # But usernames are unfortunately not in that database but in meta.sr.ht.
2192 + # Note that two syntaxes are allowed:
2193 + # - ~username/list-name@lists.${domain}
2194 + # - u.username.list-name@lists.${domain}
2195 + localRecipients = [ "@lists.${domain}" ];
2196 + transport = ''
2197 + lists.${domain} lmtp:unix:${cfg.settings."lists.sr.ht::worker".sock}
2198 + '';
2199 + };
2200 + };
2201 + }))
2202 +
2203 + (import ./service.nix "man" {
2204 + inherit configIniOfService;
2205 + port = 5004;
2206 + })
2207 +
2208 + (import ./service.nix "meta" {
2209 + inherit configIniOfService;
2210 + port = 5000;
2211 + webhooks = true;
2212 + extraServices.metasrht-api = {
2213 + serviceConfig.Restart = "always";
2214 + serviceConfig.RestartSec = "2s";
2215 + preStart = "set -x\n" + concatStringsSep "\n\n" (attrValues (mapAttrs (k: s:
2216 + let srvMatch = builtins.match "^([a-z]*)\\.sr\\.ht$" k;
2217 + srv = head srvMatch;
2218 + in
2219 + # Configure client(s) as "preauthorized"
2220 + optionalString (srvMatch != null && cfg.${srv}.enable && ((s.oauth-client-id or null) != null)) ''
2221 + # Configure ${srv}'s OAuth client as "preauthorized"
2222 + ${postgresql.package}/bin/psql '${cfg.settings."meta.sr.ht".connection-string}' \
2223 + -c "UPDATE oauthclient SET preauthorized = true WHERE client_id = '${s.oauth-client-id}'"
2224 + ''
2225 + ) cfg.settings));
2226 + serviceConfig.ExecStart = "${pkgs.sourcehut.metasrht}/bin/metasrht-api -b ${cfg.listenAddress}:${toString (cfg.meta.port + 100)}";
2227 + };
2228 + extraTimers.metasrht-daily.timerConfig = {
2229 + OnCalendar = ["daily"];
2230 + AccuracySec = "1h";
2231 + };
2232 + extraConfig = mkMerge [
2233 + {
2234 + assertions = [
2235 + { assertion = let s = cfg.settings."meta.sr.ht::billing"; in
2236 + s.enabled == "yes" -> (s.stripe-public-key != null && s.stripe-secret-key != null);
2237 + message = "If meta.sr.ht::billing is enabled, the keys must be defined.";
2238 + }
2239 + ];
2240 + environment.systemPackages = optional cfg.meta.enable
2241 + (pkgs.writeShellScriptBin "metasrht-manageuser" ''
2242 + set -eux
2243 + if test "$(${pkgs.coreutils}/bin/id -n -u)" != '${cfg.meta.user}'
2244 + then exec sudo -u '${cfg.meta.user}' "$0" "$@"
2245 + else
2246 + # In order to load config.ini
2247 + if cd /run/sourcehut/metasrht
2248 + then exec ${cfg.python}/bin/metasrht-manageuser "$@"
2249 + else cat <<EOF
2250 + Please run: sudo systemctl start metasrht
2251 + EOF
2252 + exit 1
2253 + fi
2254 + fi
2255 + '');
2256 + }
2257 + (mkIf cfg.nginx.enable {
2258 + services.nginx.virtualHosts."meta.${domain}" = {
2259 + locations."/query" = {
2260 + proxyPass = cfg.settings."meta.sr.ht".api-origin;
2261 + extraConfig = ''
2262 + if ($request_method = 'OPTIONS') {
2263 + add_header 'Access-Control-Allow-Origin' '*';
2264 + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
2265 + add_header 'Access-Control-Allow-Headers' 'User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
2266 + add_header 'Access-Control-Max-Age' 1728000;
2267 + add_header 'Content-Type' 'text/plain; charset=utf-8';
2268 + add_header 'Content-Length' 0;
2269 + return 204;
2270 + }
2271 +
2272 + add_header 'Access-Control-Allow-Origin' '*';
2273 + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
2274 + add_header 'Access-Control-Allow-Headers' 'User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
2275 + add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
2276 + '';
2277 + };
2278 + };
2279 + })
2280 + ];
2281 + })
2282 +
2283 + (import ./service.nix "pages" {
2284 + inherit configIniOfService;
2285 + port = 5112;
2286 + mainService = let
2287 + srvsrht = "pagessrht";
2288 + version = pkgs.sourcehut.${srvsrht}.version;
2289 + stateDir = "/var/lib/sourcehut/${srvsrht}";
2290 + iniKey = "pages.sr.ht";
2291 + in {
2292 + preStart = mkBefore ''
2293 + set -x
2294 + # Use the /run/sourcehut/${srvsrht}/config.ini
2295 + # installed by a previous ExecStartPre= in baseService
2296 + cd /run/sourcehut/${srvsrht}
2297 +
2298 + if test ! -e ${stateDir}/db; then
2299 + ${postgresql.package}/bin/psql '${cfg.settings.${iniKey}.connection-string}' -f ${pkgs.sourcehut.pagessrht}/share/sql/schema.sql
2300 + echo ${version} >${stateDir}/db
2301 + fi
2302 +
2303 + ${optionalString cfg.settings.${iniKey}.migrate-on-upgrade ''
2304 + # Just try all the migrations because they're not linked to the version
2305 + for sql in ${pkgs.sourcehut.pagessrht}/share/sql/migrations/*.sql; do
2306 + ${postgresql.package}/bin/psql '${cfg.settings.${iniKey}.connection-string}' -f "$sql" || true
2307 + done
2308 + ''}
2309 +
2310 + # Disable webhook
2311 + touch ${stateDir}/webhook
2312 + '';
2313 + serviceConfig = {
2314 + ExecStart = mkForce "${pkgs.sourcehut.pagessrht}/bin/pages.sr.ht -b ${cfg.listenAddress}:${toString cfg.pages.port}";
2315 + };
2316 + };
2317 + })
2318 +
2319 + (import ./service.nix "paste" {
2320 + inherit configIniOfService;
2321 + port = 5011;
2322 + })
2323 +
2324 + (import ./service.nix "todo" {
2325 + inherit configIniOfService;
2326 + port = 5003;
2327 + webhooks = true;
2328 + extraServices.todosrht-lmtp = {
2329 + wants = [ "postfix.service" ];
2330 + unitConfig.JoinsNamespaceOf = optional cfg.postfix.enable "postfix.service";
2331 + serviceConfig.ExecStart = "${cfg.python}/bin/todosrht-lmtp";
2332 + # Avoid crashing: os.chown(sock, os.getuid(), sock_gid)
2333 + serviceConfig.PrivateUsers = mkForce false;
2334 + };
2335 + extraConfig = mkIf cfg.postfix.enable {
2336 + users.groups.${postfix.group}.members = [ cfg.todo.user ];
2337 + services.sourcehut.settings."todo.sr.ht::mail".sock-group = postfix.group;
2338 + services.postfix = {
2339 + destination = [ "todo.${domain}" ];
2340 + # FIXME: an accurate recipient list should be queried
2341 + # from the todo.sr.ht PostgreSQL database to avoid backscattering.
2342 + # But usernames are unfortunately not in that database but in meta.sr.ht.
2343 + # Note that two syntaxes are allowed:
2344 + # - ~username/tracker-name@todo.${domain}
2345 + # - u.username.tracker-name@todo.${domain}
2346 + localRecipients = [ "@todo.${domain}" ];
2347 + transport = ''
2348 + todo.${domain} lmtp:unix:${cfg.settings."todo.sr.ht::mail".sock}
2349 + '';
2350 + };
2351 + };
2352 + })
2353 +
2354 + (mkRenamedOptionModule [ "services" "sourcehut" "originBase" ]
2355 + [ "services" "sourcehut" "settings" "sr.ht" "global-domain" ])
2356 + (mkRenamedOptionModule [ "services" "sourcehut" "address" ]
2357 + [ "services" "sourcehut" "listenAddress" ])
2358 +
2359 + ];
2360 +
2361 meta.doc = ./sourcehut.xml;
2362 - meta.maintainers = with maintainers; [ tomberek ];
2363 + meta.maintainers = with maintainers; [ julm tomberek ];
2364 }
2365 diff --git a/nixos/modules/services/misc/sourcehut/dispatch.nix b/nixos/modules/services/misc/sourcehut/dispatch.nix
2366 deleted file mode 100644
2367 index a9db17bebe8..00000000000
2368 --- a/nixos/modules/services/misc/sourcehut/dispatch.nix
2369 +++ /dev/null
2370 @@ -1,125 +0,0 @@
2371 -{ config, lib, pkgs, ... }:
2372 -
2373 -with lib;
2374 -let
2375 - cfg = config.services.sourcehut;
2376 - cfgIni = cfg.settings;
2377 - scfg = cfg.dispatch;
2378 - iniKey = "dispatch.sr.ht";
2379 -
2380 - drv = pkgs.sourcehut.dispatchsrht;
2381 -in
2382 -{
2383 - options.services.sourcehut.dispatch = {
2384 - user = mkOption {
2385 - type = types.str;
2386 - default = "dispatchsrht";
2387 - description = ''
2388 - User for dispatch.sr.ht.
2389 - '';
2390 - };
2391 -
2392 - port = mkOption {
2393 - type = types.port;
2394 - default = 5005;
2395 - description = ''
2396 - Port on which the "dispatch" module should listen.
2397 - '';
2398 - };
2399 -
2400 - database = mkOption {
2401 - type = types.str;
2402 - default = "dispatch.sr.ht";
2403 - description = ''
2404 - PostgreSQL database name for dispatch.sr.ht.
2405 - '';
2406 - };
2407 -
2408 - statePath = mkOption {
2409 - type = types.path;
2410 - default = "${cfg.statePath}/dispatchsrht";
2411 - description = ''
2412 - State path for dispatch.sr.ht.
2413 - '';
2414 - };
2415 - };
2416 -
2417 - config = with scfg; lib.mkIf (cfg.enable && elem "dispatch" cfg.services) {
2418 -
2419 - users = {
2420 - users = {
2421 - "${user}" = {
2422 - isSystemUser = true;
2423 - group = user;
2424 - description = "dispatch.sr.ht user";
2425 - };
2426 - };
2427 -
2428 - groups = {
2429 - "${user}" = { };
2430 - };
2431 - };
2432 -
2433 - services.postgresql = {
2434 - authentication = ''
2435 - local ${database} ${user} trust
2436 - '';
2437 - ensureDatabases = [ database ];
2438 - ensureUsers = [
2439 - {
2440 - name = user;
2441 - ensurePermissions = { "DATABASE \"${database}\"" = "ALL PRIVILEGES"; };
2442 - }
2443 - ];
2444 - };
2445 -
2446 - systemd = {
2447 - tmpfiles.rules = [
2448 - "d ${statePath} 0750 ${user} ${user} -"
2449 - ];
2450 -
2451 - services.dispatchsrht = import ./service.nix { inherit config pkgs lib; } scfg drv iniKey {
2452 - after = [ "postgresql.service" "network.target" ];
2453 - requires = [ "postgresql.service" ];
2454 - wantedBy = [ "multi-user.target" ];
2455 -
2456 - description = "dispatch.sr.ht website service";
2457 -
2458 - serviceConfig.ExecStart = "${cfg.python}/bin/gunicorn ${drv.pname}.app:app -b ${cfg.address}:${toString port}";
2459 - };
2460 - };
2461 -
2462 - services.sourcehut.settings = {
2463 - # URL dispatch.sr.ht is being served at (protocol://domain)
2464 - "dispatch.sr.ht".origin = mkDefault "http://dispatch.${cfg.originBase}";
2465 - # Address and port to bind the debug server to
2466 - "dispatch.sr.ht".debug-host = mkDefault "0.0.0.0";
2467 - "dispatch.sr.ht".debug-port = mkDefault port;
2468 - # Configures the SQLAlchemy connection string for the database.
2469 - "dispatch.sr.ht".connection-string = mkDefault "postgresql:///${database}?user=${user}&host=/var/run/postgresql";
2470 - # Set to "yes" to automatically run migrations on package upgrade.
2471 - "dispatch.sr.ht".migrate-on-upgrade = mkDefault "yes";
2472 - # dispatch.sr.ht's OAuth client ID and secret for meta.sr.ht
2473 - # Register your client at meta.example.org/oauth
2474 - "dispatch.sr.ht".oauth-client-id = mkDefault null;
2475 - "dispatch.sr.ht".oauth-client-secret = mkDefault null;
2476 -
2477 - # Github Integration
2478 - "dispatch.sr.ht::github".oauth-client-id = mkDefault null;
2479 - "dispatch.sr.ht::github".oauth-client-secret = mkDefault null;
2480 -
2481 - # Gitlab Integration
2482 - "dispatch.sr.ht::gitlab".enabled = mkDefault null;
2483 - "dispatch.sr.ht::gitlab".canonical-upstream = mkDefault "gitlab.com";
2484 - "dispatch.sr.ht::gitlab".repo-cache = mkDefault "./repo-cache";
2485 - # "dispatch.sr.ht::gitlab"."gitlab.com" = mkDefault "GitLab:application id:secret";
2486 - };
2487 -
2488 - services.nginx.virtualHosts."dispatch.${cfg.originBase}" = {
2489 - forceSSL = true;
2490 - locations."/".proxyPass = "http://${cfg.address}:${toString port}";
2491 - locations."/query".proxyPass = "http://${cfg.address}:${toString (port + 100)}";
2492 - locations."/static".root = "${pkgs.sourcehut.dispatchsrht}/${pkgs.sourcehut.python.sitePackages}/dispatchsrht";
2493 - };
2494 - };
2495 -}
2496 diff --git a/nixos/modules/services/misc/sourcehut/git.nix b/nixos/modules/services/misc/sourcehut/git.nix
2497 deleted file mode 100644
2498 index 2653d77876d..00000000000
2499 --- a/nixos/modules/services/misc/sourcehut/git.nix
2500 +++ /dev/null
2501 @@ -1,215 +0,0 @@
2502 -{ config, lib, pkgs, ... }:
2503 -
2504 -with lib;
2505 -let
2506 - cfg = config.services.sourcehut;
2507 - scfg = cfg.git;
2508 - iniKey = "git.sr.ht";
2509 -
2510 - rcfg = config.services.redis;
2511 - drv = pkgs.sourcehut.gitsrht;
2512 -in
2513 -{
2514 - options.services.sourcehut.git = {
2515 - user = mkOption {
2516 - type = types.str;
2517 - visible = false;
2518 - internal = true;
2519 - readOnly = true;
2520 - default = "git";
2521 - description = ''
2522 - User for git.sr.ht.
2523 - '';
2524 - };
2525 -
2526 - port = mkOption {
2527 - type = types.port;
2528 - default = 5001;
2529 - description = ''
2530 - Port on which the "git" module should listen.
2531 - '';
2532 - };
2533 -
2534 - database = mkOption {
2535 - type = types.str;
2536 - default = "git.sr.ht";
2537 - description = ''
2538 - PostgreSQL database name for git.sr.ht.
2539 - '';
2540 - };
2541 -
2542 - statePath = mkOption {
2543 - type = types.path;
2544 - default = "${cfg.statePath}/gitsrht";
2545 - description = ''
2546 - State path for git.sr.ht.
2547 - '';
2548 - };
2549 -
2550 - package = mkOption {
2551 - type = types.package;
2552 - default = pkgs.git;
2553 - defaultText = literalExpression "pkgs.git";
2554 - example = literalExpression "pkgs.gitFull";
2555 - description = ''
2556 - Git package for git.sr.ht. This can help silence collisions.
2557 - '';
2558 - };
2559 - };
2560 -
2561 - config = with scfg; lib.mkIf (cfg.enable && elem "git" cfg.services) {
2562 - # sshd refuses to run with `Unsafe AuthorizedKeysCommand ... bad ownership or modes for directory /nix/store`
2563 - environment.etc."ssh/gitsrht-dispatch" = {
2564 - mode = "0755";
2565 - text = ''
2566 - #! ${pkgs.stdenv.shell}
2567 - ${cfg.python}/bin/gitsrht-dispatch "$@"
2568 - '';
2569 - };
2570 -
2571 - # Needs this in the $PATH when sshing into the server
2572 - environment.systemPackages = [ cfg.git.package ];
2573 -
2574 - users = {
2575 - users = {
2576 - "${user}" = {
2577 - isSystemUser = true;
2578 - group = user;
2579 - # https://stackoverflow.com/questions/22314298/git-push-results-in-fatal-protocol-error-bad-line-length-character-this
2580 - # Probably could use gitsrht-shell if output is restricted to just parameters...
2581 - shell = pkgs.bash;
2582 - description = "git.sr.ht user";
2583 - };
2584 - };
2585 -
2586 - groups = {
2587 - "${user}" = { };
2588 - };
2589 - };
2590 -
2591 - services = {
2592 - cron.systemCronJobs = [ "*/20 * * * * ${cfg.python}/bin/gitsrht-periodic" ];
2593 - fcgiwrap.enable = true;
2594 -
2595 - openssh.authorizedKeysCommand = ''/etc/ssh/gitsrht-dispatch "%u" "%h" "%t" "%k"'';
2596 - openssh.authorizedKeysCommandUser = "root";
2597 - openssh.extraConfig = ''
2598 - PermitUserEnvironment SRHT_*
2599 - '';
2600 -
2601 - postgresql = {
2602 - authentication = ''
2603 - local ${database} ${user} trust
2604 - '';
2605 - ensureDatabases = [ database ];
2606 - ensureUsers = [
2607 - {
2608 - name = user;
2609 - ensurePermissions = { "DATABASE \"${database}\"" = "ALL PRIVILEGES"; };
2610 - }
2611 - ];
2612 - };
2613 - };
2614 -
2615 - systemd = {
2616 - tmpfiles.rules = [
2617 - # /var/log is owned by root
2618 - "f /var/log/git-srht-shell 0644 ${user} ${user} -"
2619 -
2620 - "d ${statePath} 0750 ${user} ${user} -"
2621 - "d ${cfg.settings."${iniKey}".repos} 2755 ${user} ${user} -"
2622 - ];
2623 -
2624 - services = {
2625 - gitsrht = import ./service.nix { inherit config pkgs lib; } scfg drv iniKey {
2626 - after = [ "redis.service" "postgresql.service" "network.target" ];
2627 - requires = [ "redis.service" "postgresql.service" ];
2628 - wantedBy = [ "multi-user.target" ];
2629 -
2630 - # Needs internally to create repos at the very least
2631 - path = [ pkgs.git ];
2632 - description = "git.sr.ht website service";
2633 -
2634 - serviceConfig.ExecStart = "${cfg.python}/bin/gunicorn ${drv.pname}.app:app -b ${cfg.address}:${toString port}";
2635 - };
2636 -
2637 - gitsrht-webhooks = {
2638 - after = [ "postgresql.service" "network.target" ];
2639 - requires = [ "postgresql.service" ];
2640 - wantedBy = [ "multi-user.target" ];
2641 -
2642 - description = "git.sr.ht webhooks service";
2643 - serviceConfig = {
2644 - Type = "simple";
2645 - User = user;
2646 - Restart = "always";
2647 - };
2648 -
2649 - serviceConfig.ExecStart = "${cfg.python}/bin/celery -A ${drv.pname}.webhooks worker --loglevel=info";
2650 - };
2651 - };
2652 - };
2653 -
2654 - services.sourcehut.settings = {
2655 - # URL git.sr.ht is being served at (protocol://domain)
2656 - "git.sr.ht".origin = mkDefault "http://git.${cfg.originBase}";
2657 - # Address and port to bind the debug server to
2658 - "git.sr.ht".debug-host = mkDefault "0.0.0.0";
2659 - "git.sr.ht".debug-port = mkDefault port;
2660 - # Configures the SQLAlchemy connection string for the database.
2661 - "git.sr.ht".connection-string = mkDefault "postgresql:///${database}?user=${user}&host=/var/run/postgresql";
2662 - # Set to "yes" to automatically run migrations on package upgrade.
2663 - "git.sr.ht".migrate-on-upgrade = mkDefault "yes";
2664 - # The redis connection used for the webhooks worker
2665 - "git.sr.ht".webhooks = mkDefault "redis://${rcfg.bind}:${toString rcfg.port}/1";
2666 -
2667 - # A post-update script which is installed in every git repo.
2668 - "git.sr.ht".post-update-script = mkDefault "${pkgs.sourcehut.gitsrht}/bin/gitsrht-update-hook";
2669 -
2670 - # git.sr.ht's OAuth client ID and secret for meta.sr.ht
2671 - # Register your client at meta.example.org/oauth
2672 - "git.sr.ht".oauth-client-id = mkDefault null;
2673 - "git.sr.ht".oauth-client-secret = mkDefault null;
2674 - # Path to git repositories on disk
2675 - "git.sr.ht".repos = mkDefault "/var/lib/git";
2676 -
2677 - "git.sr.ht".outgoing-domain = mkDefault "http://git.${cfg.originBase}";
2678 -
2679 - # The authorized keys hook uses this to dispatch to various handlers
2680 - # The format is a program to exec into as the key, and the user to match as the
2681 - # value. When someone tries to log in as this user, this program is executed
2682 - # and is expected to omit an AuthorizedKeys file.
2683 - #
2684 - # Discard of the string context is in order to allow derivation-derived strings.
2685 - # This is safe if the relevant package is installed which will be the case if the setting is utilized.
2686 - "git.sr.ht::dispatch".${builtins.unsafeDiscardStringContext "${pkgs.sourcehut.gitsrht}/bin/gitsrht-keys"} = mkDefault "${user}:${user}";
2687 - };
2688 -
2689 - services.nginx.virtualHosts."git.${cfg.originBase}" = {
2690 - forceSSL = true;
2691 - locations."/".proxyPass = "http://${cfg.address}:${toString port}";
2692 - locations."/query".proxyPass = "http://${cfg.address}:${toString (port + 100)}";
2693 - locations."/static".root = "${pkgs.sourcehut.gitsrht}/${pkgs.sourcehut.python.sitePackages}/gitsrht";
2694 - extraConfig = ''
2695 - location = /authorize {
2696 - proxy_pass http://${cfg.address}:${toString port};
2697 - proxy_pass_request_body off;
2698 - proxy_set_header Content-Length "";
2699 - proxy_set_header X-Original-URI $request_uri;
2700 - }
2701 - location ~ ^/([^/]+)/([^/]+)/(HEAD|info/refs|objects/info/.*|git-upload-pack).*$ {
2702 - auth_request /authorize;
2703 - root /var/lib/git;
2704 - fastcgi_pass unix:/run/fcgiwrap.sock;
2705 - fastcgi_param SCRIPT_FILENAME ${pkgs.git}/bin/git-http-backend;
2706 - fastcgi_param PATH_INFO $uri;
2707 - fastcgi_param GIT_PROJECT_ROOT $document_root;
2708 - fastcgi_read_timeout 500s;
2709 - include ${pkgs.nginx}/conf/fastcgi_params;
2710 - gzip off;
2711 - }
2712 - '';
2713 -
2714 - };
2715 - };
2716 -}
2717 diff --git a/nixos/modules/services/misc/sourcehut/hg.nix b/nixos/modules/services/misc/sourcehut/hg.nix
2718 deleted file mode 100644
2719 index 5cd36bb0455..00000000000
2720 --- a/nixos/modules/services/misc/sourcehut/hg.nix
2721 +++ /dev/null
2722 @@ -1,173 +0,0 @@
2723 -{ config, lib, pkgs, ... }:
2724 -
2725 -with lib;
2726 -let
2727 - cfg = config.services.sourcehut;
2728 - scfg = cfg.hg;
2729 - iniKey = "hg.sr.ht";
2730 -
2731 - rcfg = config.services.redis;
2732 - drv = pkgs.sourcehut.hgsrht;
2733 -in
2734 -{
2735 - options.services.sourcehut.hg = {
2736 - user = mkOption {
2737 - type = types.str;
2738 - internal = true;
2739 - readOnly = true;
2740 - default = "hg";
2741 - description = ''
2742 - User for hg.sr.ht.
2743 - '';
2744 - };
2745 -
2746 - port = mkOption {
2747 - type = types.port;
2748 - default = 5010;
2749 - description = ''
2750 - Port on which the "hg" module should listen.
2751 - '';
2752 - };
2753 -
2754 - database = mkOption {
2755 - type = types.str;
2756 - default = "hg.sr.ht";
2757 - description = ''
2758 - PostgreSQL database name for hg.sr.ht.
2759 - '';
2760 - };
2761 -
2762 - statePath = mkOption {
2763 - type = types.path;
2764 - default = "${cfg.statePath}/hgsrht";
2765 - description = ''
2766 - State path for hg.sr.ht.
2767 - '';
2768 - };
2769 -
2770 - cloneBundles = mkOption {
2771 - type = types.bool;
2772 - default = false;
2773 - description = ''
2774 - Generate clonebundles (which require more disk space but dramatically speed up cloning large repositories).
2775 - '';
2776 - };
2777 - };
2778 -
2779 - config = with scfg; lib.mkIf (cfg.enable && elem "hg" cfg.services) {
2780 - # In case it ever comes into being
2781 - environment.etc."ssh/hgsrht-dispatch" = {
2782 - mode = "0755";
2783 - text = ''
2784 - #! ${pkgs.stdenv.shell}
2785 - ${cfg.python}/bin/gitsrht-dispatch $@
2786 - '';
2787 - };
2788 -
2789 - environment.systemPackages = [ pkgs.mercurial ];
2790 -
2791 - users = {
2792 - users = {
2793 - "${user}" = {
2794 - isSystemUser = true;
2795 - group = user;
2796 - # Assuming hg.sr.ht needs this too
2797 - shell = pkgs.bash;
2798 - description = "hg.sr.ht user";
2799 - };
2800 - };
2801 -
2802 - groups = {
2803 - "${user}" = { };
2804 - };
2805 - };
2806 -
2807 - services = {
2808 - cron.systemCronJobs = [ "*/20 * * * * ${cfg.python}/bin/hgsrht-periodic" ]
2809 - ++ optional cloneBundles "0 * * * * ${cfg.python}/bin/hgsrht-clonebundles";
2810 -
2811 - openssh.authorizedKeysCommand = ''/etc/ssh/hgsrht-dispatch "%u" "%h" "%t" "%k"'';
2812 - openssh.authorizedKeysCommandUser = "root";
2813 - openssh.extraConfig = ''
2814 - PermitUserEnvironment SRHT_*
2815 - '';
2816 -
2817 - postgresql = {
2818 - authentication = ''
2819 - local ${database} ${user} trust
2820 - '';
2821 - ensureDatabases = [ database ];
2822 - ensureUsers = [
2823 - {
2824 - name = user;
2825 - ensurePermissions = { "DATABASE \"${database}\"" = "ALL PRIVILEGES"; };
2826 - }
2827 - ];
2828 - };
2829 - };
2830 -
2831 - systemd = {
2832 - tmpfiles.rules = [
2833 - # /var/log is owned by root
2834 - "f /var/log/hg-srht-shell 0644 ${user} ${user} -"
2835 -
2836 - "d ${statePath} 0750 ${user} ${user} -"
2837 - "d ${cfg.settings."${iniKey}".repos} 2755 ${user} ${user} -"
2838 - ];
2839 -
2840 - services.hgsrht = import ./service.nix { inherit config pkgs lib; } scfg drv iniKey {
2841 - after = [ "redis.service" "postgresql.service" "network.target" ];
2842 - requires = [ "redis.service" "postgresql.service" ];
2843 - wantedBy = [ "multi-user.target" ];
2844 -
2845 - path = [ pkgs.mercurial ];
2846 - description = "hg.sr.ht website service";
2847 -
2848 - serviceConfig.ExecStart = "${cfg.python}/bin/gunicorn ${drv.pname}.app:app -b ${cfg.address}:${toString port}";
2849 - };
2850 - };
2851 -
2852 - services.sourcehut.settings = {
2853 - # URL hg.sr.ht is being served at (protocol://domain)
2854 - "hg.sr.ht".origin = mkDefault "http://hg.${cfg.originBase}";
2855 - # Address and port to bind the debug server to
2856 - "hg.sr.ht".debug-host = mkDefault "0.0.0.0";
2857 - "hg.sr.ht".debug-port = mkDefault port;
2858 - # Configures the SQLAlchemy connection string for the database.
2859 - "hg.sr.ht".connection-string = mkDefault "postgresql:///${database}?user=${user}&host=/var/run/postgresql";
2860 - # The redis connection used for the webhooks worker
2861 - "hg.sr.ht".webhooks = mkDefault "redis://${rcfg.bind}:${toString rcfg.port}/1";
2862 - # A post-update script which is installed in every mercurial repo.
2863 - "hg.sr.ht".changegroup-script = mkDefault "${cfg.python}/bin/hgsrht-hook-changegroup";
2864 - # hg.sr.ht's OAuth client ID and secret for meta.sr.ht
2865 - # Register your client at meta.example.org/oauth
2866 - "hg.sr.ht".oauth-client-id = mkDefault null;
2867 - "hg.sr.ht".oauth-client-secret = mkDefault null;
2868 - # Path to mercurial repositories on disk
2869 - "hg.sr.ht".repos = mkDefault "/var/lib/hg";
2870 - # Path to the srht mercurial extension
2871 - # (defaults to where the hgsrht code is)
2872 - # "hg.sr.ht".srhtext = mkDefault null;
2873 - # .hg/store size (in MB) past which the nightly job generates clone bundles.
2874 - # "hg.sr.ht".clone_bundle_threshold = mkDefault 50;
2875 - # Path to hg-ssh (if not in $PATH)
2876 - # "hg.sr.ht".hg_ssh = mkDefault /path/to/hg-ssh;
2877 -
2878 - # The authorized keys hook uses this to dispatch to various handlers
2879 - # The format is a program to exec into as the key, and the user to match as the
2880 - # value. When someone tries to log in as this user, this program is executed
2881 - # and is expected to omit an AuthorizedKeys file.
2882 - #
2883 - # Uncomment the relevant lines to enable the various sr.ht dispatchers.
2884 - "hg.sr.ht::dispatch"."/run/current-system/sw/bin/hgsrht-keys" = mkDefault "${user}:${user}";
2885 - };
2886 -
2887 - # TODO: requires testing and addition of hg-specific requirements
2888 - services.nginx.virtualHosts."hg.${cfg.originBase}" = {
2889 - forceSSL = true;
2890 - locations."/".proxyPass = "http://${cfg.address}:${toString port}";
2891 - locations."/query".proxyPass = "http://${cfg.address}:${toString (port + 100)}";
2892 - locations."/static".root = "${pkgs.sourcehut.hgsrht}/${pkgs.sourcehut.python.sitePackages}/hgsrht";
2893 - };
2894 - };
2895 -}
2896 diff --git a/nixos/modules/services/misc/sourcehut/hub.nix b/nixos/modules/services/misc/sourcehut/hub.nix
2897 deleted file mode 100644
2898 index be3ea21011c..00000000000
2899 --- a/nixos/modules/services/misc/sourcehut/hub.nix
2900 +++ /dev/null
2901 @@ -1,118 +0,0 @@
2902 -{ config, lib, pkgs, ... }:
2903 -
2904 -with lib;
2905 -let
2906 - cfg = config.services.sourcehut;
2907 - cfgIni = cfg.settings;
2908 - scfg = cfg.hub;
2909 - iniKey = "hub.sr.ht";
2910 -
2911 - drv = pkgs.sourcehut.hubsrht;
2912 -in
2913 -{
2914 - options.services.sourcehut.hub = {
2915 - user = mkOption {
2916 - type = types.str;
2917 - default = "hubsrht";
2918 - description = ''
2919 - User for hub.sr.ht.
2920 - '';
2921 - };
2922 -
2923 - port = mkOption {
2924 - type = types.port;
2925 - default = 5014;
2926 - description = ''
2927 - Port on which the "hub" module should listen.
2928 - '';
2929 - };
2930 -
2931 - database = mkOption {
2932 - type = types.str;
2933 - default = "hub.sr.ht";
2934 - description = ''
2935 - PostgreSQL database name for hub.sr.ht.
2936 - '';
2937 - };
2938 -
2939 - statePath = mkOption {
2940 - type = types.path;
2941 - default = "${cfg.statePath}/hubsrht";
2942 - description = ''
2943 - State path for hub.sr.ht.
2944 - '';
2945 - };
2946 - };
2947 -
2948 - config = with scfg; lib.mkIf (cfg.enable && elem "hub" cfg.services) {
2949 - users = {
2950 - users = {
2951 - "${user}" = {
2952 - isSystemUser = true;
2953 - group = user;
2954 - description = "hub.sr.ht user";
2955 - };
2956 - };
2957 -
2958 - groups = {
2959 - "${user}" = { };
2960 - };
2961 - };
2962 -
2963 - services.postgresql = {
2964 - authentication = ''
2965 - local ${database} ${user} trust
2966 - '';
2967 - ensureDatabases = [ database ];
2968 - ensureUsers = [
2969 - {
2970 - name = user;
2971 - ensurePermissions = { "DATABASE \"${database}\"" = "ALL PRIVILEGES"; };
2972 - }
2973 - ];
2974 - };
2975 -
2976 - systemd = {
2977 - tmpfiles.rules = [
2978 - "d ${statePath} 0750 ${user} ${user} -"
2979 - ];
2980 -
2981 - services.hubsrht = import ./service.nix { inherit config pkgs lib; } scfg drv iniKey {
2982 - after = [ "postgresql.service" "network.target" ];
2983 - requires = [ "postgresql.service" ];
2984 - wantedBy = [ "multi-user.target" ];
2985 -
2986 - description = "hub.sr.ht website service";
2987 -
2988 - serviceConfig.ExecStart = "${cfg.python}/bin/gunicorn ${drv.pname}.app:app -b ${cfg.address}:${toString port}";
2989 - };
2990 - };
2991 -
2992 - services.sourcehut.settings = {
2993 - # URL hub.sr.ht is being served at (protocol://domain)
2994 - "hub.sr.ht".origin = mkDefault "http://hub.${cfg.originBase}";
2995 - # Address and port to bind the debug server to
2996 - "hub.sr.ht".debug-host = mkDefault "0.0.0.0";
2997 - "hub.sr.ht".debug-port = mkDefault port;
2998 - # Configures the SQLAlchemy connection string for the database.
2999 - "hub.sr.ht".connection-string = mkDefault "postgresql:///${database}?user=${user}&host=/var/run/postgresql";
3000 - # Set to "yes" to automatically run migrations on package upgrade.
3001 - "hub.sr.ht".migrate-on-upgrade = mkDefault "yes";
3002 - # hub.sr.ht's OAuth client ID and secret for meta.sr.ht
3003 - # Register your client at meta.example.org/oauth
3004 - "hub.sr.ht".oauth-client-id = mkDefault null;
3005 - "hub.sr.ht".oauth-client-secret = mkDefault null;
3006 - };
3007 -
3008 - services.nginx.virtualHosts."${cfg.originBase}" = {
3009 - forceSSL = true;
3010 - locations."/".proxyPass = "http://${cfg.address}:${toString port}";
3011 - locations."/query".proxyPass = "http://${cfg.address}:${toString (port + 100)}";
3012 - locations."/static".root = "${pkgs.sourcehut.hubsrht}/${pkgs.sourcehut.python.sitePackages}/hubsrht";
3013 - };
3014 - services.nginx.virtualHosts."hub.${cfg.originBase}" = {
3015 - globalRedirect = "${cfg.originBase}";
3016 - forceSSL = true;
3017 - };
3018 - };
3019 -}
3020 diff --git a/nixos/modules/services/misc/sourcehut/lists.nix b/nixos/modules/services/misc/sourcehut/lists.nix
3021 deleted file mode 100644
3022 index 7b1fe9fd463..00000000000
3023 --- a/nixos/modules/services/misc/sourcehut/lists.nix
3024 +++ /dev/null
3025 @@ -1,185 +0,0 @@
3026 -# Email setup is fairly involved, useful references:
3027 -# https://drewdevault.com/2018/08/05/Local-mail-server.html
3028 -
3029 -{ config, lib, pkgs, ... }:
3030 -
3031 -with lib;
3032 -let
3033 - cfg = config.services.sourcehut;
3034 - cfgIni = cfg.settings;
3035 - scfg = cfg.lists;
3036 - iniKey = "lists.sr.ht";
3037 -
3038 - rcfg = config.services.redis;
3039 - drv = pkgs.sourcehut.listssrht;
3040 -in
3041 -{
3042 - options.services.sourcehut.lists = {
3043 - user = mkOption {
3044 - type = types.str;
3045 - default = "listssrht";
3046 - description = ''
3047 - User for lists.sr.ht.
3048 - '';
3049 - };
3050 -
3051 - port = mkOption {
3052 - type = types.port;
3053 - default = 5006;
3054 - description = ''
3055 - Port on which the "lists" module should listen.
3056 - '';
3057 - };
3058 -
3059 - database = mkOption {
3060 - type = types.str;
3061 - default = "lists.sr.ht";
3062 - description = ''
3063 - PostgreSQL database name for lists.sr.ht.
3064 - '';
3065 - };
3066 -
3067 - statePath = mkOption {
3068 - type = types.path;
3069 - default = "${cfg.statePath}/listssrht";
3070 - description = ''
3071 - State path for lists.sr.ht.
3072 - '';
3073 - };
3074 - };
3075 -
3076 - config = with scfg; lib.mkIf (cfg.enable && elem "lists" cfg.services) {
3077 - users = {
3078 - users = {
3079 - "${user}" = {
3080 - isSystemUser = true;
3081 - group = user;
3082 - extraGroups = [ "postfix" ];
3083 - description = "lists.sr.ht user";
3084 - };
3085 - };
3086 - groups = {
3087 - "${user}" = { };
3088 - };
3089 - };
3090 -
3091 - services.postgresql = {
3092 - authentication = ''
3093 - local ${database} ${user} trust
3094 - '';
3095 - ensureDatabases = [ database ];
3096 - ensureUsers = [
3097 - {
3098 - name = user;
3099 - ensurePermissions = { "DATABASE \"${database}\"" = "ALL PRIVILEGES"; };
3100 - }
3101 - ];
3102 - };
3103 -
3104 - systemd = {
3105 - tmpfiles.rules = [
3106 - "d ${statePath} 0750 ${user} ${user} -"
3107 - ];
3108 -
3109 - services = {
3110 - listssrht = import ./service.nix { inherit config pkgs lib; } scfg drv iniKey {
3111 - after = [ "postgresql.service" "network.target" ];
3112 - requires = [ "postgresql.service" ];
3113 - wantedBy = [ "multi-user.target" ];
3114 -
3115 - description = "lists.sr.ht website service";
3116 -
3117 - serviceConfig.ExecStart = "${cfg.python}/bin/gunicorn ${drv.pname}.app:app -b ${cfg.address}:${toString port}";
3118 - };
3119 -
3120 - listssrht-process = {
3121 - after = [ "postgresql.service" "network.target" ];
3122 - requires = [ "postgresql.service" ];
3123 - wantedBy = [ "multi-user.target" ];
3124 -
3125 - description = "lists.sr.ht process service";
3126 - serviceConfig = {
3127 - Type = "simple";
3128 - User = user;
3129 - Restart = "always";
3130 - ExecStart = "${cfg.python}/bin/celery -A ${drv.pname}.process worker --loglevel=info";
3131 - };
3132 - };
3133 -
3134 - listssrht-lmtp = {
3135 - after = [ "postgresql.service" "network.target" ];
3136 - requires = [ "postgresql.service" ];
3137 - wantedBy = [ "multi-user.target" ];
3138 -
3139 - description = "lists.sr.ht process service";
3140 - serviceConfig = {
3141 - Type = "simple";
3142 - User = user;
3143 - Restart = "always";
3144 - ExecStart = "${cfg.python}/bin/listssrht-lmtp";
3145 - };
3146 - };
3147 -
3148 -
3149 - listssrht-webhooks = {
3150 - after = [ "postgresql.service" "network.target" ];
3151 - requires = [ "postgresql.service" ];
3152 - wantedBy = [ "multi-user.target" ];
3153 -
3154 - description = "lists.sr.ht webhooks service";
3155 - serviceConfig = {
3156 - Type = "simple";
3157 - User = user;
3158 - Restart = "always";
3159 - ExecStart = "${cfg.python}/bin/celery -A ${drv.pname}.webhooks worker --loglevel=info";
3160 - };
3161 - };
3162 - };
3163 - };
3164 -
3165 - services.sourcehut.settings = {
3166 - # URL lists.sr.ht is being served at (protocol://domain)
3167 - "lists.sr.ht".origin = mkDefault "http://lists.${cfg.originBase}";
3168 - # Address and port to bind the debug server to
3169 - "lists.sr.ht".debug-host = mkDefault "0.0.0.0";
3170 - "lists.sr.ht".debug-port = mkDefault port;
3171 - # Configures the SQLAlchemy connection string for the database.
3172 - "lists.sr.ht".connection-string = mkDefault "postgresql:///${database}?user=${user}&host=/var/run/postgresql";
3173 - # Set to "yes" to automatically run migrations on package upgrade.
3174 - "lists.sr.ht".migrate-on-upgrade = mkDefault "yes";
3175 - # lists.sr.ht's OAuth client ID and secret for meta.sr.ht
3176 - # Register your client at meta.example.org/oauth
3177 - "lists.sr.ht".oauth-client-id = mkDefault null;
3178 - "lists.sr.ht".oauth-client-secret = mkDefault null;
3179 - # Outgoing email for notifications generated by users
3180 - "lists.sr.ht".notify-from = mkDefault "CHANGEME@example.org";
3181 - # The redis connection used for the webhooks worker
3182 - "lists.sr.ht".webhooks = mkDefault "redis://${rcfg.bind}:${toString rcfg.port}/2";
3183 - # The redis connection used for the celery worker
3184 - "lists.sr.ht".redis = mkDefault "redis://${rcfg.bind}:${toString rcfg.port}/4";
3185 - # Network-key
3186 - "lists.sr.ht".network-key = mkDefault null;
3187 - # Allow creation
3188 - "lists.sr.ht".allow-new-lists = mkDefault "no";
3189 - # Posting Domain
3190 - "lists.sr.ht".posting-domain = mkDefault "lists.${cfg.originBase}";
3191 -
3192 - # Path for the lmtp daemon's unix socket. Direct incoming mail to this socket.
3193 - # Alternatively, specify IP:PORT and an SMTP server will be run instead.
3194 - "lists.sr.ht::worker".sock = mkDefault "/tmp/lists.sr.ht-lmtp.sock";
3195 - # The lmtp daemon will make the unix socket group-read/write for users in this
3196 - # group.
3197 - "lists.sr.ht::worker".sock-group = mkDefault "postfix";
3198 - "lists.sr.ht::worker".reject-url = mkDefault "https://man.sr.ht/lists.sr.ht/etiquette.md";
3199 - "lists.sr.ht::worker".reject-mimetypes = mkDefault "text/html";
3200 -
3201 - };
3202 -
3203 - services.nginx.virtualHosts."lists.${cfg.originBase}" = {
3204 - forceSSL = true;
3205 - locations."/".proxyPass = "http://${cfg.address}:${toString port}";
3206 - locations."/query".proxyPass = "http://${cfg.address}:${toString (port + 100)}";
3207 - locations."/static".root = "${pkgs.sourcehut.listssrht}/${pkgs.sourcehut.python.sitePackages}/listssrht";
3208 - };
3209 - };
3210 -}
3211 diff --git a/nixos/modules/services/misc/sourcehut/man.nix b/nixos/modules/services/misc/sourcehut/man.nix
3212 deleted file mode 100644
3213 index 7693396d187..00000000000
3214 --- a/nixos/modules/services/misc/sourcehut/man.nix
3215 +++ /dev/null
3216 @@ -1,122 +0,0 @@
3217 -{ config, lib, pkgs, ... }:
3218 -
3219 -with lib;
3220 -let
3221 - cfg = config.services.sourcehut;
3222 - cfgIni = cfg.settings;
3223 - scfg = cfg.man;
3224 - iniKey = "man.sr.ht";
3225 -
3226 - drv = pkgs.sourcehut.mansrht;
3227 -in
3228 -{
3229 - options.services.sourcehut.man = {
3230 - user = mkOption {
3231 - type = types.str;
3232 - default = "mansrht";
3233 - description = ''
3234 - User for man.sr.ht.
3235 - '';
3236 - };
3237 -
3238 - port = mkOption {
3239 - type = types.port;
3240 - default = 5004;
3241 - description = ''
3242 - Port on which the "man" module should listen.
3243 - '';
3244 - };
3245 -
3246 - database = mkOption {
3247 - type = types.str;
3248 - default = "man.sr.ht";
3249 - description = ''
3250 - PostgreSQL database name for man.sr.ht.
3251 - '';
3252 - };
3253 -
3254 - statePath = mkOption {
3255 - type = types.path;
3256 - default = "${cfg.statePath}/mansrht";
3257 - description = ''
3258 - State path for man.sr.ht.
3259 - '';
3260 - };
3261 - };
3262 -
3263 - config = with scfg; lib.mkIf (cfg.enable && elem "man" cfg.services) {
3264 - assertions =
3265 - [
3266 - {
3267 - assertion = hasAttrByPath [ "git.sr.ht" "oauth-client-id" ] cfgIni;
3268 - message = "man.sr.ht needs access to git.sr.ht.";
3269 - }
3270 - ];
3271 -
3272 - users = {
3273 - users = {
3274 - "${user}" = {
3275 - isSystemUser = true;
3276 - group = user;
3277 - description = "man.sr.ht user";
3278 - };
3279 - };
3280 -
3281 - groups = {
3282 - "${user}" = { };
3283 - };
3284 - };
3285 -
3286 - services.postgresql = {
3287 - authentication = ''
3288 - local ${database} ${user} trust
3289 - '';
3290 - ensureDatabases = [ database ];
3291 - ensureUsers = [
3292 - {
3293 - name = user;
3294 - ensurePermissions = { "DATABASE \"${database}\"" = "ALL PRIVILEGES"; };
3295 - }
3296 - ];
3297 - };
3298 -
3299 - systemd = {
3300 - tmpfiles.rules = [
3301 - "d ${statePath} 0750 ${user} ${user} -"
3302 - ];
3303 -
3304 - services.mansrht = import ./service.nix { inherit config pkgs lib; } scfg drv iniKey {
3305 - after = [ "postgresql.service" "network.target" ];
3306 - requires = [ "postgresql.service" ];
3307 - wantedBy = [ "multi-user.target" ];
3308 -
3309 - description = "man.sr.ht website service";
3310 -
3311 - serviceConfig.ExecStart = "${cfg.python}/bin/gunicorn ${drv.pname}.app:app -b ${cfg.address}:${toString port}";
3312 - };
3313 - };
3314 -
3315 - services.sourcehut.settings = {
3316 - # URL man.sr.ht is being served at (protocol://domain)
3317 - "man.sr.ht".origin = mkDefault "http://man.${cfg.originBase}";
3318 - # Address and port to bind the debug server to
3319 - "man.sr.ht".debug-host = mkDefault "0.0.0.0";
3320 - "man.sr.ht".debug-port = mkDefault port;
3321 - # Configures the SQLAlchemy connection string for the database.
3322 - "man.sr.ht".connection-string = mkDefault "postgresql:///${database}?user=${user}&host=/var/run/postgresql";
3323 - # Set to "yes" to automatically run migrations on package upgrade.
3324 - "man.sr.ht".migrate-on-upgrade = mkDefault "yes";
3325 - # man.sr.ht's OAuth client ID and secret for meta.sr.ht
3326 - # Register your client at meta.example.org/oauth
3327 - "man.sr.ht".oauth-client-id = mkDefault null;
3328 - "man.sr.ht".oauth-client-secret = mkDefault null;
3329 - };
3330 -
3331 - services.nginx.virtualHosts."man.${cfg.originBase}" = {
3332 - forceSSL = true;
3333 - locations."/".proxyPass = "http://${cfg.address}:${toString port}";
3334 - locations."/query".proxyPass = "http://${cfg.address}:${toString (port + 100)}";
3335 - locations."/static".root = "${pkgs.sourcehut.mansrht}/${pkgs.sourcehut.python.sitePackages}/mansrht";
3336 - };
3337 - };
3338 -}
3339 diff --git a/nixos/modules/services/misc/sourcehut/meta.nix b/nixos/modules/services/misc/sourcehut/meta.nix
3340 deleted file mode 100644
3341 index 56127a824eb..00000000000
3342 --- a/nixos/modules/services/misc/sourcehut/meta.nix
3343 +++ /dev/null
3344 @@ -1,211 +0,0 @@
3345 -{ config, lib, pkgs, ... }:
3346 -
3347 -with lib;
3348 -let
3349 - cfg = config.services.sourcehut;
3350 - cfgIni = cfg.settings;
3351 - scfg = cfg.meta;
3352 - iniKey = "meta.sr.ht";
3353 -
3354 - rcfg = config.services.redis;
3355 - drv = pkgs.sourcehut.metasrht;
3356 -in
3357 -{
3358 - options.services.sourcehut.meta = {
3359 - user = mkOption {
3360 - type = types.str;
3361 - default = "metasrht";
3362 - description = ''
3363 - User for meta.sr.ht.
3364 - '';
3365 - };
3366 -
3367 - port = mkOption {
3368 - type = types.port;
3369 - default = 5000;
3370 - description = ''
3371 - Port on which the "meta" module should listen.
3372 - '';
3373 - };
3374 -
3375 - database = mkOption {
3376 - type = types.str;
3377 - default = "meta.sr.ht";
3378 - description = ''
3379 - PostgreSQL database name for meta.sr.ht.
3380 - '';
3381 - };
3382 -
3383 - statePath = mkOption {
3384 - type = types.path;
3385 - default = "${cfg.statePath}/metasrht";
3386 - description = ''
3387 - State path for meta.sr.ht.
3388 - '';
3389 - };
3390 - };
3391 -
3392 - config = with scfg; lib.mkIf (cfg.enable && elem "meta" cfg.services) {
3393 - assertions =
3394 - [
3395 - {
3396 - assertion = with cfgIni."meta.sr.ht::billing"; enabled == "yes" -> (stripe-public-key != null && stripe-secret-key != null);
3397 - message = "If meta.sr.ht::billing is enabled, the keys should be defined.";
3398 - }
3399 - ];
3400 -
3401 - users = {
3402 - users = {
3403 - ${user} = {
3404 - isSystemUser = true;
3405 - group = user;
3406 - description = "meta.sr.ht user";
3407 - };
3408 - };
3409 -
3410 - groups = {
3411 - "${user}" = { };
3412 - };
3413 - };
3414 -
3415 - services.cron.systemCronJobs = [ "0 0 * * * ${cfg.python}/bin/metasrht-daily" ];
3416 - services.postgresql = {
3417 - authentication = ''
3418 - local ${database} ${user} trust
3419 - '';
3420 - ensureDatabases = [ database ];
3421 - ensureUsers = [
3422 - {
3423 - name = user;
3424 - ensurePermissions = { "DATABASE \"${database}\"" = "ALL PRIVILEGES"; };
3425 - }
3426 - ];
3427 - };
3428 -
3429 - systemd = {
3430 - tmpfiles.rules = [
3431 - "d ${statePath} 0750 ${user} ${user} -"
3432 - ];
3433 -
3434 - services = {
3435 - metasrht = import ./service.nix { inherit config pkgs lib; } scfg drv iniKey {
3436 - after = [ "postgresql.service" "network.target" ];
3437 - requires = [ "postgresql.service" ];
3438 - wantedBy = [ "multi-user.target" ];
3439 -
3440 - description = "meta.sr.ht website service";
3441 -
3442 - preStart = ''
3443 - # Configure client(s) as "preauthorized"
3444 - ${concatMapStringsSep "\n\n"
3445 - (attr: ''
3446 - if ! test -e "${statePath}/${attr}.oauth" || [ "$(cat ${statePath}/${attr}.oauth)" != "${cfgIni."${attr}".oauth-client-id}" ]; then
3447 - # Configure ${attr}'s OAuth client as "preauthorized"
3448 - psql ${database} \
3449 - -c "UPDATE oauthclient SET preauthorized = true WHERE client_id = '${cfgIni."${attr}".oauth-client-id}'"
3450 -
3451 - printf "%s" "${cfgIni."${attr}".oauth-client-id}" > "${statePath}/${attr}.oauth"
3452 - fi
3453 - '')
3454 - (builtins.attrNames (filterAttrs
3455 - (k: v: !(hasInfix "::" k) && builtins.hasAttr "oauth-client-id" v && v.oauth-client-id != null)
3456 - cfg.settings))}
3457 - '';
3458 -
3459 - serviceConfig.ExecStart = "${cfg.python}/bin/gunicorn ${drv.pname}.app:app -b ${cfg.address}:${toString port}";
3460 - };
3461 -
3462 - metasrht-api = import ./service.nix { inherit config pkgs lib; } scfg drv iniKey {
3463 - after = [ "postgresql.service" "network.target" ];
3464 - requires = [ "postgresql.service" ];
3465 - wantedBy = [ "multi-user.target" ];
3466 -
3467 - description = "meta.sr.ht api service";
3468 -
3469 - preStart = ''
3470 - # Configure client(s) as "preauthorized"
3471 - ${concatMapStringsSep "\n\n"
3472 - (attr: ''
3473 - if ! test -e "${statePath}/${attr}.oauth" || [ "$(cat ${statePath}/${attr}.oauth)" != "${cfgIni."${attr}".oauth-client-id}" ]; then
3474 - # Configure ${attr}'s OAuth client as "preauthorized"
3475 - psql ${database} \
3476 - -c "UPDATE oauthclient SET preauthorized = true WHERE client_id = '${cfgIni."${attr}".oauth-client-id}'"
3477 -
3478 - printf "%s" "${cfgIni."${attr}".oauth-client-id}" > "${statePath}/${attr}.oauth"
3479 - fi
3480 - '')
3481 - (builtins.attrNames (filterAttrs
3482 - (k: v: !(hasInfix "::" k) && builtins.hasAttr "oauth-client-id" v && v.oauth-client-id != null)
3483 - cfg.settings))}
3484 - '';
3485 -
3486 - serviceConfig.ExecStart = "${pkgs.sourcehut.metasrht}/bin/metasrht-api -b :${toString (port + 100)}";
3487 - };
3488 -
3489 - metasrht-webhooks = {
3490 - after = [ "postgresql.service" "network.target" ];
3491 - requires = [ "postgresql.service" ];
3492 - wantedBy = [ "multi-user.target" ];
3493 -
3494 - description = "meta.sr.ht webhooks service";
3495 - serviceConfig = {
3496 - Type = "simple";
3497 - User = user;
3498 - Restart = "always";
3499 - ExecStart = "${cfg.python}/bin/celery -A ${drv.pname}.webhooks worker --loglevel=info";
3500 - };
3501 -
3502 - };
3503 - };
3504 - };
3505 -
3506 - services.sourcehut.settings = {
3507 - # URL meta.sr.ht is being served at (protocol://domain)
3508 - "meta.sr.ht".origin = mkDefault "https://meta.${cfg.originBase}";
3509 - # Address and port to bind the debug server to
3510 - "meta.sr.ht".debug-host = mkDefault "0.0.0.0";
3511 - "meta.sr.ht".debug-port = mkDefault port;
3512 - # Configures the SQLAlchemy connection string for the database.
3513 - "meta.sr.ht".connection-string = mkDefault "postgresql:///${database}?user=${user}&host=/var/run/postgresql";
3514 - # Set to "yes" to automatically run migrations on package upgrade.
3515 - "meta.sr.ht".migrate-on-upgrade = mkDefault "yes";
3516 - # If "yes", the user will be sent the stock sourcehut welcome emails after
3517 - # signup (requires cron to be configured properly). These are specific to the
3518 - # sr.ht instance so you probably want to patch these before enabling this.
3519 - "meta.sr.ht".welcome-emails = mkDefault "no";
3520 -
3521 - # The redis connection used for the webhooks worker
3522 - "meta.sr.ht".webhooks = mkDefault "redis://${rcfg.bind}:${toString rcfg.port}/6";
3523 -
3524 - # If "no", public registration will not be permitted.
3525 - "meta.sr.ht::settings".registration = mkDefault "no";
3526 - # Where to redirect new users upon registration
3527 - "meta.sr.ht::settings".onboarding-redirect = mkDefault "https://meta.${cfg.originBase}";
3528 - # How many invites each user is issued upon registration (only applicable if
3529 - # open registration is disabled)
3530 - "meta.sr.ht::settings".user-invites = mkDefault 5;
3531 -
3532 - # Origin URL for API, 100 more than web
3533 - "meta.sr.ht".api-origin = mkDefault "http://localhost:5100";
3534 -
3535 - # You can add aliases for the client IDs of commonly used OAuth clients here.
3536 - #
3537 - # Example:
3538 - "meta.sr.ht::aliases" = mkDefault { };
3539 - # "meta.sr.ht::aliases"."git.sr.ht" = 12345;
3540 -
3541 - # "yes" to enable the billing system
3542 - "meta.sr.ht::billing".enabled = mkDefault "no";
3543 - # Get your keys at https://dashboard.stripe.com/account/apikeys
3544 - "meta.sr.ht::billing".stripe-public-key = mkDefault null;
3545 - "meta.sr.ht::billing".stripe-secret-key = mkDefault null;
3546 - };
3547 -
3548 - services.nginx.virtualHosts."meta.${cfg.originBase}" = {
3549 - forceSSL = true;
3550 - locations."/".proxyPass = "http://${cfg.address}:${toString port}";
3551 - locations."/query".proxyPass = "http://${cfg.address}:${toString (port + 100)}";
3552 - locations."/static".root = "${pkgs.sourcehut.metasrht}/${pkgs.sourcehut.python.sitePackages}/metasrht";
3553 - };
3554 - };
3555 -}
3556 diff --git a/nixos/modules/services/misc/sourcehut/paste.nix b/nixos/modules/services/misc/sourcehut/paste.nix
3557 deleted file mode 100644
3558 index b2d5151969e..00000000000
3559 --- a/nixos/modules/services/misc/sourcehut/paste.nix
3560 +++ /dev/null
3561 @@ -1,133 +0,0 @@
3562 -{ config, lib, pkgs, ... }:
3563 -
3564 -with lib;
3565 -let
3566 - cfg = config.services.sourcehut;
3567 - cfgIni = cfg.settings;
3568 - scfg = cfg.paste;
3569 - iniKey = "paste.sr.ht";
3570 -
3571 - rcfg = config.services.redis;
3572 - drv = pkgs.sourcehut.pastesrht;
3573 -in
3574 -{
3575 - options.services.sourcehut.paste = {
3576 - user = mkOption {
3577 - type = types.str;
3578 - default = "pastesrht";
3579 - description = ''
3580 - User for paste.sr.ht.
3581 - '';
3582 - };
3583 -
3584 - port = mkOption {
3585 - type = types.port;
3586 - default = 5011;
3587 - description = ''
3588 - Port on which the "paste" module should listen.
3589 - '';
3590 - };
3591 -
3592 - database = mkOption {
3593 - type = types.str;
3594 - default = "paste.sr.ht";
3595 - description = ''
3596 - PostgreSQL database name for paste.sr.ht.
3597 - '';
3598 - };
3599 -
3600 - statePath = mkOption {
3601 - type = types.path;
3602 - default = "${cfg.statePath}/pastesrht";
3603 - description = ''
3604 - State path for pastesrht.sr.ht.
3605 - '';
3606 - };
3607 - };
3608 -
3609 - config = with scfg; lib.mkIf (cfg.enable && elem "paste" cfg.services) {
3610 - users = {
3611 - users = {
3612 - "${user}" = {
3613 - isSystemUser = true;
3614 - group = user;
3615 - description = "paste.sr.ht user";
3616 - };
3617 - };
3618 -
3619 - groups = {
3620 - "${user}" = { };
3621 - };
3622 - };
3623 -
3624 - services.postgresql = {
3625 - authentication = ''
3626 - local ${database} ${user} trust
3627 - '';
3628 - ensureDatabases = [ database ];
3629 - ensureUsers = [
3630 - {
3631 - name = user;
3632 - ensurePermissions = { "DATABASE \"${database}\"" = "ALL PRIVILEGES"; };
3633 - }
3634 - ];
3635 - };
3636 -
3637 - systemd = {
3638 - tmpfiles.rules = [
3639 - "d ${statePath} 0750 ${user} ${user} -"
3640 - ];
3641 -
3642 - services = {
3643 - pastesrht = import ./service.nix { inherit config pkgs lib; } scfg drv iniKey {
3644 - after = [ "postgresql.service" "network.target" ];
3645 - requires = [ "postgresql.service" ];
3646 - wantedBy = [ "multi-user.target" ];
3647 -
3648 - description = "paste.sr.ht website service";
3649 -
3650 - serviceConfig.ExecStart = "${cfg.python}/bin/gunicorn ${drv.pname}.app:app -b ${cfg.address}:${toString port}";
3651 - };
3652 -
3653 - pastesrht-webhooks = {
3654 - after = [ "postgresql.service" "network.target" ];
3655 - requires = [ "postgresql.service" ];
3656 - wantedBy = [ "multi-user.target" ];
3657 -
3658 - description = "paste.sr.ht webhooks service";
3659 - serviceConfig = {
3660 - Type = "simple";
3661 - User = user;
3662 - Restart = "always";
3663 - ExecStart = "${cfg.python}/bin/celery -A ${drv.pname}.webhooks worker --loglevel=info";
3664 - };
3665 -
3666 - };
3667 - };
3668 - };
3669 -
3670 - services.sourcehut.settings = {
3671 - # URL paste.sr.ht is being served at (protocol://domain)
3672 - "paste.sr.ht".origin = mkDefault "http://paste.${cfg.originBase}";
3673 - # Address and port to bind the debug server to
3674 - "paste.sr.ht".debug-host = mkDefault "0.0.0.0";
3675 - "paste.sr.ht".debug-port = mkDefault port;
3676 - # Configures the SQLAlchemy connection string for the database.
3677 - "paste.sr.ht".connection-string = mkDefault "postgresql:///${database}?user=${user}&host=/var/run/postgresql";
3678 - # Set to "yes" to automatically run migrations on package upgrade.
3679 - "paste.sr.ht".migrate-on-upgrade = mkDefault "yes";
3680 - # paste.sr.ht's OAuth client ID and secret for meta.sr.ht
3681 - # Register your client at meta.example.org/oauth
3682 - "paste.sr.ht".oauth-client-id = mkDefault null;
3683 - "paste.sr.ht".oauth-client-secret = mkDefault null;
3684 - "paste.sr.ht".webhooks = mkDefault "redis://${rcfg.bind}:${toString rcfg.port}/5";
3685 - };
3686 -
3687 - services.nginx.virtualHosts."paste.${cfg.originBase}" = {
3688 - forceSSL = true;
3689 - locations."/".proxyPass = "http://${cfg.address}:${toString port}";
3690 - locations."/query".proxyPass = "http://${cfg.address}:${toString (port + 100)}";
3691 - locations."/static".root = "${pkgs.sourcehut.pastesrht}/${pkgs.sourcehut.python.sitePackages}/pastesrht";
3692 - };
3693 - };
3694 -}
3695 diff --git a/nixos/modules/services/misc/sourcehut/service.nix b/nixos/modules/services/misc/sourcehut/service.nix
3696 index 65b4ad020f9..b3c0efc07dd 100644
3697 --- a/nixos/modules/services/misc/sourcehut/service.nix
3698 +++ b/nixos/modules/services/misc/sourcehut/service.nix
3699 @@ -1,66 +1,375 @@
3700 -{ config, pkgs, lib }:
3701 -serviceCfg: serviceDrv: iniKey: attrs:
3702 +srv:
3703 +{ configIniOfService
3704 +, srvsrht ? "${srv}srht" # Because "buildsrht" does not follow that pattern (missing an "s").
3705 +, iniKey ? "${srv}.sr.ht"
3706 +, webhooks ? false
3707 +, extraTimers ? {}
3708 +, mainService ? {}
3709 +, extraServices ? {}
3710 +, extraConfig ? {}
3711 +, port
3712 +}:
3713 +{ config, lib, pkgs, ... }:
3714 +
3715 +with lib;
3716 let
3717 + inherit (config.services) postgresql;
3718 + redis = config.services.redis.servers."sourcehut-${srvsrht}";
3719 + inherit (config.users) users;
3720 cfg = config.services.sourcehut;
3721 - cfgIni = cfg.settings."${iniKey}";
3722 - pgSuperUser = config.services.postgresql.superUser;
3723 -
3724 - setupDB = pkgs.writeScript "${serviceDrv.pname}-gen-db" ''
3725 - #! ${cfg.python}/bin/python
3726 - from ${serviceDrv.pname}.app import db
3727 - db.create()
3728 - '';
3729 + configIni = configIniOfService srv;
3730 + srvCfg = cfg.${srv};
3731 + baseService = serviceName: { allowStripe ? false }: extraService: let
3732 + runDir = "/run/sourcehut/${serviceName}";
3733 + rootDir = "/run/sourcehut/chroots/${serviceName}";
3734 + in
3735 + mkMerge [ extraService {
3736 + after = [ "network.target" ] ++
3737 + optional cfg.postgresql.enable "postgresql.service" ++
3738 + optional cfg.redis.enable "redis-sourcehut-${srvsrht}.service";
3739 + requires =
3740 + optional cfg.postgresql.enable "postgresql.service" ++
3741 + optional cfg.redis.enable "redis-sourcehut-${srvsrht}.service";
3742 + path = [ pkgs.gawk ];
3743 + environment.HOME = runDir;
3744 + serviceConfig = {
3745 + User = mkDefault srvCfg.user;
3746 + Group = mkDefault srvCfg.group;
3747 + RuntimeDirectory = [
3748 + "sourcehut/${serviceName}"
3749 + # Used by *srht-keys which reads ../config.ini
3750 + "sourcehut/${serviceName}/subdir"
3751 + "sourcehut/chroots/${serviceName}"
3752 + ];
3753 + RuntimeDirectoryMode = "2750";
3754 + # No need for the chroot path once inside the chroot
3755 + InaccessiblePaths = [ "-+${rootDir}" ];
3756 + # g+rx is for group members (eg. fcgiwrap or nginx)
3757 + # to read Git/Mercurial repositories, buildlogs, etc.
3758 + # o+x is for intermediate directories created by BindPaths= and like,
3759 + # as they're owned by root:root.
3760 + UMask = "0026";
3761 + RootDirectory = rootDir;
3762 + RootDirectoryStartOnly = true;
3763 + PrivateTmp = true;
3764 + MountAPIVFS = true;
3765 + # config.ini is looked up in there, before /etc/srht/config.ini
3766 + # Note that it fails to be set in ExecStartPre=
3767 + WorkingDirectory = mkDefault ("-"+runDir);
3768 + BindReadOnlyPaths = [
3769 + builtins.storeDir
3770 + "/etc"
3771 + "/run/booted-system"
3772 + "/run/current-system"
3773 + "/run/systemd"
3774 + ] ++
3775 + optional cfg.postgresql.enable "/run/postgresql" ++
3776 + optional cfg.redis.enable "/run/redis-sourcehut-${srvsrht}";
3777 + # LoadCredential= are unfortunately not available in ExecStartPre=
3778 + # Hence this one is run as root (the +) with RootDirectoryStartOnly=
3779 + # to reach credentials wherever they are.
3780 + # Note that each systemd service gets its own ${runDir}/config.ini file.
3781 + ExecStartPre = mkBefore [("+"+pkgs.writeShellScript "${serviceName}-credentials" ''
3782 + set -x
3783 + # Replace values begining with a '<' by the content of the file whose name is after.
3784 + gawk '{ if (match($0,/^([^=]+=)<(.+)/,m)) { getline f < m[2]; print m[1] f } else print $0 }' ${configIni} |
3785 + ${optionalString (!allowStripe) "gawk '!/^stripe-secret-key=/' |"}
3786 + install -o ${srvCfg.user} -g root -m 400 /dev/stdin ${runDir}/config.ini
3787 + '')];
3788 + # The following options are only for optimizing:
3789 + # systemd-analyze security
3790 + AmbientCapabilities = "";
3791 + CapabilityBoundingSet = "";
3792 + # ProtectClock= adds DeviceAllow=char-rtc r
3793 + DeviceAllow = "";
3794 + LockPersonality = true;
3795 + MemoryDenyWriteExecute = true;
3796 + NoNewPrivileges = true;
3797 + PrivateDevices = true;
3798 + PrivateMounts = true;
3799 + PrivateNetwork = mkDefault false;
3800 + PrivateUsers = true;
3801 + ProcSubset = "pid";
3802 + ProtectClock = true;
3803 + ProtectControlGroups = true;
3804 + ProtectHome = true;
3805 + ProtectHostname = true;
3806 + ProtectKernelLogs = true;
3807 + ProtectKernelModules = true;
3808 + ProtectKernelTunables = true;
3809 + ProtectProc = "invisible";
3810 + ProtectSystem = "strict";
3811 + RemoveIPC = true;
3812 + RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ];
3813 + RestrictNamespaces = true;
3814 + RestrictRealtime = true;
3815 + RestrictSUIDSGID = true;
3816 + #SocketBindAllow = [ "tcp:${toString srvCfg.port}" "tcp:${toString srvCfg.prometheusPort}" ];
3817 + #SocketBindDeny = "any";
3818 + SystemCallFilter = [
3819 + "@system-service"
3820 + "~@aio" "~@keyring" "~@memlock" "~@privileged" "~@resources" "~@timer"
3821 + "@chown" "@setuid"
3822 + ];
3823 + SystemCallArchitectures = "native";
3824 + };
3825 + } ];
3826 in
3827 -with serviceCfg; with lib; recursiveUpdate
3828 {
3829 - environment.HOME = statePath;
3830 - path = [ config.services.postgresql.package ] ++ (attrs.path or [ ]);
3831 - restartTriggers = [ config.environment.etc."sr.ht/config.ini".source ];
3832 - serviceConfig = {
3833 - Type = "simple";
3834 - User = user;
3835 - Group = user;
3836 - Restart = "always";
3837 - WorkingDirectory = statePath;
3838 - } // (if (cfg.statePath == "/var/lib/sourcehut/${serviceDrv.pname}") then {
3839 - StateDirectory = [ "sourcehut/${serviceDrv.pname}" ];
3840 - } else {})
3841 - ;
3842 + options.services.sourcehut.${srv} = {
3843 + enable = mkEnableOption "${srv} service";
3844
3845 - preStart = ''
3846 - if ! test -e ${statePath}/db; then
3847 - # Setup the initial database
3848 - ${setupDB}
3849 + user = mkOption {
3850 + type = types.str;
3851 + default = srvsrht;
3852 + description = ''
3853 + User for ${srv}.sr.ht.
3854 + '';
3855 + };
3856
3857 - # Set the initial state of the database for future database upgrades
3858 - if test -e ${cfg.python}/bin/${serviceDrv.pname}-migrate; then
3859 - # Run alembic stamp head once to tell alembic the schema is up-to-date
3860 - ${cfg.python}/bin/${serviceDrv.pname}-migrate stamp head
3861 - fi
3862 + group = mkOption {
3863 + type = types.str;
3864 + default = srvsrht;
3865 + description = ''
3866 + Group for ${srv}.sr.ht.
3867 + Membership grants access to the Git/Mercurial repositories by default,
3868 + but not to the config.ini file (where secrets are).
3869 + '';
3870 + };
3871
3872 - printf "%s" "${serviceDrv.version}" > ${statePath}/db
3873 - fi
3874 + port = mkOption {
3875 + type = types.port;
3876 + default = port;
3877 + description = ''
3878 + Port on which the "${srv}" backend should listen.
3879 + '';
3880 + };
3881
3882 - # Update copy of each users' profile to the latest
3883 - # See https://lists.sr.ht/~sircmpwn/sr.ht-admins/<20190302181207.GA13778%40cirno.my.domain>
3884 - if ! test -e ${statePath}/webhook; then
3885 - # Update ${iniKey}'s users' profile copy to the latest
3886 - ${cfg.python}/bin/srht-update-profiles ${iniKey}
3887 + redis = {
3888 + host = mkOption {
3889 + type = types.str;
3890 + default = "unix:/run/redis-sourcehut-${srvsrht}/redis.sock?db=0";
3891 + example = "redis://shared.wireguard:6379/0";
3892 + description = ''
3893 + The redis host URL. This is used for caching and temporary storage, and must
3894 + be shared between nodes (e.g. git1.sr.ht and git2.sr.ht), but need not be
3895 + shared between services. It may be shared between services, however, with no
3896 + ill effect, if this better suits your infrastructure.
3897 + '';
3898 + };
3899 + };
3900
3901 - touch ${statePath}/webhook
3902 - fi
3903 + postgresql = {
3904 + database = mkOption {
3905 + type = types.str;
3906 + default = "${srv}.sr.ht";
3907 + description = ''
3908 + PostgreSQL database name for the ${srv}.sr.ht service,
3909 + used if <xref linkend="opt-services.sourcehut.postgresql.enable"/> is <literal>true</literal>.
3910 + '';
3911 + };
3912 + };
3913
3914 - ${optionalString (builtins.hasAttr "migrate-on-upgrade" cfgIni && cfgIni.migrate-on-upgrade == "yes") ''
3915 - if [ "$(cat ${statePath}/db)" != "${serviceDrv.version}" ]; then
3916 - # Manage schema migrations using alembic
3917 - ${cfg.python}/bin/${serviceDrv.pname}-migrate -a upgrade head
3918 + gunicorn = {
3919 + extraArgs = mkOption {
3920 + type = with types; listOf str;
3921 + default = ["--timeout 120" "--workers 1" "--log-level=info"];
3922 + description = "Extra arguments passed to Gunicorn.";
3923 + };
3924 + };
3925 + } // optionalAttrs webhooks {
3926 + webhooks = {
3927 + extraArgs = mkOption {
3928 + type = with types; listOf str;
3929 + default = ["--loglevel DEBUG" "--pool eventlet" "--without-heartbeat"];
3930 + description = "Extra arguments passed to the Celery responsible for webhooks.";
3931 + };
3932 + celeryConfig = mkOption {
3933 + type = types.lines;
3934 + default = "";
3935 + description = "Content of the <literal>celeryconfig.py</literal> used by the Celery responsible for webhooks.";
3936 + };
3937 + };
3938 + };
3939
3940 - # Mark down current package version
3941 - printf "%s" "${serviceDrv.version}" > ${statePath}/db
3942 - fi
3943 - ''}
3944 + config = lib.mkIf (cfg.enable && srvCfg.enable) (mkMerge [ extraConfig {
3945 + users = {
3946 + users = {
3947 + "${srvCfg.user}" = {
3948 + isSystemUser = true;
3949 + group = mkDefault srvCfg.group;
3950 + description = mkDefault "sourcehut user for ${srv}.sr.ht";
3951 + };
3952 + };
3953 + groups = {
3954 + "${srvCfg.group}" = { };
3955 + } // optionalAttrs (cfg.postgresql.enable
3956 + && hasSuffix "0" (postgresql.settings.unix_socket_permissions or "")) {
3957 + "postgres".members = [ srvCfg.user ];
3958 + } // optionalAttrs (cfg.redis.enable
3959 + && hasSuffix "0" (redis.settings.unixsocketperm or "")) {
3960 + "redis-sourcehut-${srvsrht}".members = [ srvCfg.user ];
3961 + };
3962 + };
3963
3964 - ${attrs.preStart or ""}
3965 - '';
3966 + services.nginx = mkIf cfg.nginx.enable {
3967 + virtualHosts."${srv}.${cfg.settings."sr.ht".global-domain}" = mkMerge [ {
3968 + forceSSL = true;
3969 + locations."/".proxyPass = "http://${cfg.listenAddress}:${toString srvCfg.port}";
3970 + locations."/static" = {
3971 + root = "${pkgs.sourcehut.${srvsrht}}/${pkgs.sourcehut.python.sitePackages}/${srvsrht}";
3972 + extraConfig = mkDefault ''
3973 + expires 30d;
3974 + '';
3975 + };
3976 + } cfg.nginx.virtualHost ];
3977 + };
3978 +
3979 + services.postgresql = mkIf cfg.postgresql.enable {
3980 + authentication = ''
3981 + local ${srvCfg.postgresql.database} ${srvCfg.user} trust
3982 + '';
3983 + ensureDatabases = [ srvCfg.postgresql.database ];
3984 + ensureUsers = map (name: {
3985 + inherit name;
3986 + ensurePermissions = { "DATABASE \"${srvCfg.postgresql.database}\"" = "ALL PRIVILEGES"; };
3987 + }) [srvCfg.user];
3988 + };
3989 +
3990 + services.sourcehut.services = mkDefault (filter (s: cfg.${s}.enable)
3991 + [ "builds" "dispatch" "git" "hg" "hub" "lists" "man" "meta" "pages" "paste" "todo" ]);
3992 +
3993 + services.sourcehut.settings = mkMerge [
3994 + {
3995 + "${srv}.sr.ht".origin = mkDefault "https://${srv}.${cfg.settings."sr.ht".global-domain}";
3996 + }
3997 +
3998 + (mkIf cfg.postgresql.enable {
3999 + "${srv}.sr.ht".connection-string = mkDefault "postgresql:///${srvCfg.postgresql.database}?user=${srvCfg.user}&host=/run/postgresql";
4000 + })
4001 + ];
4002 +
4003 + services.redis.servers."sourcehut-${srvsrht}" = mkIf cfg.redis.enable {
4004 + enable = true;
4005 + databases = 3;
4006 + syslog = true;
4007 + # TODO: set a more informed value
4008 + save = mkDefault [ [1800 10] [300 100] ];
4009 + settings = {
4010 + # TODO: set a more informed value
4011 + maxmemory = "128MB";
4012 + maxmemory-policy = "volatile-ttl";
4013 + };
4014 + };
4015 +
4016 + systemd.services = mkMerge [
4017 + {
4018 + "${srvsrht}" = baseService srvsrht { allowStripe = srv == "meta"; } (mkMerge [
4019 + {
4020 + description = "sourcehut ${srv}.sr.ht website service";
4021 + before = optional cfg.nginx.enable "nginx.service";
4022 + wants = optional cfg.nginx.enable "nginx.service";
4023 + wantedBy = [ "multi-user.target" ];
4024 + path = optional cfg.postgresql.enable postgresql.package;
4025 + # Beware: change in credentials' content will not trigger restart.
4026 + restartTriggers = [ configIni ];
4027 + serviceConfig = {
4028 + Type = "simple";
4029 + Restart = mkDefault "always";
4030 + #RestartSec = mkDefault "2min";
4031 + StateDirectory = [ "sourcehut/${srvsrht}" ];
4032 + StateDirectoryMode = "2750";
4033 + ExecStart = "${cfg.python}/bin/gunicorn ${srvsrht}.app:app --name ${srvsrht} --bind ${cfg.listenAddress}:${toString srvCfg.port} " + concatStringsSep " " srvCfg.gunicorn.extraArgs;
4034 + };
4035 + preStart = let
4036 + version = pkgs.sourcehut.${srvsrht}.version;
4037 + stateDir = "/var/lib/sourcehut/${srvsrht}";
4038 + in mkBefore ''
4039 + set -x
4040 + # Use the /run/sourcehut/${srvsrht}/config.ini
4041 + # installed by a previous ExecStartPre= in baseService
4042 + cd /run/sourcehut/${srvsrht}
4043 +
4044 + if test ! -e ${stateDir}/db; then
4045 + # Setup the initial database.
4046 + # Note that it stamps the alembic head afterward
4047 + ${cfg.python}/bin/${srvsrht}-initdb
4048 + echo ${version} >${stateDir}/db
4049 + fi
4050 +
4051 + ${optionalString cfg.settings.${iniKey}.migrate-on-upgrade ''
4052 + if [ "$(cat ${stateDir}/db)" != "${version}" ]; then
4053 + # Manage schema migrations using alembic
4054 + ${cfg.python}/bin/${srvsrht}-migrate -a upgrade head
4055 + echo ${version} >${stateDir}/db
4056 + fi
4057 + ''}
4058 +
4059 + # Update copy of each users' profile to the latest
4060 + # See https://lists.sr.ht/~sircmpwn/sr.ht-admins/<20190302181207.GA13778%40cirno.my.domain>
4061 + if test ! -e ${stateDir}/webhook; then
4062 + # Update ${iniKey}'s users' profile copy to the latest
4063 + ${cfg.python}/bin/srht-update-profiles ${iniKey}
4064 + touch ${stateDir}/webhook
4065 + fi
4066 + '';
4067 + } mainService ]);
4068 + }
4069 +
4070 + (mkIf webhooks {
4071 + "${srvsrht}-webhooks" = baseService "${srvsrht}-webhooks" {}
4072 + {
4073 + description = "sourcehut ${srv}.sr.ht webhooks service";
4074 + after = [ "${srvsrht}.service" ];
4075 + wantedBy = [ "${srvsrht}.service" ];
4076 + partOf = [ "${srvsrht}.service" ];
4077 + preStart = ''
4078 + cp ${pkgs.writeText "${srvsrht}-webhooks-celeryconfig.py" srvCfg.webhooks.celeryConfig} \
4079 + /run/sourcehut/${srvsrht}-webhooks/celeryconfig.py
4080 + '';
4081 + serviceConfig = {
4082 + Type = "simple";
4083 + Restart = "always";
4084 + ExecStart = "${cfg.python}/bin/celery --app ${srvsrht}.webhooks worker --hostname ${srvsrht}-webhooks@%%h " + concatStringsSep " " srvCfg.webhooks.extraArgs;
4085 + # Avoid crashing: os.getloadavg()
4086 + ProcSubset = mkForce "all";
4087 + };
4088 + };
4089 + })
4090 +
4091 + (mapAttrs (timerName: timer: (baseService timerName {} (mkMerge [
4092 + {
4093 + description = "sourcehut ${timerName} service";
4094 + after = [ "network.target" "${srvsrht}.service" ];
4095 + serviceConfig = {
4096 + Type = "oneshot";
4097 + ExecStart = "${cfg.python}/bin/${timerName}";
4098 + };
4099 + }
4100 + (timer.service or {})
4101 + ]))) extraTimers)
4102 +
4103 + (mapAttrs (serviceName: extraService: baseService serviceName {} (mkMerge [
4104 + {
4105 + description = "sourcehut ${serviceName} service";
4106 + # So that extraServices have the PostgreSQL database initialized.
4107 + after = [ "${srvsrht}.service" ];
4108 + wantedBy = [ "${srvsrht}.service" ];
4109 + partOf = [ "${srvsrht}.service" ];
4110 + serviceConfig = {
4111 + Type = "simple";
4112 + Restart = mkDefault "always";
4113 + };
4114 + }
4115 + extraService
4116 + ])) extraServices)
4117 + ];
4118 +
4119 + systemd.timers = mapAttrs (timerName: timer:
4120 + {
4121 + description = "sourcehut timer for ${timerName}";
4122 + wantedBy = [ "timers.target" ];
4123 + inherit (timer) timerConfig;
4124 + }) extraTimers;
4125 + } ]);
4126 }
4127 - (builtins.removeAttrs attrs [ "path" "preStart" ])
4128 diff --git a/nixos/modules/services/misc/sourcehut/sourcehut.xml b/nixos/modules/services/misc/sourcehut/sourcehut.xml
4129 index ab9a8c6cb4b..41094f65a94 100644
4130 --- a/nixos/modules/services/misc/sourcehut/sourcehut.xml
4131 +++ b/nixos/modules/services/misc/sourcehut/sourcehut.xml
4132 @@ -14,13 +14,12 @@
4133 <title>Basic usage</title>
4134 <para>
4135 Sourcehut is a Python and Go based set of applications.
4136 - <literal><link linkend="opt-services.sourcehut.enable">services.sourcehut</link></literal>
4137 - by default will use
4138 + This NixOS module also provides basic configuration integrating Sourcehut into locally running
4139 <literal><link linkend="opt-services.nginx.enable">services.nginx</link></literal>,
4140 - <literal><link linkend="opt-services.nginx.enable">services.redis</link></literal>,
4141 - <literal><link linkend="opt-services.nginx.enable">services.cron</link></literal>,
4142 + <literal><link linkend="opt-services.redis.servers">services.redis.servers.sourcehut</link></literal>,
4143 + <literal><link linkend="opt-services.postfix.enable">services.postfix</link></literal>
4144 and
4145 - <literal><link linkend="opt-services.postgresql.enable">services.postgresql</link></literal>.
4146 + <literal><link linkend="opt-services.postgresql.enable">services.postgresql</link></literal> services.
4147 </para>
4148
4149 <para>
4150 @@ -42,18 +41,23 @@ in {
4151
4152 services.sourcehut = {
4153 <link linkend="opt-services.sourcehut.enable">enable</link> = true;
4154 - <link linkend="opt-services.sourcehut.originBase">originBase</link> = fqdn;
4155 - <link linkend="opt-services.sourcehut.services">services</link> = [ "meta" "man" "git" ];
4156 + <link linkend="opt-services.sourcehut.git.enable">git.enable</link> = true;
4157 + <link linkend="opt-services.sourcehut.man.enable">man.enable</link> = true;
4158 + <link linkend="opt-services.sourcehut.meta.enable">meta.enable</link> = true;
4159 + <link linkend="opt-services.sourcehut.nginx.enable">nginx.enable</link> = true;
4160 + <link linkend="opt-services.sourcehut.postfix.enable">postfix.enable</link> = true;
4161 + <link linkend="opt-services.sourcehut.postgresql.enable">postgresql.enable</link> = true;
4162 + <link linkend="opt-services.sourcehut.redis.enable">redis.enable</link> = true;
4163 <link linkend="opt-services.sourcehut.settings">settings</link> = {
4164 "sr.ht" = {
4165 environment = "production";
4166 global-domain = fqdn;
4167 origin = "https://${fqdn}";
4168 # Produce keys with srht-keygen from <package>sourcehut.coresrht</package>.
4169 - network-key = "SECRET";
4170 - service-key = "SECRET";
4171 + network-key = "/run/keys/path/to/network-key";
4172 + service-key = "/run/keys/path/to/service-key";
4173 };
4174 - webhooks.private-key= "SECRET";
4175 + webhooks.private-key= "/run/keys/path/to/webhook-key";
4176 };
4177 };
4178
4179 diff --git a/nixos/modules/services/misc/sourcehut/todo.nix b/nixos/modules/services/misc/sourcehut/todo.nix
4180 deleted file mode 100644
4181 index aec773b0669..00000000000
4182 --- a/nixos/modules/services/misc/sourcehut/todo.nix
4183 +++ /dev/null
4184 @@ -1,161 +0,0 @@
4185 -{ config, lib, pkgs, ... }:
4186 -
4187 -with lib;
4188 -let
4189 - cfg = config.services.sourcehut;
4190 - cfgIni = cfg.settings;
4191 - scfg = cfg.todo;
4192 - iniKey = "todo.sr.ht";
4193 -
4194 - rcfg = config.services.redis;
4195 - drv = pkgs.sourcehut.todosrht;
4196 -in
4197 -{
4198 - options.services.sourcehut.todo = {
4199 - user = mkOption {
4200 - type = types.str;
4201 - default = "todosrht";
4202 - description = ''
4203 - User for todo.sr.ht.
4204 - '';
4205 - };
4206 -
4207 - port = mkOption {
4208 - type = types.port;
4209 - default = 5003;
4210 - description = ''
4211 - Port on which the "todo" module should listen.
4212 - '';
4213 - };
4214 -
4215 - database = mkOption {
4216 - type = types.str;
4217 - default = "todo.sr.ht";
4218 - description = ''
4219 - PostgreSQL database name for todo.sr.ht.
4220 - '';
4221 - };
4222 -
4223 - statePath = mkOption {
4224 - type = types.path;
4225 - default = "${cfg.statePath}/todosrht";
4226 - description = ''
4227 - State path for todo.sr.ht.
4228 - '';
4229 - };
4230 - };
4231 -
4232 - config = with scfg; lib.mkIf (cfg.enable && elem "todo" cfg.services) {
4233 - users = {
4234 - users = {
4235 - "${user}" = {
4236 - isSystemUser = true;
4237 - group = user;
4238 - extraGroups = [ "postfix" ];
4239 - description = "todo.sr.ht user";
4240 - };
4241 - };
4242 - groups = {
4243 - "${user}" = { };
4244 - };
4245 - };
4246 -
4247 - services.postgresql = {
4248 - authentication = ''
4249 - local ${database} ${user} trust
4250 - '';
4251 - ensureDatabases = [ database ];
4252 - ensureUsers = [
4253 - {
4254 - name = user;
4255 - ensurePermissions = { "DATABASE \"${database}\"" = "ALL PRIVILEGES"; };
4256 - }
4257 - ];
4258 - };
4259 -
4260 - systemd = {
4261 - tmpfiles.rules = [
4262 - "d ${statePath} 0750 ${user} ${user} -"
4263 - ];
4264 -
4265 - services = {
4266 - todosrht = import ./service.nix { inherit config pkgs lib; } scfg drv iniKey {
4267 - after = [ "postgresql.service" "network.target" ];
4268 - requires = [ "postgresql.service" ];
4269 - wantedBy = [ "multi-user.target" ];
4270 -
4271 - description = "todo.sr.ht website service";
4272 -
4273 - serviceConfig.ExecStart = "${cfg.python}/bin/gunicorn ${drv.pname}.app:app -b ${cfg.address}:${toString port}";
4274 - };
4275 -
4276 - todosrht-lmtp = {
4277 - after = [ "postgresql.service" "network.target" ];
4278 - bindsTo = [ "postgresql.service" ];
4279 - wantedBy = [ "multi-user.target" ];
4280 -
4281 - description = "todo.sr.ht process service";
4282 - serviceConfig = {
4283 - Type = "simple";
4284 - User = user;
4285 - Restart = "always";
4286 - ExecStart = "${cfg.python}/bin/todosrht-lmtp";
4287 - };
4288 - };
4289 -
4290 - todosrht-webhooks = {
4291 - after = [ "postgresql.service" "network.target" ];
4292 - requires = [ "postgresql.service" ];
4293 - wantedBy = [ "multi-user.target" ];
4294 -
4295 - description = "todo.sr.ht webhooks service";
4296 - serviceConfig = {
4297 - Type = "simple";
4298 - User = user;
4299 - Restart = "always";
4300 - ExecStart = "${cfg.python}/bin/celery -A ${drv.pname}.webhooks worker --loglevel=info";
4301 - };
4302 -
4303 - };
4304 - };
4305 - };
4306 -
4307 - services.sourcehut.settings = {
4308 - # URL todo.sr.ht is being served at (protocol://domain)
4309 - "todo.sr.ht".origin = mkDefault "http://todo.${cfg.originBase}";
4310 - # Address and port to bind the debug server to
4311 - "todo.sr.ht".debug-host = mkDefault "0.0.0.0";
4312 - "todo.sr.ht".debug-port = mkDefault port;
4313 - # Configures the SQLAlchemy connection string for the database.
4314 - "todo.sr.ht".connection-string = mkDefault "postgresql:///${database}?user=${user}&host=/var/run/postgresql";
4315 - # Set to "yes" to automatically run migrations on package upgrade.
4316 - "todo.sr.ht".migrate-on-upgrade = mkDefault "yes";
4317 - # todo.sr.ht's OAuth client ID and secret for meta.sr.ht
4318 - # Register your client at meta.example.org/oauth
4319 - "todo.sr.ht".oauth-client-id = mkDefault null;
4320 - "todo.sr.ht".oauth-client-secret = mkDefault null;
4321 - # Outgoing email for notifications generated by users
4322 - "todo.sr.ht".notify-from = mkDefault "CHANGEME@example.org";
4323 - # The redis connection used for the webhooks worker
4324 - "todo.sr.ht".webhooks = mkDefault "redis://${rcfg.bind}:${toString rcfg.port}/1";
4325 - # Network-key
4326 - "todo.sr.ht".network-key = mkDefault null;
4327 -
4328 - # Path for the lmtp daemon's unix socket. Direct incoming mail to this socket.
4329 - # Alternatively, specify IP:PORT and an SMTP server will be run instead.
4330 - "todo.sr.ht::mail".sock = mkDefault "/tmp/todo.sr.ht-lmtp.sock";
4331 - # The lmtp daemon will make the unix socket group-read/write for users in this
4332 - # group.
4333 - "todo.sr.ht::mail".sock-group = mkDefault "postfix";
4334 -
4335 - "todo.sr.ht::mail".posting-domain = mkDefault "todo.${cfg.originBase}";
4336 - };
4337 -
4338 - services.nginx.virtualHosts."todo.${cfg.originBase}" = {
4339 - forceSSL = true;
4340 - locations."/".proxyPass = "http://${cfg.address}:${toString port}";
4341 - locations."/query".proxyPass = "http://${cfg.address}:${toString (port + 100)}";
4342 - locations."/static".root = "${pkgs.sourcehut.todosrht}/${pkgs.sourcehut.python.sitePackages}/todosrht";
4343 - };
4344 - };
4345 -}
4346 diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
4347 index a6eb2c03258..eb0238c0ca1 100644
4348 --- a/nixos/tests/all-tests.nix
4349 +++ b/nixos/tests/all-tests.nix
4350 @@ -412,6 +412,7 @@ in
4351 solanum = handleTest ./solanum.nix {};
4352 solr = handleTest ./solr.nix {};
4353 sonarr = handleTest ./sonarr.nix {};
4354 + sourcehut = handleTest ./sourcehut.nix {};
4355 spacecookie = handleTest ./spacecookie.nix {};
4356 spike = handleTest ./spike.nix {};
4357 sslh = handleTest ./sslh.nix {};
4358 diff --git a/nixos/tests/sourcehut.nix b/nixos/tests/sourcehut.nix
4359 index b56a14ebf85..6492250bd57 100644
4360 --- a/nixos/tests/sourcehut.nix
4361 +++ b/nixos/tests/sourcehut.nix
4362 @@ -12,10 +12,20 @@ import ./make-test-python.nix ({ pkgs, ... }:
4363 services.sourcehut = {
4364 enable = true;
4365 services = [ "meta" ];
4366 - originBase = "sourcehut";
4367 - settings."sr.ht".service-key = "8888888888888888888888888888888888888888888888888888888888888888";
4368 - settings."sr.ht".network-key = "0000000000000000000000000000000000000000000=";
4369 - settings.webhooks.private-key = "0000000000000000000000000000000000000000000=";
4370 + redis.enable = true;
4371 + postgresql.enable = true;
4372 + meta.enable = true;
4373 + settings."sr.ht" = {
4374 + global-domain = "sourcehut";
4375 + service-key = pkgs.writeText "service-key" "8b327279b77e32a3620e2fc9aabce491cc46e7d821fd6713b2a2e650ce114d01";
4376 + network-key = pkgs.writeText "network-key" "cEEmc30BRBGkgQZcHFksiG7hjc6_dK1XR2Oo5Jb9_nQ=";
4377 + };
4378 + settings.webhooks.private-key = pkgs.writeText "webhook-key" "Ra3IjxgFiwG9jxgp4WALQIZw/BMYt30xWiOsqD0J7EA=";
4379 + };
4380 + services.postgresql = {
4381 + enable = true;
4382 + enableTCPIP = false;
4383 + settings.unix_socket_permissions = "0770";
4384 };
4385 };
4386
4387 diff --git a/pkgs/applications/version-management/sourcehut/builds.nix b/pkgs/applications/version-management/sourcehut/builds.nix
4388 index c8163caf8ea..55d09ad0d34 100644
4389 --- a/pkgs/applications/version-management/sourcehut/builds.nix
4390 +++ b/pkgs/applications/version-management/sourcehut/builds.nix
4391 @@ -11,26 +11,54 @@
4392 , python
4393 }:
4394 let
4395 - version = "0.66.7";
4396 -
4397 - buildWorker = src: buildGoModule {
4398 - inherit src version;
4399 - pname = "builds-sr-ht-worker";
4400 -
4401 - vendorSha256 = "sha256-giOaldV46aBqXyFH/cQVsbUr6Rb4VMhbBO86o48tRZY=";
4402 - };
4403 -in
4404 -buildPythonPackage rec {
4405 - inherit version;
4406 - pname = "buildsrht";
4407 + version = "0.74.2";
4408
4409 src = fetchFromSourcehut {
4410 owner = "~sircmpwn";
4411 repo = "builds.sr.ht";
4412 rev = version;
4413 - sha256 = "sha256-2MLs/DOXHjEYarXDVUcPZe3o0fmZbzVxn528SE72lhM=";
4414 + sha256 = "sha256-vdVKaI42pA0dnyMXhQ4AEaDgTtKcrH6hc9L6PFcl6ZA=";
4415 };
4416
4417 + worker = buildGoModule {
4418 + inherit src version;
4419 + sourceRoot = "source/worker";
4420 + pname = "buildsrht-worker";
4421 +
4422 + vendorSha256 = "sha256-7zlt5305P3KzGrs4wUyAU1+FpoBMyl+yjkLSzqUybxg=";
4423 +
4424 + # What follows is only to update go-redis,
4425 + # and thus also using a patched srht-keys.
4426 + # go.{mod,sum} could be patched directly but that would be less resilient
4427 + # to changes from upstream, and thus harder to maintain the patching
4428 + # while it hasn't been merged upstream.
4429 +
4430 + overrideModAttrs = old: {
4431 + preBuild = ''
4432 + go get github.com/go-redis/redis/v8
4433 + go get github.com/go-redis/redis@none
4434 + go mod tidy
4435 + '';
4436 + # Pass updated go.{mod,sum} from go-modules to worker's vendor/go.{mod,sum}
4437 + postInstall = ''
4438 + cp --reflink=auto go.* $out/
4439 + '';
4440 + };
4441 +
4442 + patches = [
4443 + # Update go-redis to support Unix sockets
4444 + patches/redis-socket/build/v3-0001-worker-update-go-redis-to-support-Unix-sockets.patch
4445 + ];
4446 + patchFlags = ["-p2"];
4447 + postConfigure = ''
4448 + cp -v vendor/go.{mod,sum} .
4449 + '';
4450 + };
4451 +in
4452 +buildPythonPackage rec {
4453 + inherit src version;
4454 + pname = "buildsrht";
4455 +
4456 nativeBuildInputs = srht.nativeBuildInputs;
4457
4458 propagatedBuildInputs = [
4459 @@ -53,13 +81,17 @@ buildPythonPackage rec {
4460
4461 cp -r images $out/lib
4462 cp contrib/submit_image_build $out/bin/builds.sr.ht
4463 - cp ${buildWorker "${src}/worker"}/bin/worker $out/bin/builds.sr.ht-worker
4464 + cp ${worker}/bin/worker $out/bin/builds.sr.ht-worker
4465 '';
4466
4467 + pythonImportsCheck = [ "buildsrht" ];
4468 +
4469 + passthru = { inherit worker; };
4470 +
4471 meta = with lib; {
4472 homepage = "https://git.sr.ht/~sircmpwn/builds.sr.ht";
4473 description = "Continuous integration service for the sr.ht network";
4474 - license = licenses.agpl3;
4475 + license = licenses.agpl3Only;
4476 maintainers = with maintainers; [ eadwu ];
4477 };
4478 }
4479 diff --git a/pkgs/applications/version-management/sourcehut/core.nix b/pkgs/applications/version-management/sourcehut/core.nix
4480 index 7c3a516ed9d..7e7aca4df2d 100644
4481 --- a/pkgs/applications/version-management/sourcehut/core.nix
4482 +++ b/pkgs/applications/version-management/sourcehut/core.nix
4483 @@ -25,17 +25,16 @@
4484 , sassc
4485 , nodejs
4486 , redis
4487 -, writeText
4488 }:
4489
4490 buildPythonPackage rec {
4491 pname = "srht";
4492 - version = "0.67.4";
4493 + version = "0.68.2";
4494
4495 src = fetchgit {
4496 url = "https://git.sr.ht/~sircmpwn/core.sr.ht";
4497 rev = version;
4498 - sha256 = "sha256-XvzFfcBK5Mq8p7xEBAF/eupUE1kkUBh5k+ByM/WA9bc=";
4499 + sha256 = "sha256-vLdKJgi3arF5PSODbCSCX7fWGZfgkOirGSdYzcNXRdk=";
4500 fetchSubmodules = true;
4501 };
4502
4503 @@ -46,7 +45,10 @@ buildPythonPackage rec {
4504 };
4505
4506 patches = [
4507 - ./disable-npm-install.patch
4508 + # Disable check for npm
4509 + patches/disable-npm-install.patch
4510 + # Add Unix socket support for redis-host=
4511 + patches/redis-socket/core/v3-0001-add-Unix-socket-support-for-redis-host.patch
4512 ];
4513
4514 nativeBuildInputs = [
4515 @@ -87,6 +89,7 @@ buildPythonPackage rec {
4516 '';
4517
4518 dontUseSetuptoolsCheck = true;
4519 + pythonImportsCheck = [ "srht" ];
4520
4521 meta = with lib; {
4522 homepage = "https://git.sr.ht/~sircmpwn/srht";
4523 diff --git a/pkgs/applications/version-management/sourcehut/default.nix b/pkgs/applications/version-management/sourcehut/default.nix
4524 index 401a1437b7d..7dde841b543 100644
4525 --- a/pkgs/applications/version-management/sourcehut/default.nix
4526 +++ b/pkgs/applications/version-management/sourcehut/default.nix
4527 @@ -22,10 +22,12 @@ let
4528 listssrht = self.callPackage ./lists.nix { };
4529 mansrht = self.callPackage ./man.nix { };
4530 metasrht = self.callPackage ./meta.nix { };
4531 + pagessrht = self.callPackage ./pages.nix { };
4532 pastesrht = self.callPackage ./paste.nix { };
4533 todosrht = self.callPackage ./todo.nix { };
4534
4535 scmsrht = self.callPackage ./scm.nix { };
4536 + srht-keys = self.scmsrht.srht-keys;
4537 };
4538 };
4539 in
4540 @@ -40,6 +42,8 @@ with python.pkgs; recurseIntoAttrs {
4541 listssrht = toPythonApplication listssrht;
4542 mansrht = toPythonApplication mansrht;
4543 metasrht = toPythonApplication metasrht;
4544 + pagessrht = pagessrht;
4545 pastesrht = toPythonApplication pastesrht;
4546 todosrht = toPythonApplication todosrht;
4547 + srht-keys = scmsrht.srht-keys;
4548 }
4549 diff --git a/pkgs/applications/version-management/sourcehut/dispatch.nix b/pkgs/applications/version-management/sourcehut/dispatch.nix
4550 index 637c6f9c1df..9456d0c998c 100644
4551 --- a/pkgs/applications/version-management/sourcehut/dispatch.nix
4552 +++ b/pkgs/applications/version-management/sourcehut/dispatch.nix
4553 @@ -9,13 +9,13 @@
4554
4555 buildPythonPackage rec {
4556 pname = "dispatchsrht";
4557 - version = "0.15.8";
4558 + version = "0.15.32";
4559
4560 src = fetchFromSourcehut {
4561 owner = "~sircmpwn";
4562 repo = "dispatch.sr.ht";
4563 rev = version;
4564 - sha256 = "sha256-zWCGPjIgMKHXHJUs9aciV7IFgo0rpahon6KXHDwcfss=";
4565 + sha256 = "sha256-4P4cXhjcZ8IBzpRfmYIJkzl9U4Plo36a48Pf/KjmhFY=";
4566 };
4567
4568 nativeBuildInputs = srht.nativeBuildInputs;
4569 @@ -31,10 +31,12 @@ buildPythonPackage rec {
4570 export SRHT_PATH=${srht}/${python.sitePackages}/srht
4571 '';
4572
4573 + pythonImportsCheck = [ "dispatchsrht" ];
4574 +
4575 meta = with lib; {
4576 homepage = "https://dispatch.sr.ht/~sircmpwn/dispatch.sr.ht";
4577 description = "Task dispatcher and service integration tool for the sr.ht network";
4578 - license = licenses.agpl3;
4579 + license = licenses.agpl3Only;
4580 maintainers = with maintainers; [ eadwu ];
4581 };
4582 }
4583 diff --git a/pkgs/applications/version-management/sourcehut/git.nix b/pkgs/applications/version-management/sourcehut/git.nix
4584 index e44fb9cd6c6..21898faf857 100644
4585 --- a/pkgs/applications/version-management/sourcehut/git.nix
4586 +++ b/pkgs/applications/version-management/sourcehut/git.nix
4587 @@ -6,42 +6,109 @@
4588 , srht
4589 , pygit2
4590 , scmsrht
4591 +, srht-keys
4592 }:
4593 let
4594 - version = "0.72.8";
4595 + version = "0.73.6";
4596
4597 src = fetchFromSourcehut {
4598 owner = "~sircmpwn";
4599 repo = "git.sr.ht";
4600 rev = version;
4601 - sha256 = "sha256-AB2uzajO5PtcpJfbOOTfuDFM6is5K39v3AZJ1hShRNc=";
4602 + sha256 = "sha256-9WdeHXmyX5K/ldaE9AbSWTRlsrSDuKtm8QhthEHfmuU=";
4603 };
4604
4605 - buildShell = src: buildGoModule {
4606 + gitsrht-shell = buildGoModule {
4607 inherit src version;
4608 + sourceRoot = "source/gitsrht-shell";
4609 pname = "gitsrht-shell";
4610 vendorSha256 = "sha256-aqUFICp0C2reqb2p6JCPAUIRsxzSv0t9BHoNWrTYfqk=";
4611 };
4612
4613 - buildDispatcher = src: buildGoModule {
4614 + gitsrht-dispatch = buildGoModule {
4615 inherit src version;
4616 - pname = "gitsrht-dispatcher";
4617 + sourceRoot = "source/gitsrht-dispatch";
4618 + pname = "gitsrht-dispatch";
4619 vendorSha256 = "sha256-qWXPHo86s6iuRBhRMtmD5jxnAWKdrWHtA/iSUkdw89M=";
4620 + patches = [
4621 + # Add support for supplementary groups
4622 + patches/redis-socket/git/v3-0003-gitsrht-dispatch-add-support-for-supplementary-gr.patch
4623 + ];
4624 + patchFlags = ["-p2"];
4625 };
4626
4627 - buildKeys = src: buildGoModule {
4628 + gitsrht-keys = buildGoModule {
4629 inherit src version;
4630 + sourceRoot = "source/gitsrht-keys";
4631 pname = "gitsrht-keys";
4632 - vendorSha256 = "1d94cqy7x0q0agwg515xxsbl70b3qrzxbzsyjhn1pbyj532brn7f";
4633 + vendorSha256 = "sha256-SOI7wimFthY+BwsDtMuyqKS1hCaEa3R90Q0qaA9boyE=";
4634 +
4635 + # What follows is only to update go-redis,
4636 + # and thus also using a patched srht-keys.
4637 + # go.{mod,sum} could be patched directly but that would be less resilient
4638 + # to changes from upstream, and thus harder to maintain the patching
4639 + # while it hasn't been merged upstream.
4640 +
4641 + overrideModAttrs = _: {
4642 + preBuild = ''
4643 + # This is a fixed-output derivation so it is not allowed to reference other derivations,
4644 + # but here srht-keys will be copied to vendor/ by go mod vendor
4645 + ln -s ${srht-keys} srht-keys
4646 + go mod edit -replace git.sr.ht/~sircmpwn/scm.sr.ht/srht-keys=$PWD/srht-keys
4647 + go get github.com/go-redis/redis/v8
4648 + go get github.com/go-redis/redis@none
4649 + go mod tidy
4650 + '';
4651 + # Pass updated go.{mod,sum} from go-modules to gitsrht-keys' vendor/go.{mod,sum}
4652 + postInstall = ''
4653 + cp --reflink=auto go.* $out/
4654 + '';
4655 + };
4656 +
4657 + patches = [
4658 + # Update go-redis to support Unix sockets
4659 + patches/redis-socket/git/v3-0001-gitsrht-keys-update-go-redis-to-support-Unix-sock.patch
4660 + ];
4661 + patchFlags = ["-p2"];
4662 + postConfigure = ''
4663 + cp -v vendor/go.{mod,sum} .
4664 + '';
4665 };
4666
4667 - buildUpdateHook = src: buildGoModule {
4668 + gitsrht-update-hook = buildGoModule {
4669 inherit src version;
4670 + sourceRoot = "source/gitsrht-update-hook";
4671 pname = "gitsrht-update-hook";
4672 - vendorSha256 = "0fwzqpjv8x5y3w3bfjd0x0cvqjjak23m0zj88hf32jpw49xmjkih";
4673 - };
4674 + vendorSha256 = "sha256-L/tGwbBSwhtGhHcinCK/0lsp1ffXjiHXCmGgsY9s2Nc=";
4675
4676 - updateHook = buildUpdateHook "${src}/gitsrht-update-hook";
4677 + # What follows is only to update go-redis
4678 + # and thus also using a patched srht-keys.
4679 +
4680 + overrideModAttrs = old: {
4681 + preBuild = ''
4682 + # This is a fixed-output derivation so it is not allowed to reference other derivations,
4683 + # but here srht-keys will be copied to vendor/ by go mod vendor
4684 + ln -s ${srht-keys} srht-keys
4685 + go mod edit -replace git.sr.ht/~sircmpwn/scm.sr.ht/srht-keys=$PWD/srht-keys
4686 + go get github.com/go-redis/redis/v8
4687 + go get github.com/go-redis/redis@none
4688 + go mod tidy
4689 + '';
4690 + # Pass updated go.{mod,sum} from go-modules to gitsrht-keys' vendor/go.{mod,sum}
4691 + postInstall = ''
4692 + cp --reflink=auto go.* $out/
4693 + '';
4694 + };
4695 +
4696 + patches = [
4697 + # Update go-redis to support Unix sockets
4698 + patches/redis-socket/git/v3-0002-gitsrht-update-hook-update-go-redis-to-support-Un.patch
4699 + ];
4700 + patchFlags = ["-p2"];
4701 + postConfigure = ''
4702 + cp -v vendor/go.{mod,sum} .
4703 + '';
4704 + };
4705
4706 in
4707 buildPythonPackage rec {
4708 @@ -63,19 +130,21 @@ buildPythonPackage rec {
4709
4710 postInstall = ''
4711 mkdir -p $out/bin
4712 - cp ${buildShell "${src}/gitsrht-shell"}/bin/gitsrht-shell $out/bin/gitsrht-shell
4713 - cp ${buildDispatcher "${src}/gitsrht-dispatch"}/bin/gitsrht-dispatch $out/bin/gitsrht-dispatch
4714 - cp ${buildKeys "${src}/gitsrht-keys"}/bin/gitsrht-keys $out/bin/gitsrht-keys
4715 - cp ${updateHook}/bin/gitsrht-update-hook $out/bin/gitsrht-update-hook
4716 + cp ${gitsrht-shell}/bin/gitsrht-shell $out/bin/gitsrht-shell
4717 + cp ${gitsrht-dispatch}/bin/gitsrht-dispatch $out/bin/gitsrht-dispatch
4718 + cp ${gitsrht-keys}/bin/gitsrht-keys $out/bin/gitsrht-keys
4719 + cp ${gitsrht-update-hook}/bin/gitsrht-update-hook $out/bin/gitsrht-update-hook
4720 '';
4721 passthru = {
4722 - inherit updateHook;
4723 + inherit gitsrht-shell gitsrht-dispatch gitsrht-keys gitsrht-update-hook;
4724 };
4725
4726 + pythonImportsCheck = [ "gitsrht" ];
4727 +
4728 meta = with lib; {
4729 homepage = "https://git.sr.ht/~sircmpwn/git.sr.ht";
4730 description = "Git repository hosting service for the sr.ht network";
4731 - license = licenses.agpl3;
4732 + license = licenses.agpl3Only;
4733 maintainers = with maintainers; [ eadwu ];
4734 };
4735 }
4736 diff --git a/pkgs/applications/version-management/sourcehut/hg.nix b/pkgs/applications/version-management/sourcehut/hg.nix
4737 index cddb76cabf2..e13b27d4139 100644
4738 --- a/pkgs/applications/version-management/sourcehut/hg.nix
4739 +++ b/pkgs/applications/version-management/sourcehut/hg.nix
4740 @@ -10,12 +10,12 @@
4741
4742 buildPythonPackage rec {
4743 pname = "hgsrht";
4744 - version = "0.27.4";
4745 + version = "0.28.1";
4746
4747 src = fetchhg {
4748 url = "https://hg.sr.ht/~sircmpwn/hg.sr.ht";
4749 rev = version;
4750 - sha256 = "1c0qfi0gmbfngvds6917fy9ii2iglawn429757rh7b4bvzn7n6mr";
4751 + sha256 = "ERMPaCtExZebwV1BrjyE/gGK7p/Nvf7ia+ZBO472bdw=";
4752 };
4753
4754 nativeBuildInputs = srht.nativeBuildInputs;
4755 @@ -32,10 +32,12 @@ buildPythonPackage rec {
4756 export SRHT_PATH=${srht}/${python.sitePackages}/srht
4757 '';
4758
4759 + pythonImportsCheck = [ "hgsrht" ];
4760 +
4761 meta = with lib; {
4762 homepage = "https://git.sr.ht/~sircmpwn/hg.sr.ht";
4763 description = "Mercurial repository hosting service for the sr.ht network";
4764 - license = licenses.agpl3;
4765 + license = licenses.agpl3Only;
4766 maintainers = with maintainers; [ eadwu ];
4767 };
4768 }
4769 diff --git a/pkgs/applications/version-management/sourcehut/hub.nix b/pkgs/applications/version-management/sourcehut/hub.nix
4770 index 17cb3fe4b61..9c834246def 100644
4771 --- a/pkgs/applications/version-management/sourcehut/hub.nix
4772 +++ b/pkgs/applications/version-management/sourcehut/hub.nix
4773 @@ -6,13 +6,13 @@
4774
4775 buildPythonPackage rec {
4776 pname = "hubsrht";
4777 - version = "0.13.1";
4778 + version = "0.13.16";
4779
4780 src = fetchFromSourcehut {
4781 owner = "~sircmpwn";
4782 repo = "hub.sr.ht";
4783 rev = version;
4784 - sha256 = "sha256-Kqzy4mh5Nn1emzHBco/LVuXro/tW3NX+OYqdEwBSQ/U=";
4785 + sha256 = "sha256-TyeEJvkRjqTs92+pKloJhpTnnkYaMZHZkdO6Da5Bq7c=";
4786 };
4787
4788 nativeBuildInputs = srht.nativeBuildInputs;
4789 @@ -26,11 +26,12 @@ buildPythonPackage rec {
4790 '';
4791
4792 dontUseSetuptoolsCheck = true;
4793 + pythonImportsCheck = [ "hubsrht" ];
4794
4795 meta = with lib; {
4796 homepage = "https://git.sr.ht/~sircmpwn/hub.sr.ht";
4797 description = "Project hub service for the sr.ht network";
4798 - license = licenses.agpl3;
4799 + license = licenses.agpl3Only;
4800 maintainers = with maintainers; [ eadwu ];
4801 };
4802 }
4803 diff --git a/pkgs/applications/version-management/sourcehut/lists.nix b/pkgs/applications/version-management/sourcehut/lists.nix
4804 index b419b49f7b5..4ffc2ac9dee 100644
4805 --- a/pkgs/applications/version-management/sourcehut/lists.nix
4806 +++ b/pkgs/applications/version-management/sourcehut/lists.nix
4807 @@ -12,13 +12,13 @@
4808
4809 buildPythonPackage rec {
4810 pname = "listssrht";
4811 - version = "0.48.19";
4812 + version = "0.50.2";
4813
4814 src = fetchFromSourcehut {
4815 owner = "~sircmpwn";
4816 repo = "lists.sr.ht";
4817 rev = version;
4818 - sha256 = "sha256-bsakEMyvWaxiE4/SGcAP4mlGG9jkdHfFxpt9H+TJn/8=";
4819 + sha256 = "sha256-2NO6WJCOwCqGuICnn425NbnemTm8vYBltJyrveUt1n0=";
4820 };
4821
4822 nativeBuildInputs = srht.nativeBuildInputs;
4823 @@ -37,10 +37,12 @@ buildPythonPackage rec {
4824 export SRHT_PATH=${srht}/${python.sitePackages}/srht
4825 '';
4826
4827 + pythonImportsCheck = [ "listssrht" ];
4828 +
4829 meta = with lib; {
4830 homepage = "https://git.sr.ht/~sircmpwn/lists.sr.ht";
4831 description = "Mailing list service for the sr.ht network";
4832 - license = licenses.agpl3;
4833 + license = licenses.agpl3Only;
4834 maintainers = with maintainers; [ eadwu ];
4835 };
4836 }
4837 diff --git a/pkgs/applications/version-management/sourcehut/man.nix b/pkgs/applications/version-management/sourcehut/man.nix
4838 index bd331f000a7..2d4d152e3aa 100644
4839 --- a/pkgs/applications/version-management/sourcehut/man.nix
4840 +++ b/pkgs/applications/version-management/sourcehut/man.nix
4841 @@ -8,13 +8,13 @@
4842
4843 buildPythonPackage rec {
4844 pname = "mansrht";
4845 - version = "0.15.12";
4846 + version = "0.15.22";
4847
4848 src = fetchFromSourcehut {
4849 owner = "~sircmpwn";
4850 repo = "man.sr.ht";
4851 rev = version;
4852 - sha256 = "sha256-MqH/8K9XRvEg6P7GHE6XXtWnhDP3wT8iGoNaFtYQbio=";
4853 + sha256 = "sha256-curouf+eNCKprDI23blGs4AzJMry6zlCLDt/+0j5c8A=";
4854 };
4855
4856 nativeBuildInputs = srht.nativeBuildInputs;
4857 @@ -29,10 +29,12 @@ buildPythonPackage rec {
4858 export SRHT_PATH=${srht}/${python.sitePackages}/srht
4859 '';
4860
4861 + pythonImportsCheck = [ "mansrht" ];
4862 +
4863 meta = with lib; {
4864 homepage = "https://git.sr.ht/~sircmpwn/man.sr.ht";
4865 description = "Wiki service for the sr.ht network";
4866 - license = licenses.agpl3;
4867 + license = licenses.agpl3Only;
4868 maintainers = with maintainers; [ eadwu ];
4869 };
4870 }
4871 diff --git a/pkgs/applications/version-management/sourcehut/meta.nix b/pkgs/applications/version-management/sourcehut/meta.nix
4872 index 86d293973d7..96ea83a4ef3 100644
4873 --- a/pkgs/applications/version-management/sourcehut/meta.nix
4874 +++ b/pkgs/applications/version-management/sourcehut/meta.nix
4875 @@ -18,19 +18,19 @@
4876 , python
4877 }:
4878 let
4879 - version = "0.53.14";
4880 + version = "0.56.19";
4881
4882 src = fetchFromSourcehut {
4883 owner = "~sircmpwn";
4884 repo = "meta.sr.ht";
4885 rev = version;
4886 - sha256 = "sha256-/+r/XLDkcSTW647xPMh5bcJmR2xZNNH74AJ5jemna2k=";
4887 + sha256 = "sha256-YVj+aehO+2cJGvti9KXexm3y/0dx3rZBjEf0tKFC+s4=";
4888 };
4889
4890 buildApi = src: buildGoModule {
4891 inherit src version;
4892 pname = "metasrht-api";
4893 - vendorSha256 = "sha256-eZyDrr2VcNMxI++18qUy7LA1Q1YDlWCoRtl00L8lfR4=";
4894 + vendorSha256 = "sha256-j++Z+QXwCC7H3OK0sfWZrFluOVdN+b2tGCpLnmjKjc4=";
4895 };
4896
4897 in
4898 @@ -66,10 +66,12 @@ buildPythonPackage rec {
4899 cp ${buildApi "${src}/api/"}/bin/api $out/bin/metasrht-api
4900 '';
4901
4902 + pythonImportsCheck = [ "metasrht" ];
4903 +
4904 meta = with lib; {
4905 homepage = "https://git.sr.ht/~sircmpwn/meta.sr.ht";
4906 description = "Account management service for the sr.ht network";
4907 - license = licenses.agpl3;
4908 + license = licenses.agpl3Only;
4909 maintainers = with maintainers; [ eadwu ];
4910 };
4911 }
4912 diff --git a/pkgs/applications/version-management/sourcehut/pages.nix b/pkgs/applications/version-management/sourcehut/pages.nix
4913 new file mode 100644
4914 index 00000000000..c49e49c2664
4915 --- /dev/null
4916 +++ b/pkgs/applications/version-management/sourcehut/pages.nix
4917 @@ -0,0 +1,30 @@
4918 +{ lib
4919 +, fetchFromSourcehut
4920 +, buildGoModule
4921 +}:
4922 +
4923 +buildGoModule rec {
4924 + pname = "pagessrht";
4925 + version = "0.5.1";
4926 +
4927 + src = fetchFromSourcehut {
4928 + owner = "~sircmpwn";
4929 + repo = "pages.sr.ht";
4930 + rev = version;
4931 + sha256 = "sha256-Cab8zx+9WHHAB1rBoyZACq7lx9JdRBGzI1H+Yu9qHfs=";
4932 + };
4933 +
4934 + vendorSha256 = "sha256-udr+1y5ApQCSPhs3yQTTi9QfzRbz0A9COYuFMjQGa74=";
4935 +
4936 + postInstall = ''
4937 + mkdir -p $out/share/sql/
4938 + cp -r -t $out/share/sql/ schema.sql migrations
4939 + '';
4940 +
4941 + meta = with lib; {
4942 + homepage = "https://git.sr.ht/~sircmpwn/pages.sr.ht";
4943 + description = "Web hosting service for the sr.ht network";
4944 + license = licenses.agpl3Only;
4945 + maintainers = with maintainers; [ eadwu ];
4946 + };
4947 +}
4948 diff --git a/pkgs/applications/version-management/sourcehut/paste.nix b/pkgs/applications/version-management/sourcehut/paste.nix
4949 index 0d8c9135493..c411f8e8c95 100644
4950 --- a/pkgs/applications/version-management/sourcehut/paste.nix
4951 +++ b/pkgs/applications/version-management/sourcehut/paste.nix
4952 @@ -8,13 +8,13 @@
4953
4954 buildPythonPackage rec {
4955 pname = "pastesrht";
4956 - version = "0.12.1";
4957 + version = "0.13.6";
4958
4959 src = fetchFromSourcehut {
4960 owner = "~sircmpwn";
4961 repo = "paste.sr.ht";
4962 rev = version;
4963 - sha256 = "sha256-QQhd2LeH9BLmlHilhsv+9fZ+RPNmEMSmOpFA3dsMBFc=";
4964 + sha256 = "sha256-Khcqk86iD9nxiKXN3+8mSLNoDau2qXNFOrLdkVu+rH8=";
4965 };
4966
4967 nativeBuildInputs = srht.nativeBuildInputs;
4968 @@ -29,10 +29,12 @@ buildPythonPackage rec {
4969 export SRHT_PATH=${srht}/${python.sitePackages}/srht
4970 '';
4971
4972 + pythonImportsCheck = [ "pastesrht" ];
4973 +
4974 meta = with lib; {
4975 homepage = "https://git.sr.ht/~sircmpwn/paste.sr.ht";
4976 description = "Ad-hoc text file hosting service for the sr.ht network";
4977 - license = licenses.agpl3;
4978 + license = licenses.agpl3Only;
4979 maintainers = with maintainers; [ eadwu ];
4980 };
4981 }
4982 diff --git a/pkgs/applications/version-management/sourcehut/disable-npm-install.patch b/pkgs/applications/version-management/sourcehut/patches/disable-npm-install.patch
4983 similarity index 100%
4984 rename from pkgs/applications/version-management/sourcehut/disable-npm-install.patch
4985 rename to pkgs/applications/version-management/sourcehut/patches/disable-npm-install.patch
4986 diff --git a/pkgs/applications/version-management/sourcehut/patches/redis-socket/build/v3-0001-worker-update-go-redis-to-support-Unix-sockets.patch b/pkgs/applications/version-management/sourcehut/patches/redis-socket/build/v3-0001-worker-update-go-redis-to-support-Unix-sockets.patch
4987 new file mode 100644
4988 index 00000000000..4efd12be875
4989 --- /dev/null
4990 +++ b/pkgs/applications/version-management/sourcehut/patches/redis-socket/build/v3-0001-worker-update-go-redis-to-support-Unix-sockets.patch
4991 @@ -0,0 +1,113 @@
4992 +From 5991960a5d412f0e1bdc505b970248c68b44a720 Mon Sep 17 00:00:00 2001
4993 +From: Julien Moutinho <julm+srht@sourcephile.fr>
4994 +Date: Wed, 15 Sep 2021 19:45:41 +0200
4995 +Subject: [PATCH builds.sr.ht v3 1/2] worker: update go-redis to support Unix
4996 + sockets
4997 +
4998 +---
4999 + worker/context.go | 4 ++--
5000 + worker/main.go | 11 +++++++----
5001 + worker/tasks.go | 10 +++++-----
5002 + 3 files changed, 14 insertions(+), 11 deletions(-)
5003 +
5004 +diff --git a/worker/context.go b/worker/context.go
5005 +index f84a60c..be54717 100644
5006 +--- a/worker/context.go
5007 ++++ b/worker/context.go
5008 +@@ -14,7 +14,7 @@ import (
5009 + "strings"
5010 + "time"
5011 +
5012 +- "github.com/go-redis/redis"
5013 ++ goredis "github.com/go-redis/redis/v8"
5014 + "github.com/google/shlex"
5015 + "github.com/pkg/errors"
5016 + "github.com/prometheus/client_golang/prometheus"
5017 +@@ -41,7 +41,7 @@ var (
5018 +
5019 + type WorkerContext struct {
5020 + Db *sql.DB
5021 +- Redis *redis.Client
5022 ++ Redis *goredis.Client
5023 + Conf func(section, key string) string
5024 + }
5025 +
5026 +diff --git a/worker/main.go b/worker/main.go
5027 +index 274ba68..e22ab6b 100644
5028 +--- a/worker/main.go
5029 ++++ b/worker/main.go
5030 +@@ -1,6 +1,7 @@
5031 + package main
5032 +
5033 + import (
5034 ++ "context"
5035 + "database/sql"
5036 + "flag"
5037 + "log"
5038 +@@ -9,7 +10,7 @@ import (
5039 + "runtime"
5040 + "sync"
5041 +
5042 +- "github.com/go-redis/redis"
5043 ++ goredis "github.com/go-redis/redis/v8"
5044 + "github.com/vaughan0/go-ini"
5045 + "git.sr.ht/~sircmpwn/core-go/crypto"
5046 +
5047 +@@ -26,6 +27,8 @@ var (
5048 + jobsMutex sync.Mutex
5049 + )
5050 +
5051 ++var redisctx = context.Background()
5052 ++
5053 + func main() {
5054 + flag.IntVar(&workers, "workers", runtime.NumCPU(),
5055 + "configure number of workers")
5056 +@@ -68,12 +71,12 @@ func main() {
5057 + if !ok {
5058 + redisHost = "redis://localhost:6379"
5059 + }
5060 +- ropts, err := redis.ParseURL(redisHost)
5061 ++ ropts, err := goredis.ParseURL(redisHost)
5062 + if err != nil {
5063 + panic(err)
5064 + }
5065 +- localRedis := redis.NewClient(ropts)
5066 +- if _, err := localRedis.Ping().Result(); err != nil {
5067 ++ localRedis := goredis.NewClient(ropts)
5068 ++ if _, err := localRedis.Ping(redisctx).Result(); err != nil {
5069 + panic(err)
5070 + }
5071 +
5072 +diff --git a/worker/tasks.go b/worker/tasks.go
5073 +index d27bf33..d0c28f1 100644
5074 +--- a/worker/tasks.go
5075 ++++ b/worker/tasks.go
5076 +@@ -19,7 +19,7 @@ import (
5077 + "time"
5078 +
5079 + "git.sr.ht/~sircmpwn/core-go/auth"
5080 +- "github.com/go-redis/redis"
5081 ++ goredis "github.com/go-redis/redis/v8"
5082 + "github.com/kr/pty"
5083 + "github.com/minio/minio-go/v6"
5084 + "github.com/pkg/errors"
5085 +@@ -39,12 +39,12 @@ var (
5086 + }, []string{"image", "arch"})
5087 + )
5088 +
5089 +-func (ctx *JobContext) Boot(r *redis.Client) func() {
5090 +- port, err := r.Incr("builds.sr.ht.ssh-port").Result()
5091 ++func (ctx *JobContext) Boot(r *goredis.Client) func() {
5092 ++ port, err := r.Incr(ctx.Context, "builds.sr.ht.ssh-port").Result()
5093 + if err == nil && port < 22000 {
5094 +- err = r.Set("builds.sr.ht.ssh-port", 22100, 0).Err()
5095 ++ err = r.Set(ctx.Context, "builds.sr.ht.ssh-port", 22100, 0).Err()
5096 + } else if err == nil && port >= 23000 {
5097 +- err = r.Set("builds.sr.ht.ssh-port", 22000, 0).Err()
5098 ++ err = r.Set(ctx.Context, "builds.sr.ht.ssh-port", 22000, 0).Err()
5099 + }
5100 + if err != nil {
5101 + panic(errors.Wrap(err, "assign port"))
5102 +--
5103 +2.32.0
5104 +
5105 diff --git a/pkgs/applications/version-management/sourcehut/patches/redis-socket/build/v3-0002-worker-update-go.-mod-sum-for-go-redis.patch b/pkgs/applications/version-management/sourcehut/patches/redis-socket/build/v3-0002-worker-update-go.-mod-sum-for-go-redis.patch
5106 new file mode 100644
5107 index 00000000000..c9368d05c18
5108 --- /dev/null
5109 +++ b/pkgs/applications/version-management/sourcehut/patches/redis-socket/build/v3-0002-worker-update-go.-mod-sum-for-go-redis.patch
5110 @@ -0,0 +1,378 @@
5111 +From eac18e913e4ee48895b94acfa56cf1c6a3fb49fa Mon Sep 17 00:00:00 2001
5112 +From: Julien Moutinho <julm+srht@sourcephile.fr>
5113 +Date: Wed, 15 Sep 2021 20:11:49 +0200
5114 +Subject: [PATCH builds.sr.ht v3 2/2] worker: update go.{mod,sum} for go-redis
5115 +
5116 +---
5117 + worker/go.mod | 8 +------
5118 + worker/go.sum | 64 +++++++++++++++++++--------------------------------
5119 + 2 files changed, 25 insertions(+), 47 deletions(-)
5120 +
5121 +diff --git a/worker/go.mod b/worker/go.mod
5122 +index 6e9a11c..4893dfa 100644
5123 +--- a/worker/go.mod
5124 ++++ b/worker/go.mod
5125 +@@ -2,24 +2,18 @@ module git.sr.ht/~sircmpwn/builds.sr.ht/worker
5126 +
5127 + require (
5128 + git.sr.ht/~sircmpwn/core-go v0.0.0-20210108160653-070566136c1a
5129 +- github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df
5130 +- github.com/go-redis/redis v6.15.2+incompatible
5131 ++ github.com/go-redis/redis/v8 v8.2.3
5132 + github.com/gocelery/gocelery v0.0.0-20201111034804-825d89059344
5133 +- github.com/gomodule/redigo v2.0.0+incompatible // indirect
5134 + github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
5135 +- github.com/jpillora/longestcommon v0.0.0-20161227235612-adb9d91ee629
5136 + github.com/kr/pty v1.1.3
5137 + github.com/lib/pq v1.8.0
5138 + github.com/martinlindhe/base36 v1.1.0
5139 +- github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
5140 + github.com/minio/minio-go/v6 v6.0.49
5141 + github.com/mitchellh/mapstructure v1.1.2
5142 + github.com/pkg/errors v0.9.1
5143 + github.com/prometheus/client_golang v1.7.1
5144 +- github.com/shicky/gocelery v0.0.0-20180807061531-b2f0dd7ec05b
5145 + github.com/streadway/amqp v1.0.0 // indirect
5146 + github.com/vaughan0/go-ini v0.0.0-20130923145212-a98ad7ee00ec
5147 +- golang.org/x/sys v0.0.0-20201013132646-2da7054afaeb
5148 + gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
5149 + gopkg.in/mail.v2 v2.3.1
5150 + gopkg.in/yaml.v2 v2.3.0
5151 +diff --git a/worker/go.sum b/worker/go.sum
5152 +index 1cd3989..4a2d6d9 100644
5153 +--- a/worker/go.sum
5154 ++++ b/worker/go.sum
5155 +@@ -10,6 +10,7 @@ git.sr.ht/~sircmpwn/go-bare v0.0.0-20200812160916-d2c72e1a5018/go.mod h1:BVJwbDf
5156 + github.com/99designs/gqlgen v0.13.0 h1:haLTcUp3Vwp80xMVEg5KRNwzfUrgFdRmtBY8fuB8scA=
5157 + github.com/99designs/gqlgen v0.13.0/go.mod h1:NV130r6f4tpRWuAI+zsrSdooO/eWUv+Gyyoi3rEfXIk=
5158 + github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
5159 ++github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
5160 + github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
5161 + github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
5162 + github.com/Masterminds/squirrel v1.4.0 h1:he5i/EXixZxrBUWcxzDYMiju9WZ3ld/l7QBNuo/eN3w=
5163 +@@ -25,6 +26,7 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
5164 + github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
5165 + github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
5166 + github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
5167 ++github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
5168 + github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
5169 + github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
5170 + github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
5171 +@@ -36,7 +38,6 @@ github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6l
5172 + github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
5173 + github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
5174 + github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
5175 +-github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
5176 + github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
5177 + github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
5178 + github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
5179 +@@ -58,8 +59,10 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma
5180 + github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
5181 + github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
5182 + github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5183 ++github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
5184 + github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5185 + github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
5186 ++github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
5187 + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
5188 + github.com/dgryski/trifles v0.0.0-20190318185328-a8d75aae118c/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
5189 + github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
5190 +@@ -84,22 +87,18 @@ github.com/fernet/fernet-go v0.0.0-20191111064656-eff2850e6001/go.mod h1:2H9hjfb
5191 + github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
5192 + github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
5193 + github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
5194 ++github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
5195 + github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
5196 + github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
5197 + github.com/go-chi/chi v3.3.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
5198 + github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
5199 +-github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df h1:Bao6dhmbTA1KFVxmJ6nBoMuOJit2yjEgLJpIMYpop0E=
5200 +-github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df/go.mod h1:GJr+FCSXshIwgHBtLglIg9M2l2kQSi6QjVAngtzI08Y=
5201 + github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
5202 + github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
5203 + github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
5204 + github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
5205 + github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
5206 + github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
5207 +-github.com/go-redis/redis v6.14.1+incompatible h1:kSJohAREGMr344uMa8PzuIg5OU6ylCbyDkWkkNOfEik=
5208 +-github.com/go-redis/redis v6.14.1+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
5209 +-github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDAhzyXg+Bs+0Sb4=
5210 +-github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
5211 ++github.com/go-redis/redis/v8 v8.2.3 h1:eNesND+DWt/sjQOtPFxAbQkTIXaXX00qNLxjVWkZ70k=
5212 + github.com/go-redis/redis/v8 v8.2.3/go.mod h1:ysgGY09J/QeDYbu3HikWEIPCwaeOkuNoTgKayTEaEOw=
5213 + github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
5214 + github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
5215 +@@ -114,7 +113,6 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU
5216 + github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
5217 + github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
5218 + github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
5219 +-github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
5220 + github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
5221 + github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
5222 + github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
5223 +@@ -136,12 +134,14 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
5224 + github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
5225 + github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
5226 + github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
5227 ++github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k=
5228 + github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
5229 + github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
5230 + github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
5231 + github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
5232 + github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
5233 + github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
5234 ++github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
5235 + github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
5236 + github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
5237 + github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
5238 +@@ -180,12 +180,11 @@ github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod
5239 + github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
5240 + github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
5241 + github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
5242 +-github.com/jpillora/longestcommon v0.0.0-20161227235612-adb9d91ee629 h1:1dSBUfGlorLAua2CRx0zFN7kQsTpE2DQSmr7rrTNgY8=
5243 +-github.com/jpillora/longestcommon v0.0.0-20161227235612-adb9d91ee629/go.mod h1:mb5nS4uRANwOJSZj8rlCWAfAcGi72GGMIXx+xGOjA7M=
5244 + github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
5245 + github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
5246 + github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
5247 + github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
5248 ++github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
5249 + github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
5250 + github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
5251 + github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
5252 +@@ -200,20 +199,18 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
5253 + github.com/kr/pty v1.1.3 h1:/Um6a/ZmD5tF7peoOJ5oN5KMQ0DrGVQSXLNwyckutPk=
5254 + github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
5255 + github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
5256 ++github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
5257 + github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
5258 + github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw=
5259 + github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o=
5260 + github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk=
5261 + github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw=
5262 +-github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
5263 +-github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
5264 + github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg=
5265 + github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
5266 + github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
5267 + github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
5268 + github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
5269 + github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
5270 +-github.com/martinlindhe/base36 v1.0.0 h1:eYsumTah144C0A8P1T/AVSUk5ZoLnhfYFM3OGQxB52A=
5271 + github.com/martinlindhe/base36 v1.0.0/go.mod h1:+AtEs8xrBpCeYgSLoY/aJ6Wf37jtBuR0s35750M27+8=
5272 + github.com/martinlindhe/base36 v1.1.0 h1:cIwvvwYse/0+1CkUPYH5ZvVIYG3JrILmQEIbLuar02Y=
5273 + github.com/martinlindhe/base36 v1.1.0/go.mod h1:+AtEs8xrBpCeYgSLoY/aJ6Wf37jtBuR0s35750M27+8=
5274 +@@ -228,7 +225,6 @@ github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp
5275 + github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
5276 + github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
5277 + github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
5278 +-github.com/minio/minio-go v6.0.14+incompatible h1:fnV+GD28LeqdN6vT2XdGKW8Qe/IfjJDswNVuni6km9o=
5279 + github.com/minio/minio-go/v6 v6.0.49 h1:bU4kIa/qChTLC1jrWZ8F+8gOiw1MClubddAJVR4gW3w=
5280 + github.com/minio/minio-go/v6 v6.0.49/go.mod h1:qD0lajrGW49lKZLtXKtCB4X/qkMf0a5tBvN2PaZg7Gg=
5281 + github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=
5282 +@@ -242,8 +238,6 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4
5283 + github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
5284 + github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
5285 + github.com/mitchellh/mapstructure v0.0.0-20180203102830-a4e142e9c047/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
5286 +-github.com/mitchellh/mapstructure v1.0.0 h1:vVpGvMXJPqSDh2VYHF7gsfQj8Ncx+Xw5Y1KHeTRY+7I=
5287 +-github.com/mitchellh/mapstructure v1.0.0/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
5288 + github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
5289 + github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
5290 + github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
5291 +@@ -259,7 +253,9 @@ github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzE
5292 + github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
5293 + github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
5294 + github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
5295 ++github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
5296 + github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
5297 ++github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
5298 + github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
5299 + github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
5300 + github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
5301 +@@ -267,10 +263,12 @@ github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:v
5302 + github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
5303 + github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
5304 + github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
5305 ++github.com/onsi/ginkgo v1.14.1 h1:jMU0WaQrP0a/YAEq8eJmJKjBoMs+pClEr1vDMlM/Do4=
5306 + github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
5307 + github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
5308 + github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
5309 + github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
5310 ++github.com/onsi/gomega v1.10.2 h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs=
5311 + github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
5312 + github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
5313 + github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
5314 +@@ -287,22 +285,20 @@ github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtP
5315 + github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
5316 + github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
5317 + github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
5318 +-github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
5319 + github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
5320 + github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
5321 + github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
5322 + github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
5323 + github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
5324 ++github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
5325 + github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
5326 + github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
5327 +-github.com/prometheus/client_golang v0.9.1 h1:K47Rk0v/fkEfwfQet2KWhscE0cJzjgCCDBG2KHZoVno=
5328 + github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
5329 + github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
5330 + github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
5331 + github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
5332 + github.com/prometheus/client_golang v1.7.1 h1:NTGy1Ja9pByO+xAeH/qiWnLrKtr3hJPNjaVUwnjpdpA=
5333 + github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
5334 +-github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8=
5335 + github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
5336 + github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
5337 + github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
5338 +@@ -310,15 +306,12 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:
5339 + github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
5340 + github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
5341 + github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
5342 +-github.com/prometheus/common v0.0.0-20181020173914-7e9e6cabbd39 h1:Cto4X6SVMWRPBkJ/3YHn1iDGDGc/Z+sW+AEMKHMVvN4=
5343 +-github.com/prometheus/common v0.0.0-20181020173914-7e9e6cabbd39/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
5344 + github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
5345 + github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
5346 + github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
5347 + github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
5348 + github.com/prometheus/common v0.14.0 h1:RHRyE8UocrbjU+6UvRzwi6HjiDfxrrBU91TtbKzkGp4=
5349 + github.com/prometheus/common v0.14.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
5350 +-github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d h1:GoAlyOgbOEIFdaDqxJVlbOQ1DtGmZWs/Qau0hIlk+WQ=
5351 + github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
5352 + github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
5353 + github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
5354 +@@ -333,36 +326,28 @@ github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
5355 + github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
5356 + github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
5357 + github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
5358 +-github.com/satori/go.uuid v1.1.0 h1:B9KXyj+GzIpJbV7gmr873NsY6zpbxNy24CBtGrk7jHo=
5359 +-github.com/satori/go.uuid v1.1.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
5360 +-github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
5361 +-github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
5362 +-github.com/satori/go.uuid v1.2.1-0.20180103174451-36e9d2ebbde5 h1:Jw7W4WMfQDxsXvfeFSaS2cHlY7bAF4MGrgnbd0+Uo78=
5363 +-github.com/satori/go.uuid v1.2.1-0.20180103174451-36e9d2ebbde5/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
5364 + github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b h1:gQZ0qzfKHQIybLANtM3mBXNUtOfsCFXeTsnBqCsx1KM=
5365 + github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
5366 + github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
5367 + github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
5368 ++github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
5369 + github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
5370 +-github.com/shicky/gocelery v0.0.0-20180807061531-b2f0dd7ec05b h1:7kJLeBNcPG1orS3ksAFN0qoJGtf8jvwgOh5Q+bsNZvc=
5371 +-github.com/shicky/gocelery v0.0.0-20180807061531-b2f0dd7ec05b/go.mod h1:kn4CkFIzvsrXBvbNk2hX9DpIM8xo/74mYhiYTpGhYXE=
5372 + github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
5373 + github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
5374 + github.com/shurcooL/vfsgen v0.0.0-20180121065927-ffb13db8def0/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
5375 + github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
5376 + github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
5377 + github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
5378 ++github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
5379 + github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
5380 + github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
5381 ++github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
5382 + github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
5383 + github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
5384 + github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
5385 + github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
5386 + github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
5387 +-github.com/streadway/amqp v0.0.0-20180806233856-70e15c650864 h1:Oj3PUEs+OUSYUpn35O+BE/ivHGirKixA3+vqA0Atu9A=
5388 +-github.com/streadway/amqp v0.0.0-20180806233856-70e15c650864/go.mod h1:1WNBiOZtZQLpVAyu0iTduoJL9hEsMloAK5XWrtW0xdY=
5389 + github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
5390 +-github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271 h1:WhxRHzgeVGETMlmVfqhRn8RIeeNoPr2Czh33I4Zdccw=
5391 + github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
5392 + github.com/streadway/amqp v1.0.0 h1:kuuDrUJFZL1QYL9hUNuCxNObNzB0bV/ZG5jV3RWAQgo=
5393 + github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
5394 +@@ -373,6 +358,7 @@ github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
5395 + github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
5396 + github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
5397 + github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
5398 ++github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
5399 + github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
5400 + github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
5401 + github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
5402 +@@ -391,6 +377,7 @@ go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mI
5403 + go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
5404 + go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
5405 + go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
5406 ++go.opentelemetry.io/otel v0.11.0 h1:IN2tzQa9Gc4ZVKnTaMbPVcHjvzOdg5n9QfnmlqiET7E=
5407 + go.opentelemetry.io/otel v0.11.0/go.mod h1:G8UCk+KooF2HLkgo8RHX9epABH/aRGYET7gQOqBVdB0=
5408 + go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
5409 + go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
5410 +@@ -403,7 +390,6 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf
5411 + golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
5412 + golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
5413 + golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
5414 +-golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f h1:R423Cnkcp5JABoeemiGEPlt9tHXFfw5kvc0yqlxRPWo=
5415 + golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
5416 + golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
5417 + golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
5418 +@@ -431,7 +417,6 @@ golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73r
5419 + golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
5420 + golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
5421 + golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
5422 +-golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco=
5423 + golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
5424 + golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
5425 + golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
5426 +@@ -451,7 +436,6 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
5427 + golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
5428 + golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
5429 + golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
5430 +-golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs=
5431 + golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
5432 + golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
5433 + golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
5434 +@@ -460,7 +444,6 @@ golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5h
5435 + golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
5436 + golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
5437 + golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
5438 +-golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
5439 + golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
5440 + golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
5441 + golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
5442 +@@ -477,7 +460,6 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w
5443 + golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
5444 + golang.org/x/sys v0.0.0-20201013132646-2da7054afaeb h1:HS9IzC4UFbpMBLQUDSQcU+ViVT1vdFCQVjdPVpTlZrs=
5445 + golang.org/x/sys v0.0.0-20201013132646-2da7054afaeb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
5446 +-golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
5447 + golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
5448 + golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
5449 + golang.org/x/text v0.3.4-0.20201021145329-22f1617af38e h1:0kyKOEC0chG7FKmnf/1uNwvDLc3NtNTRip2rXAN9nwI=
5450 +@@ -502,6 +484,7 @@ golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapK
5451 + golang.org/x/tools v0.0.0-20200114235610-7ae403b6b589/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
5452 + golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
5453 + golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
5454 ++golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
5455 + golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
5456 + google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
5457 + google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
5458 +@@ -539,6 +522,7 @@ gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod
5459 + gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
5460 + gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
5461 + gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
5462 ++gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
5463 + gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
5464 + gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
5465 + gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
5466 +@@ -549,6 +533,7 @@ gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
5467 + gopkg.in/mail.v2 v2.3.1 h1:WYFn/oANrAGP2C0dcV6/pbkPzv8yGzqTjPmTeO7qoXk=
5468 + gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw=
5469 + gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
5470 ++gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
5471 + gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
5472 + gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
5473 + gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
5474 +@@ -556,10 +541,9 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
5475 + gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
5476 + gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
5477 + gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
5478 +-gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
5479 +-gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
5480 + gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
5481 + gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
5482 ++gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
5483 + gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
5484 + honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
5485 + honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
5486 +--
5487 +2.32.0
5488 +
5489 diff --git a/pkgs/applications/version-management/sourcehut/patches/redis-socket/core/v3-0001-add-Unix-socket-support-for-redis-host.patch b/pkgs/applications/version-management/sourcehut/patches/redis-socket/core/v3-0001-add-Unix-socket-support-for-redis-host.patch
5490 new file mode 100644
5491 index 00000000000..299ad3d83c5
5492 --- /dev/null
5493 +++ b/pkgs/applications/version-management/sourcehut/patches/redis-socket/core/v3-0001-add-Unix-socket-support-for-redis-host.patch
5494 @@ -0,0 +1,30 @@
5495 +From c0ccc8db051a2f8278edf59b41ed238fa71aa4c0 Mon Sep 17 00:00:00 2001
5496 +From: Julien Moutinho <julm+srht@sourcephile.fr>
5497 +Date: Mon, 23 Aug 2021 18:43:18 +0200
5498 +Subject: [PATCH core.sr.ht v3] add Unix socket support for redis-host=
5499 +
5500 +---
5501 + srht/redis.py | 11 ++---------
5502 + 1 file changed, 2 insertions(+), 9 deletions(-)
5503 +
5504 +diff --git a/srht/redis.py b/srht/redis.py
5505 +index 8a9347c..2e91c35 100644
5506 +--- a/srht/redis.py
5507 ++++ b/srht/redis.py
5508 +@@ -1,11 +1,4 @@
5509 +-from redis import Redis
5510 ++from redis import from_url
5511 + from srht.config import cfg
5512 +-from urllib.parse import urlparse
5513 +
5514 +-url = cfg("sr.ht", "redis-host", "redis://localhost")
5515 +-url = urlparse(url)
5516 +-
5517 +-redis = Redis(host=url.hostname,
5518 +- port=(url.port or 6379),
5519 +- password=url.password,
5520 +- db=int(url.path[1:]) if url.path else 0)
5521 ++redis = from_url(cfg("sr.ht", "redis-host", "redis://localhost"))
5522 +--
5523 +2.32.0
5524 +
5525 diff --git a/pkgs/applications/version-management/sourcehut/patches/redis-socket/git/v3-0001-gitsrht-keys-update-go-redis-to-support-Unix-sock.patch b/pkgs/applications/version-management/sourcehut/patches/redis-socket/git/v3-0001-gitsrht-keys-update-go-redis-to-support-Unix-sock.patch
5526 new file mode 100644
5527 index 00000000000..48e91ac739b
5528 --- /dev/null
5529 +++ b/pkgs/applications/version-management/sourcehut/patches/redis-socket/git/v3-0001-gitsrht-keys-update-go-redis-to-support-Unix-sock.patch
5530 @@ -0,0 +1,26 @@
5531 +From 083e4791771d998c9a6c881a4101d24296e38252 Mon Sep 17 00:00:00 2001
5532 +From: Julien Moutinho <julm+srht@sourcephile.fr>
5533 +Date: Fri, 27 Aug 2021 15:38:28 +0200
5534 +Subject: [PATCH git.sr.ht v3 1/3] gitsrht-keys: update go-redis to support
5535 + Unix sockets
5536 +
5537 +---
5538 + gitsrht-keys/main.go | 2 +-
5539 + 1 file changed, 1 insertion(+), 1 deletion(-)
5540 +
5541 +diff --git a/gitsrht-keys/main.go b/gitsrht-keys/main.go
5542 +index 0c1aea1..fa17183 100644
5543 +--- a/gitsrht-keys/main.go
5544 ++++ b/gitsrht-keys/main.go
5545 +@@ -5,7 +5,7 @@ import (
5546 + "os"
5547 + "path"
5548 +
5549 +- goredis "github.com/go-redis/redis"
5550 ++ goredis "github.com/go-redis/redis/v8"
5551 + "github.com/vaughan0/go-ini"
5552 + "git.sr.ht/~sircmpwn/scm.sr.ht/srht-keys"
5553 + )
5554 +--
5555 +2.32.0
5556 +
5557 diff --git a/pkgs/applications/version-management/sourcehut/patches/redis-socket/git/v3-0002-gitsrht-update-hook-update-go-redis-to-support-Un.patch b/pkgs/applications/version-management/sourcehut/patches/redis-socket/git/v3-0002-gitsrht-update-hook-update-go-redis-to-support-Un.patch
5558 new file mode 100644
5559 index 00000000000..41847ac8717
5560 --- /dev/null
5561 +++ b/pkgs/applications/version-management/sourcehut/patches/redis-socket/git/v3-0002-gitsrht-update-hook-update-go-redis-to-support-Un.patch
5562 @@ -0,0 +1,109 @@
5563 +From d9683aced0dc3a94c56de2fde31c1765054900fa Mon Sep 17 00:00:00 2001
5564 +From: Julien Moutinho <julm+srht@sourcephile.fr>
5565 +Date: Fri, 27 Aug 2021 15:39:29 +0200
5566 +Subject: [PATCH git.sr.ht v3 2/3] gitsrht-update-hook: update go-redis to
5567 + support Unix sockets
5568 +
5569 +---
5570 + gitsrht-update-hook/options.go | 12 +++++++-----
5571 + gitsrht-update-hook/post-update.go | 4 ++--
5572 + gitsrht-update-hook/update.go | 4 ++--
5573 + 3 files changed, 11 insertions(+), 9 deletions(-)
5574 +
5575 +diff --git a/gitsrht-update-hook/options.go b/gitsrht-update-hook/options.go
5576 +index 8efbb0a..962502a 100644
5577 +--- a/gitsrht-update-hook/options.go
5578 ++++ b/gitsrht-update-hook/options.go
5579 +@@ -1,15 +1,17 @@
5580 + package main
5581 +
5582 + import (
5583 ++ "context"
5584 + "fmt"
5585 + "os"
5586 + "strconv"
5587 + "strings"
5588 + "time"
5589 +
5590 +- goredis "github.com/go-redis/redis"
5591 ++ goredis "github.com/go-redis/redis/v8"
5592 + )
5593 +
5594 ++var ctx = context.Background()
5595 + var options map[string]string
5596 +
5597 + func loadOptions() {
5598 +@@ -35,10 +37,10 @@ func loadOptions() {
5599 + var n int
5600 + if nopts, ok := os.LookupEnv("GIT_PUSH_OPTION_COUNT"); ok {
5601 + n, _ = strconv.Atoi(nopts)
5602 +- redis.Set(fmt.Sprintf("git.sr.ht.options.%s", uuid),
5603 ++ redis.Set(ctx, fmt.Sprintf("git.sr.ht.options.%s", uuid),
5604 + nopts, 10*time.Minute)
5605 + } else {
5606 +- nopts, err := redis.Get(fmt.Sprintf(
5607 ++ nopts, err := redis.Get(ctx, fmt.Sprintf(
5608 + "git.sr.ht.options.%s", uuid)).Result()
5609 + if err != nil {
5610 + return
5611 +@@ -51,12 +53,12 @@ func loadOptions() {
5612 + opt, ok := os.LookupEnv(fmt.Sprintf("GIT_PUSH_OPTION_%d", i))
5613 + optkey := fmt.Sprintf("git.sr.ht.options.%s.%d", uuid, i)
5614 + if !ok {
5615 +- opt, err = redis.Get(optkey).Result()
5616 ++ opt, err = redis.Get(ctx, optkey).Result()
5617 + if err != nil {
5618 + return
5619 + }
5620 + } else {
5621 +- redis.Set(optkey, opt, 10*time.Minute)
5622 ++ redis.Set(ctx, optkey, opt, 10*time.Minute)
5623 + }
5624 + parts := strings.SplitN(opt, "=", 2)
5625 + if len(parts) == 1 {
5626 +diff --git a/gitsrht-update-hook/post-update.go b/gitsrht-update-hook/post-update.go
5627 +index d14d616..fcd7864 100644
5628 +--- a/gitsrht-update-hook/post-update.go
5629 ++++ b/gitsrht-update-hook/post-update.go
5630 +@@ -15,7 +15,7 @@ import (
5631 + "github.com/go-git/go-git/v5/plumbing"
5632 + "github.com/go-git/go-git/v5/plumbing/object"
5633 + "github.com/go-git/go-git/v5/plumbing/storer"
5634 +- goredis "github.com/go-redis/redis"
5635 ++ goredis "github.com/go-redis/redis/v8"
5636 + _ "github.com/lib/pq"
5637 + )
5638 +
5639 +@@ -220,7 +220,7 @@ func postUpdate() {
5640 + var oldref, newref string
5641 + var oldobj, newobj object.Object
5642 + updateKey := fmt.Sprintf("update.%s.%s", pushUuid, refname)
5643 +- update, err := redis.Get(updateKey).Result()
5644 ++ update, err := redis.Get(ctx, updateKey).Result()
5645 + if update == "" || err != nil {
5646 + logger.Println("redis.Get: missing key")
5647 + continue
5648 +diff --git a/gitsrht-update-hook/update.go b/gitsrht-update-hook/update.go
5649 +index 72c661a..e33fd4b 100644
5650 +--- a/gitsrht-update-hook/update.go
5651 ++++ b/gitsrht-update-hook/update.go
5652 +@@ -5,7 +5,7 @@ import (
5653 + "os"
5654 + "time"
5655 +
5656 +- goredis "github.com/go-redis/redis"
5657 ++ goredis "github.com/go-redis/redis/v8"
5658 + )
5659 +
5660 + // XXX: This is run once for every single ref that's pushed. If someone pushes
5661 +@@ -31,6 +31,6 @@ func update() {
5662 + logger.Fatalf("Failed to parse redis host: %v", err)
5663 + }
5664 + redis := goredis.NewClient(ropts)
5665 +- redis.Set(fmt.Sprintf("update.%s.%s", pushUuid, refname),
5666 ++ redis.Set(ctx, fmt.Sprintf("update.%s.%s", pushUuid, refname),
5667 + fmt.Sprintf("%s:%s", oldref, newref), 10*time.Minute)
5668 + }
5669 +--
5670 +2.32.0
5671 +
5672 diff --git a/pkgs/applications/version-management/sourcehut/patches/redis-socket/git/v3-0003-gitsrht-dispatch-add-support-for-supplementary-gr.patch b/pkgs/applications/version-management/sourcehut/patches/redis-socket/git/v3-0003-gitsrht-dispatch-add-support-for-supplementary-gr.patch
5673 new file mode 100644
5674 index 00000000000..9a4b0300921
5675 --- /dev/null
5676 +++ b/pkgs/applications/version-management/sourcehut/patches/redis-socket/git/v3-0003-gitsrht-dispatch-add-support-for-supplementary-gr.patch
5677 @@ -0,0 +1,57 @@
5678 +From fcbec39a406562c29dfcf7eeef6f284da28bc619 Mon Sep 17 00:00:00 2001
5679 +From: Julien Moutinho <julm+srht@sourcephile.fr>
5680 +Date: Fri, 27 Aug 2021 17:42:33 +0200
5681 +Subject: [PATCH git.sr.ht v3 3/3] gitsrht-dispatch: add support for
5682 + supplementary groups
5683 +
5684 +---
5685 + gitsrht-dispatch/main.go | 17 ++++++++++++++---
5686 + 1 file changed, 14 insertions(+), 3 deletions(-)
5687 +
5688 +diff --git a/gitsrht-dispatch/main.go b/gitsrht-dispatch/main.go
5689 +index d7aee14..5f17b75 100644
5690 +--- a/gitsrht-dispatch/main.go
5691 ++++ b/gitsrht-dispatch/main.go
5692 +@@ -17,6 +17,7 @@ type Dispatcher struct {
5693 + cmd string
5694 + uid int
5695 + gid int
5696 ++ gids []int
5697 + }
5698 +
5699 + func main() {
5700 +@@ -70,11 +71,20 @@ AuthorizedKeysUser=root`, os.Args[0])
5701 + if err != nil {
5702 + logger.Fatalf("Error looking up group %s: %v", spec[1], err)
5703 + }
5704 ++ groups, err := user.GroupIds()
5705 ++ if err != nil {
5706 ++ logger.Fatalf("Error looking up supplementary groups of user %s: %v", spec[0], err)
5707 ++ }
5708 ++ gids := make([]int, len(groups))
5709 ++ for i, grp := range groups {
5710 ++ sgid, _ := strconv.Atoi(grp)
5711 ++ gids[i] = sgid
5712 ++ }
5713 + uid, _ := strconv.Atoi(user.Uid)
5714 + gid, _ := strconv.Atoi(group.Gid)
5715 +- dispatchers[uid] = Dispatcher{cmd, uid, gid}
5716 +- logger.Printf("Registered dispatcher for %s(%d):%s(%d): %s",
5717 +- spec[0], uid, spec[1], gid, cmd)
5718 ++ dispatchers[uid] = Dispatcher{cmd, uid, gid, gids}
5719 ++ logger.Printf("Registered dispatcher for %s(%d):%s(%d):(%s): %s",
5720 ++ spec[0], uid, spec[1], gid, strings.Join(groups, ","), cmd)
5721 + }
5722 +
5723 + var user *osuser.User
5724 +@@ -93,6 +103,7 @@ AuthorizedKeysUser=root`, os.Args[0])
5725 +
5726 + if dispatcher, ok := dispatchers[uid]; ok {
5727 + logger.Printf("Dispatching to %s", dispatcher.cmd)
5728 ++ syscall.Setgroups(dispatcher.gids)
5729 + syscall.Setgid(dispatcher.gid)
5730 + syscall.Setuid(dispatcher.uid)
5731 + if err := syscall.Exec(dispatcher.cmd, append([]string{
5732 +--
5733 +2.32.0
5734 +
5735 diff --git a/pkgs/applications/version-management/sourcehut/patches/redis-socket/scm/v3-0001-srht-keys-update-go-redis-to-support-Unix-sockets.patch b/pkgs/applications/version-management/sourcehut/patches/redis-socket/scm/v3-0001-srht-keys-update-go-redis-to-support-Unix-sockets.patch
5736 new file mode 100644
5737 index 00000000000..191ff61b826
5738 --- /dev/null
5739 +++ b/pkgs/applications/version-management/sourcehut/patches/redis-socket/scm/v3-0001-srht-keys-update-go-redis-to-support-Unix-sockets.patch
5740 @@ -0,0 +1,61 @@
5741 +From e244cb7398758f91cc6deaabf278a1b6412ee477 Mon Sep 17 00:00:00 2001
5742 +From: Julien Moutinho <julm+srht@sourcephile.fr>
5743 +Date: Fri, 27 Aug 2021 12:48:56 +0200
5744 +Subject: [PATCH scm.sr.ht v3 1/2] srht-keys: update go-redis to support Unix
5745 + sockets
5746 +
5747 +---
5748 + srht-keys/srhtkeys.go | 9 ++++++---
5749 + 1 file changed, 6 insertions(+), 3 deletions(-)
5750 +
5751 +diff --git a/srht-keys/srhtkeys.go b/srht-keys/srhtkeys.go
5752 +index be925ed..1a300d5 100644
5753 +--- a/srht-keys/srhtkeys.go
5754 ++++ b/srht-keys/srhtkeys.go
5755 +@@ -1,6 +1,7 @@
5756 + package srhtkeys
5757 +
5758 + import (
5759 ++ "context"
5760 + "database/sql"
5761 + "encoding/json"
5762 + "errors"
5763 +@@ -12,7 +13,7 @@ import (
5764 + "path"
5765 + "time"
5766 +
5767 +- goredis "github.com/go-redis/redis"
5768 ++ goredis "github.com/go-redis/redis/v8"
5769 + "github.com/google/uuid"
5770 + _ "github.com/lib/pq"
5771 + "github.com/vaughan0/go-ini"
5772 +@@ -37,6 +38,8 @@ type MetaSSHKey struct {
5773 + Owner MetaUser `json:"owner"`
5774 + }
5775 +
5776 ++var ctx = context.Background()
5777 ++
5778 + // Stores the SSH key in the database and returns the user's ID.
5779 + func storeKey(logger *log.Logger, db *sql.DB, key *MetaSSHKey) (int, error) {
5780 + logger.Println("Storing meta.sr.ht key in database")
5781 +@@ -145,7 +148,7 @@ func fetchKeysFromMeta(logger *log.Logger, config ini.File,
5782 + if err != nil {
5783 + logger.Printf("Caching SSH key in redis failed: %v", err)
5784 + } else {
5785 +- redis.Set(cacheKey, cacheBytes, 7*24*time.Hour)
5786 ++ redis.Set(ctx, cacheKey, cacheBytes, 7*24*time.Hour)
5787 + }
5788 +
5789 + return key.Owner.Username, userId
5790 +@@ -168,7 +171,7 @@ func UserFromKey(logger *log.Logger, config ini.File,
5791 +
5792 + cacheKey := fmt.Sprintf("%s.ssh-keys.%s", service, b64key)
5793 + logger.Printf("Cache key for SSH key lookup: %s", cacheKey)
5794 +- cacheBytes, err := redis.Get(cacheKey).Bytes()
5795 ++ cacheBytes, err := redis.Get(ctx, cacheKey).Bytes()
5796 + var (
5797 + username string
5798 + userId int
5799 +--
5800 +2.32.0
5801 +
5802 diff --git a/pkgs/applications/version-management/sourcehut/patches/redis-socket/scm/v3-0002-srht-keys-update-go.-mod-sum-for-go-redis.patch b/pkgs/applications/version-management/sourcehut/patches/redis-socket/scm/v3-0002-srht-keys-update-go.-mod-sum-for-go-redis.patch
5803 new file mode 100644
5804 index 00000000000..c5407a26491
5805 --- /dev/null
5806 +++ b/pkgs/applications/version-management/sourcehut/patches/redis-socket/scm/v3-0002-srht-keys-update-go.-mod-sum-for-go-redis.patch
5807 @@ -0,0 +1,155 @@
5808 +From aeb3e0dc2270e6ab3cd0f651ea735275e527e7ce Mon Sep 17 00:00:00 2001
5809 +From: Julien Moutinho <julm+srht@sourcephile.fr>
5810 +Date: Fri, 27 Aug 2021 13:06:27 +0200
5811 +Subject: [PATCH scm.sr.ht v3 2/2] srht-keys: update go.{mod,sum} for go-redis
5812 +
5813 +---
5814 + srht-keys/go.mod | 2 +-
5815 + srht-keys/go.sum | 103 ++++++++++++++++++++++++++++++++++++++++++++---
5816 + 2 files changed, 99 insertions(+), 6 deletions(-)
5817 +
5818 +diff --git a/srht-keys/go.mod b/srht-keys/go.mod
5819 +index d275913..8d1c10a 100644
5820 +--- a/srht-keys/go.mod
5821 ++++ b/srht-keys/go.mod
5822 +@@ -4,7 +4,7 @@ go 1.13
5823 +
5824 + require (
5825 + git.sr.ht/~sircmpwn/core-go v0.0.0-20201005173246-a9e49d17a1e6
5826 +- github.com/go-redis/redis v6.15.9+incompatible
5827 ++ github.com/go-redis/redis/v8 v8.11.3
5828 + github.com/google/uuid v1.1.1
5829 + github.com/lib/pq v1.8.0
5830 + github.com/vaughan0/go-ini v0.0.0-20130923145212-a98ad7ee00ec
5831 +diff --git a/srht-keys/go.sum b/srht-keys/go.sum
5832 +index 974326e..a264a26 100644
5833 +--- a/srht-keys/go.sum
5834 ++++ b/srht-keys/go.sum
5835 +@@ -1,26 +1,119 @@
5836 +-git.sr.ht/~sircmpwn/core-go v0.0.0-20200820135923-98806e712f5e h1:TJqf/neVU5peFAS9WcR1aADXcflPOvAd7ABEirmU7m0=
5837 +-git.sr.ht/~sircmpwn/core-go v0.0.0-20200820135923-98806e712f5e/go.mod h1:aXSNgRsGoI3tTFKlwD0xm2htbEzKlR2xUm1osRxfhOM=
5838 + git.sr.ht/~sircmpwn/core-go v0.0.0-20201005173246-a9e49d17a1e6 h1:Ky6HzcRmbMUxOrWXv04+mb97GkyxO/Nx7v8uJBUdpNk=
5839 + git.sr.ht/~sircmpwn/core-go v0.0.0-20201005173246-a9e49d17a1e6/go.mod h1:HpPX22ilJUWKOA4NDhrOcIyblQhdiKHPg4oMJFYdh0Y=
5840 ++github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
5841 ++github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
5842 + github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5843 ++github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
5844 ++github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5845 ++github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
5846 ++github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
5847 ++github.com/fernet/fernet-go v0.0.0-20191111064656-eff2850e6001 h1:/UMxx5lGDg30aioUL9e7xJnbJfJeX7vhcm57fa5udaI=
5848 + github.com/fernet/fernet-go v0.0.0-20191111064656-eff2850e6001/go.mod h1:2H9hjfbpSMHwY503FclkV/lZTBh2YlOmLLSda12uL8c=
5849 +-github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
5850 +-github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
5851 ++github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
5852 ++github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
5853 ++github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
5854 ++github.com/go-redis/redis/v8 v8.11.3 h1:GCjoYp8c+yQTJfc0n69iwSiHjvuAdruxl7elnZCxgt8=
5855 ++github.com/go-redis/redis/v8 v8.11.3/go.mod h1:xNJ9xDG09FsIPwh3bWdk+0oDWHbtF9rPN0F/oD9XeKc=
5856 ++github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
5857 ++github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
5858 ++github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
5859 ++github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
5860 ++github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
5861 ++github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
5862 ++github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
5863 ++github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
5864 ++github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
5865 ++github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
5866 ++github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
5867 ++github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
5868 ++github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
5869 ++github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
5870 ++github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
5871 ++github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
5872 ++github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
5873 + github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
5874 + github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
5875 ++github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
5876 + github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg=
5877 + github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
5878 ++github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
5879 ++github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
5880 ++github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
5881 ++github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
5882 ++github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
5883 ++github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
5884 ++github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
5885 ++github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
5886 ++github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
5887 ++github.com/onsi/gomega v1.15.0 h1:WjP/FQ/sk43MRmnEcT+MlDw2TFvkrXlprrPST/IudjU=
5888 ++github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
5889 ++github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
5890 + github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
5891 + github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
5892 ++github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
5893 ++github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
5894 + github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
5895 + github.com/vaughan0/go-ini v0.0.0-20130923145212-a98ad7ee00ec h1:DGmKwyZwEB8dI7tbLt/I/gQuP559o/0FrAkHKlQM/Ks=
5896 + github.com/vaughan0/go-ini v0.0.0-20130923145212-a98ad7ee00ec/go.mod h1:owBmyHYMLkxyrugmfwE/DLJyW8Ro9mkphwuVErQ0iUw=
5897 ++github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
5898 + golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
5899 +-golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de h1:ikNHVSjEfnvz6sxdSPCaPt572qowuyMDMJLLm3Db3ig=
5900 ++golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
5901 ++golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
5902 + golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
5903 ++golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
5904 ++golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
5905 + golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
5906 ++golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
5907 ++golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
5908 ++golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
5909 ++golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0=
5910 ++golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
5911 ++golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
5912 ++golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
5913 ++golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
5914 ++golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
5915 + golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
5916 + golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
5917 ++golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
5918 ++golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
5919 ++golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
5920 ++golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
5921 ++golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
5922 ++golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
5923 ++golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
5924 ++golang.org/x/sys v0.0.0-20210423082822-04245dca01da h1:b3NXsE2LusjYGGjL5bxEVZZORm/YEFFrWFjR8eFrw/c=
5925 ++golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
5926 ++golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
5927 + golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
5928 ++golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
5929 ++golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
5930 ++golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
5931 ++golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
5932 ++golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
5933 ++golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
5934 ++golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
5935 ++golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
5936 ++golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
5937 ++golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
5938 ++golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
5939 ++google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
5940 ++google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
5941 ++google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
5942 ++google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
5943 ++google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
5944 ++google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
5945 ++google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
5946 ++google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
5947 ++google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
5948 ++gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
5949 + gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
5950 ++gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
5951 ++gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
5952 ++gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
5953 ++gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
5954 ++gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
5955 ++gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
5956 ++gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
5957 ++gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
5958 ++gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
5959 + gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
5960 +--
5961 +2.32.0
5962 +
5963 diff --git a/pkgs/applications/version-management/sourcehut/scm.nix b/pkgs/applications/version-management/sourcehut/scm.nix
5964 index 1f385265360..55bc2aa9e72 100644
5965 --- a/pkgs/applications/version-management/sourcehut/scm.nix
5966 +++ b/pkgs/applications/version-management/sourcehut/scm.nix
5967 @@ -1,22 +1,57 @@
5968 { lib
5969 , fetchFromSourcehut
5970 +, buildGoModule
5971 , buildPythonPackage
5972 , srht
5973 , redis
5974 , pyyaml
5975 -, buildsrht
5976 -, writeText
5977 +, applyPatches
5978 }:
5979
5980 buildPythonPackage rec {
5981 pname = "scmsrht";
5982 - version = "0.22.9";
5983 + version = "0.22.15";
5984
5985 src = fetchFromSourcehut {
5986 owner = "~sircmpwn";
5987 repo = "scm.sr.ht";
5988 rev = version;
5989 - sha256 = "sha256-327G6C8FW+iZx+167D7TQsFtV6FGc8MpMVo9L/cUUqU=";
5990 + sha256 = "sha256-h4akgDn78ctBF31TX8D8NwUVUVazClPVvCR9xWyQPBk=";
5991 + };
5992 +
5993 + passthru = {
5994 + srht-keys = buildGoModule {
5995 + inherit src version;
5996 + sourceRoot = "source/srht-keys";
5997 + pname = "srht-keys";
5998 + vendorSha256 = "sha256-7j6b9VOpdQ2YcoM1F4xf14IwHg3GFDN6VDbC4gt6wO0=";
5999 +
6000 + # What follows is only to update go-redis
6001 + # go.{mod,sum} could be patched directly but that would be less resilient
6002 + # to changes from upstream, and thus harder to maintain the patching
6003 + # while it hasn't been merged upstream.
6004 +
6005 + overrideModAttrs = old: {
6006 + preBuild = ''
6007 + go get github.com/go-redis/redis/v8
6008 + go get github.com/go-redis/redis@none
6009 + go mod tidy
6010 + '';
6011 + # Pass updated go.{mod,sum} from go-modules to srht-keys's vendor/go.{mod,sum}
6012 + postInstall = ''
6013 + cp --reflink=auto go.* $out
6014 + '';
6015 + };
6016 +
6017 + patches = [
6018 + # Update go-redis to support Unix sockets
6019 + patches/redis-socket/scm/v3-0001-srht-keys-update-go-redis-to-support-Unix-sockets.patch
6020 + ];
6021 + patchFlags = ["-p2"];
6022 + postInstall = ''
6023 + cp --reflink=auto *.go vendor/go.* $out
6024 + '';
6025 + };
6026 };
6027
6028 nativeBuildInputs = srht.nativeBuildInputs;
6029 @@ -25,7 +60,6 @@ buildPythonPackage rec {
6030 srht
6031 redis
6032 pyyaml
6033 - buildsrht
6034 ];
6035
6036 preBuild = ''
6037 @@ -33,11 +67,12 @@ buildPythonPackage rec {
6038 '';
6039
6040 dontUseSetuptoolsCheck = true;
6041 + pythonImportsCheck = [ "scmsrht" ];
6042
6043 meta = with lib; {
6044 homepage = "https://git.sr.ht/~sircmpwn/git.sr.ht";
6045 description = "Shared support code for sr.ht source control services.";
6046 - license = licenses.agpl3;
6047 + license = licenses.agpl3Only;
6048 maintainers = with maintainers; [ eadwu ];
6049 };
6050 }
6051 diff --git a/pkgs/applications/version-management/sourcehut/todo.nix b/pkgs/applications/version-management/sourcehut/todo.nix
6052 index 85e1f5637b6..cdb1f8cf8be 100644
6053 --- a/pkgs/applications/version-management/sourcehut/todo.nix
6054 +++ b/pkgs/applications/version-management/sourcehut/todo.nix
6055 @@ -12,13 +12,13 @@
6056
6057 buildPythonPackage rec {
6058 pname = "todosrht";
6059 - version = "0.64.14";
6060 + version = "0.65.2";
6061
6062 src = fetchFromSourcehut {
6063 owner = "~sircmpwn";
6064 repo = "todo.sr.ht";
6065 rev = version;
6066 - sha256 = "sha256-huIAhn6h1F5w5ST4/yBwr82kAzyYwhLu+gpRuOQgnsE=";
6067 + sha256 = "sha256-46RkBwLuGpYYw2V4JBDR414W2EaYnz0rru/T9j/PrJs=";
6068 };
6069
6070 nativeBuildInputs = srht.nativeBuildInputs;
6071 @@ -42,11 +42,12 @@ buildPythonPackage rec {
6072 ];
6073
6074 dontUseSetuptoolsCheck = true;
6075 + pythonImportsCheck = [ "todosrht" ];
6076
6077 meta = with lib; {
6078 homepage = "https://todo.sr.ht/~sircmpwn/todo.sr.ht";
6079 description = "Ticket tracking service for the sr.ht network";
6080 - license = licenses.agpl3;
6081 + license = licenses.agpl3Only;
6082 maintainers = with maintainers; [ eadwu ];
6083 };
6084 }
6085 diff --git a/pkgs/applications/version-management/sourcehut/update.sh b/pkgs/applications/version-management/sourcehut/update.sh
6086 index 156d4cc35e4..1638313697c 100755
6087 --- a/pkgs/applications/version-management/sourcehut/update.sh
6088 +++ b/pkgs/applications/version-management/sourcehut/update.sh
6089 @@ -1,8 +1,11 @@
6090 #! /usr/bin/env nix-shell
6091 #! nix-shell -i bash -p git mercurial common-updater-scripts
6092 +set -eux -o pipefail
6093
6094 -cd "$(dirname "${BASH_SOURCE[0]}")"
6095 +cd "$(dirname "${BASH_SOURCE[0]}")" || exit 1
6096 root=../../../..
6097 +tmp=$(mktemp -d)
6098 +trap 'rm -rf "$tmp"' EXIT
6099
6100 default() {
6101 (cd "$root" && nix-instantiate --eval --strict -A "sourcehut.python.pkgs.$1.meta.position" | sed -re 's/^"(.*):[0-9]+"$/\1/')
6102 @@ -13,42 +16,61 @@ version() {
6103 }
6104
6105 src_url() {
6106 - (cd "$root" && nix-instantiate --eval --strict -A "sourcehut.python.pkgs.$1.src.drvAttrs.url" | tr -d '"')
6107 + nix-instantiate --eval --strict --expr " with import $root {}; let src = sourcehut.python.pkgs.$1.drvAttrs.src; in src.url or src.meta.homepage" | tr -d '"'
6108 }
6109
6110 get_latest_version() {
6111 src="$(src_url "$1")"
6112 - tmp=$(mktemp -d)
6113 -
6114 + rm -rf "$tmp"
6115 if [ "$1" = "hgsrht" ]; then
6116 - hg clone "$src" "$tmp" &> /dev/null
6117 + hg clone "$src" "$tmp" >/dev/null
6118 printf "%s" "$(cd "$tmp" && hg log --limit 1 --template '{latesttag}')"
6119 else
6120 - git clone "$src" "$tmp"
6121 - printf "%s" "$(cd "$tmp" && git describe $(git rev-list --tags --max-count=1))"
6122 + git clone "$src" "$tmp" >/dev/null
6123 + printf "%s" "$(cd "$tmp" && git describe "$(git rev-list --tags --max-count=1)")"
6124 fi
6125 }
6126
6127 update_version() {
6128 default_nix="$(default "$1")"
6129 - version_old="$(version "$1")"
6130 + oldVersion="$(version "$1")"
6131 version="$(get_latest_version "$1")"
6132
6133 (cd "$root" && update-source-version "sourcehut.python.pkgs.$1" "$version")
6134
6135 - git add "$default_nix"
6136 - git commit -m "$1: $version_old -> $version"
6137 + # Update vendorSha256 of Go modules
6138 + retry=true
6139 + while "$retry"; do
6140 + retry=false;
6141 + exec < <(exec nix -L build -f "$root" sourcehut.python.pkgs."$1" 2>&1)
6142 + while IFS=' :' read -r origin hash; do
6143 + case "$origin" in
6144 + (expected|specified) oldHash="$hash";;
6145 + (got) sed -i "s|$oldHash|$hash|" "$default_nix"; retry=true; break;;
6146 + (*) printf >&2 "%s\n" "$origin${hash:+:$hash}"
6147 + esac
6148 + done
6149 + done
6150 +
6151 + if [ "$oldVersion" != "$version" ]; then
6152 + git add "$default_nix"
6153 + git commit -m "sourcehut.$1: $oldVersion -> $version"
6154 + fi
6155 }
6156
6157 -services=( "srht" "buildsrht" "dispatchsrht" "gitsrht" "hgsrht" "hubsrht" "listssrht" "mansrht"
6158 - "metasrht" "pastesrht" "todosrht" "scmsrht" )
6159 -
6160 -# Whether or not a specific service is requested
6161 -if [ -n "$1" ]; then
6162 - version="$(get_latest_version "$1")"
6163 - (cd "$root" && update-source-version "sourcehut.python.pkgs.$1" "$version")
6164 +if [ $# -gt 0 ]; then
6165 + services=("$@")
6166 else
6167 - for service in "${services[@]}"; do
6168 - update_version "$service"
6169 - done
6170 + # Beware that some packages must be updated before others,
6171 + # eg. srht-keys must be update before gitsrht,
6172 + # otherwise this script would enter an infinite loop
6173 + # because the reported $oldHash to be changed
6174 + # may not actually be in $default_nix
6175 + # but in the file of one of its dependencies.
6176 + services=( "srht" "scmsrht" "srht-keys" "buildsrht" "dispatchsrht" "gitsrht" "hgsrht" "hubsrht" "listssrht" "mansrht"
6177 + "metasrht" "pagessrht" "pastesrht" "todosrht" )
6178 fi
6179 +
6180 +for service in "${services[@]}"; do
6181 + update_version "$service"
6182 +done
6183 diff --git a/pkgs/development/go-modules/generic/default.nix b/pkgs/development/go-modules/generic/default.nix
6184 index 3b645f9ce8b..f00ca1984ec 100644
6185 --- a/pkgs/development/go-modules/generic/default.nix
6186 +++ b/pkgs/development/go-modules/generic/default.nix
6187 @@ -71,6 +71,7 @@ let
6188 inherit (go) GOOS GOARCH;
6189
6190 patches = args.patches or [];
6191 + patchFlags = args.patchFlags or [];
6192 preBuild = args.preBuild or "";
6193 sourceRoot = args.sourceRoot or "";
6194