feat: init hydra-queue-runner-v2
Simon Hauser committed
Jul 7, 2025 at 18:47 UTC
8cfd161df7d2acbeab4680a8f7f843ef8f444f58
13 files changed
+994
-46
dns/nixos.org.js
+1
@@ -96,6 +96,7 @@ D("nixos.org",
96
// hydra staging area
97
A("staging-hydra", "157.180.25.203"),
98
AAAA("staging-hydra", "2a01:4f9:c012:d5d3::1"),
99
+ CNAME("queue-runner.staging-hydra", "staging-hydra"),
100
101
// services infra
102
A("caliban", "65.109.26.213"),
non-critical-infra/hosts/staging-hydra/ca.crt
new
+11
@@ -0,0 +1,11 @@
1
+-----BEGIN CERTIFICATE-----
2
+MIIBnTCCAU+gAwIBAgIUQpxYsPwAyTY70yYO9fcCmCaZreIwBQYDK2VwMEMxCzAJ
3
+BgNVBAYTAkRFMRQwEgYDVQQKDAtOaXhPUyBJbmZyYTEeMBwGA1UEAwwVaHlkcmEt
4
+cXVldWUtcnVubmVyLWNhMCAXDTI1MDczMTEyMDQxN1oYDzIwNzUwNzE5MTIwNDE3
5
+WjBDMQswCQYDVQQGEwJERTEUMBIGA1UECgwLTml4T1MgSW5mcmExHjAcBgNVBAMM
6
+FWh5ZHJhLXF1ZXVlLXJ1bm5lci1jYTAqMAUGAytlcAMhAM+Mc/XSTXwJeWPxrpqo
7
+SPT5Xwi8/j85VO6TsfBlXFt4o1MwUTAdBgNVHQ4EFgQU0wQG6BxTKtYwlywuyD0a
8
+Vr/1r4gwHwYDVR0jBBgwFoAU0wQG6BxTKtYwlywuyD0aVr/1r4gwDwYDVR0TAQH/
9
+BAUwAwEB/zAFBgMrZXADQQA3BRP2+TkkDQPnPy6MQyDCxqfEeV6OQjtspSvCO0UL
10
+GWmfvzrlUQytwTFTPfVzaErbyVPbeYU5y8rmRoGPNSoI
11
+-----END CERTIFICATE-----
non-critical-infra/hosts/staging-hydra/client.crt
new
+11
@@ -0,0 +1,11 @@
1
+-----BEGIN CERTIFICATE-----
2
+MIIBlDCCAUagAwIBAgIUfUYjDOaJML1lIMkAMvLjnSTscYwwBQYDK2VwMEMxCzAJ
3
+BgNVBAYTAkRFMRQwEgYDVQQKDAtOaXhPUyBJbmZyYTEeMBwGA1UEAwwVaHlkcmEt
4
+cXVldWUtcnVubmVyLWNhMCAXDTI1MDczMTEyMDQxN1oYDzIwNzUwNzE5MTIwNDE3
5
+WjBLMQswCQYDVQQGEwJERTEUMBIGA1UECgwLTml4T1MgSW5mcmExJjAkBgNVBAMM
6
+HWh5ZHJhLXF1ZXVlLWJ1aWxkZXItbG9jYWxob3N0MCowBQYDK2VwAyEAJqCvjdwY
7
+0l4z0cbwecONx3DfhpPo+SBymv7H2OQt4aejQjBAMB0GA1UdDgQWBBQw54bw+CrK
8
+O53J4qzB4Cknzf7CzTAfBgNVHSMEGDAWgBTTBAboHFMq1jCXLC7IPRpWv/WviDAF
9
+BgMrZXADQQB+XUCZQo0aX6IyEQDrds1d3SWF1rFBv5MjtZS25TYpnQQPgt9iiD6Q
10
+dtCwSVqyAgCG4XlkYBpU4AKVKqyMsSAC
11
+-----END CERTIFICATE-----
non-critical-infra/hosts/staging-hydra/default.nix
+2
@@ -5,6 +5,8 @@
5
inputs.srvos.nixosModules.server
6
inputs.srvos.nixosModules.hardware-hetzner-cloud-arm
7
../../modules/common.nix
8
+ ../../modules/hydra-queue-runner-v2.nix
9
+ ../../modules/hydra-queue-builder-v2.nix
10
./hydra-proxy.nix
11
./hydra.nix
12
inputs.hydra.nixosModules.hydra
non-critical-infra/hosts/staging-hydra/genca.sh
new
+55
@@ -0,0 +1,55 @@
1
+#!/usr/bin/env bash
2
+
3
+set -x
4
+
5
+hosts="localhost ofborg-eval02 ofborg-eval03 ofborg-eval04 ofborg-build01 ofborg-build02 ofborg-build03 ofborg-build04 ofborg-build05"
6
+
7
+C="DE"
8
+O="NixOS Infra"
9
+
10
+newDir="$(date '+%Y-%m-%dT%H:%M')"
11
+mkdir "${newDir}"
12
+cd "${newDir}" || exit
13
+
14
+openssl genpkey -algorithm Ed25519 -out ca.key
15
+openssl req -x509 -new -nodes -key ca.key -sha256 -days 18250 -out ca.crt \
16
+ -subj "/C=${C}/O=${O}/CN=hydra-queue-runner-ca"
17
+
18
+cat <<EOF >server.cnf
19
+[req]
20
+prompt = no
21
+x509_extensions = v3_req
22
+req_extensions = v3_req
23
+default_md = sha256
24
+distinguished_name = req_distinguished_name
25
+
26
+[req_distinguished_name]
27
+C = ${C}
28
+O = ${O}
29
+CN = queue-runner.staging-hydra.nixos.org
30
+
31
+[v3_req]
32
+basicConstraints = CA:FALSE
33
+keyUsage = nonRepudiation, digitalSignature, keyEncipherment, keyAgreement
34
+extendedKeyUsage = critical, serverAuth
35
+subjectAltName = @alt_names
36
+
37
+[alt_names]
38
+DNS.1 = queue-runner.staging-hydra.nixos.org
39
+EOF
40
+
41
+openssl genpkey -algorithm Ed25519 -out server.key
42
+openssl req -new -key server.key -out server.csr -config server.cnf
43
+openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 18250 -sha256 -extfile server.cnf -extensions v3_req
44
+
45
+for host in ${hosts}; do
46
+ openssl genpkey -algorithm Ed25519 -out "client-${host}.key"
47
+ openssl req -new -key "client-${host}.key" -out "client-${host}.csr" \
48
+ -subj "/C=${C}/O=${O}/CN=hydra-queue-builder-${host}"
49
+ openssl x509 -req -in "client-${host}.csr" -CA ca.crt -CAkey ca.key -CAcreateserial -out "client-${host}.crt" -days 18250 -sha256
50
+done
51
+
52
+rm -rf -- *.csr *.srl
53
+rm server.cnf
54
+
55
+cd - || exit
non-critical-infra/hosts/staging-hydra/hydra.nix
+117
-46
@@ -44,67 +44,136 @@ in
44
};
45
};
46
47
- services.hydra-dev = {
48
- enable = true;
49
- package = pkgs.hydra;
50
- buildMachinesFiles = [
51
- (pkgs.writeText "local" ''
52
- localhost ${lib.concatStringsSep "," localSystems} - 3 1 ${lib.concatStringsSep "," config.nix.settings.system-features} - -
53
- '')
54
- ];
55
- logo = ../../../build/hydra-logo.png;
56
- hydraURL = "https://hydra.nixos.org";
57
- notificationSender = "edolstra@gmail.com";
58
- smtpHost = "localhost";
59
- useSubstitutes = true;
60
- extraConfig = ''
61
- max_servers 30
47
+ services = {
48
+ hydra-dev = {
49
+ enable = true;
50
+ package = pkgs.hydra;
51
+ buildMachinesFiles = [
52
+ (pkgs.writeText "local" ''
53
+ localhost ${lib.concatStringsSep "," localSystems} - 3 1 ${lib.concatStringsSep "," config.nix.settings.system-features} - -
54
+ '')
55
+ ];
56
+ logo = ../../../build/hydra-logo.png;
57
+ hydraURL = "https://hydra.nixos.org";
58
+ notificationSender = "edolstra@gmail.com";
59
+ smtpHost = "localhost";
60
+ useSubstitutes = true;
61
+ extraConfig = ''
62
+ max_servers 30
63
63
- store_uri = s3://nix-cache-staging?secret-key=${config.sops.secrets.signing-key.path}&ls-compression=br&log-compression=br
64
- server_store_uri = https://cache-staging.nixos.org?local-nar-cache=${narCache}
65
- binary_cache_public_uri = https://cache-staging.nixos.org
64
+ store_uri = s3://nix-cache-staging?secret-key=${config.sops.secrets.signing-key.path}&ls-compression=br&log-compression=br
65
+ server_store_uri = https://cache-staging.nixos.org?local-nar-cache=${narCache}
66
+ binary_cache_public_uri = https://cache-staging.nixos.org
67
67
- <Plugin::Session>
68
- cache_size = 32m
69
- </Plugin::Session>
68
+ <Plugin::Session>
69
+ cache_size = 32m
70
+ </Plugin::Session>
71
71
- # patchelf:master:3
72
- xxx-jobset-repeats = nixos:reproducibility:1
72
+ # patchelf:master:3
73
+ xxx-jobset-repeats = nixos:reproducibility:1
74
74
- upload_logs_to_binary_cache = true
75
- compress_build_logs = false # conflicts with upload_logs_to_binary_cache
75
+ upload_logs_to_binary_cache = true
76
+ compress_build_logs = false # conflicts with upload_logs_to_binary_cache
77
77
- log_prefix = https://cache.nixos.org/
78
+ log_prefix = https://cache.nixos.org/
79
79
- evaluator_workers = 1
80
- evaluator_max_memory_size = 4096
80
+ evaluator_workers = 1
81
+ evaluator_max_memory_size = 4096
82
82
- max_concurrent_evals = 1
83
+ queue_runner_endpoint = http://localhost:8080
84
84
- # increase the number of active compress slots (CPU is 48*2 on mimas)
85
- max_local_worker_threads = 144
85
+ max_concurrent_evals = 1
86
87
- max_unsupported_time = 86400
87
+ # increase the number of active compress slots (CPU is 48*2 on mimas)
88
+ max_local_worker_threads = 144
89
89
- allow_import_from_derivation = false
90
+ max_unsupported_time = 86400
91
91
- max_output_size = 3821225472 # 3 << 30 + 600000000 = 3 GiB + 0.6 GB
92
- max_db_connections = 350
92
+ allow_import_from_derivation = false
93
94
- queue_runner_metrics_address = [::]:9198
94
+ max_output_size = 3821225472 # 3 << 30 + 600000000 = 3 GiB + 0.6 GB
95
+ max_db_connections = 350
96
96
- <hydra_notify>
97
- <prometheus>
98
- listen_address = 0.0.0.0
99
- port = 9199
100
- </prometheus>
101
- </hydra_notify>
102
- '';
97
+ queue_runner_metrics_address = [::]:9198
98
+
99
+ <hydra_notify>
100
+ <prometheus>
101
+ listen_address = 0.0.0.0
102
+ port = 9199
103
+ </prometheus>
104
+ </hydra_notify>
105
+ '';
106
+ };
107
+
108
+ hydra-queue-runner-v2 = {
109
+ enable = true;
110
+ settings.remoteStoreAddr = [
111
+ "s3://nix-cache-staging?secret-key=${config.sops.secrets.signing-key.path}&ls-compression=br&log-compression=br"
112
+ ];
113
+ };
114
+
115
+ hydra-queue-builder-v2 = {
116
+ enable = true;
117
+ queueRunnerAddr = "https://queue-runner.staging-hydra.nixos.org";
118
+ mtls = {
119
+ serverRootCaCertPath = "${./ca.crt}";
120
+ clientCertPath = "${./client.crt}";
121
+ clientKeyPath = config.sops.secrets."queue-runner-client.key".path;
122
+ domainName = "queue-runner.staging-hydra.nixos.org";
123
+ };
124
+ };
125
+
126
+ nginx = {
127
+ enable = true;
128
+ virtualHosts."queue-runner.staging-hydra.nixos.org" = {
129
+ extraConfig = ''
130
+ ssl_client_certificate ${./ca.crt};
131
+ ssl_verify_depth 2;
132
+ ssl_verify_client on;
133
+ '';
134
+
135
+ sslCertificate = ./server.crt;
136
+ sslCertificateKey = config.sops.secrets."queue-runner-server.key".path;
137
+ onlySSL = true;
138
+
139
+ locations."/".extraConfig = ''
140
+ # This is necessary so that grpc connections do not get closed early
141
+ # see https://stackoverflow.com/a/67805465
142
+ client_body_timeout 31536000s;
143
+
144
+ grpc_pass grpc://[::1]:50051;
145
+
146
+ grpc_read_timeout 31536000s; # 1 year in seconds
147
+ grpc_send_timeout 31536000s; # 1 year in seconds
148
+ grpc_socket_keepalive on;
149
+
150
+ grpc_set_header Host $host;
151
+ grpc_set_header X-Real-IP $remote_addr;
152
+ grpc_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
153
+ grpc_set_header X-Forwarded-Proto $scheme;
154
+
155
+ grpc_set_header X-Client-DN $ssl_client_s_dn;
156
+ grpc_set_header X-Client-Cert $ssl_client_escaped_cert;
157
+ '';
158
+ };
159
+ };
160
};
161
105
- sops.secrets.hydra-users = {
106
- sopsFile = ../../secrets/hydra-users.staging-hydra;
107
- format = "binary";
162
+ sops.secrets = {
163
+ "queue-runner-server.key" = {
164
+ sopsFile = ../../secrets/queue-runner-server.key.staging-hydra;
165
+ format = "binary";
166
+ owner = config.systemd.services.hydra-queue-runner.serviceConfig.User;
167
+ };
168
+ "queue-runner-client.key" = {
169
+ sopsFile = ../../secrets/queue-runner-client.key.staging-hydra;
170
+ format = "binary";
171
+ owner = config.systemd.services.hydra-queue-runner.serviceConfig.User;
172
+ };
173
+ hydra-users = {
174
+ sopsFile = ../../secrets/hydra-users.staging-hydra;
175
+ format = "binary";
176
+ };
177
};
178
179
systemd = {
@@ -117,6 +186,8 @@ in
186
services = {
187
hydra-notify.enable = false;
188
hydra-queue-runner = {
189
+ enable = false;
190
+
191
# restarting the scheduler is very expensive
192
restartIfChanged = false;
193
serviceConfig = {
non-critical-infra/hosts/staging-hydra/server.crt
new
+13
@@ -0,0 +1,13 @@
1
+-----BEGIN CERTIFICATE-----
2
+MIIB/jCCAbCgAwIBAgIUfUYjDOaJML1lIMkAMvLjnSTscYswBQYDK2VwMEMxCzAJ
3
+BgNVBAYTAkRFMRQwEgYDVQQKDAtOaXhPUyBJbmZyYTEeMBwGA1UEAwwVaHlkcmEt
4
+cXVldWUtcnVubmVyLWNhMCAXDTI1MDczMTEyMDQxN1oYDzIwNzUwNzE5MTIwNDE3
5
+WjBSMQswCQYDVQQGEwJERTEUMBIGA1UECgwLTml4T1MgSW5mcmExLTArBgNVBAMM
6
+JHF1ZXVlLXJ1bm5lci5zdGFnaW5nLWh5ZHJhLm5peG9zLm9yZzAqMAUGAytlcAMh
7
+ANVnDi5rY0Ar4hPbqRJqS+Nw7b5GTg0QxL2DM7l1xTqHo4GkMIGhMAkGA1UdEwQC
8
+MAAwCwYDVR0PBAQDAgPoMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMBMC8GA1UdEQQo
9
+MCaCJHF1ZXVlLXJ1bm5lci5zdGFnaW5nLWh5ZHJhLm5peG9zLm9yZzAdBgNVHQ4E
10
+FgQU4ArR8rzVAt6dFkSXiMUlYYAzbwUwHwYDVR0jBBgwFoAU0wQG6BxTKtYwlywu
11
+yD0aVr/1r4gwBQYDK2VwA0EAScS72oaQ8PcYpH26FuRGnKaWe4e7fQ5RmKBUyC+5
12
+CiYIWu4D7fNGYJ15szCfh4nJIuyB0eXBv1ddAGAQMVdhDw==
13
+-----END CERTIFICATE-----
non-critical-infra/modules/hydra-queue-builder-v2.nix
new
+275
@@ -0,0 +1,275 @@
1
+{
2
+ config,
3
+ pkgs,
4
+ lib,
5
+ ...
6
+}:
7
+let
8
+ cfg = config.services.hydra-queue-builder-v2;
9
+in
10
+{
11
+ options = {
12
+ services.hydra-queue-builder-v2 = {
13
+ enable = lib.mkEnableOption "QueueBuilder";
14
+
15
+ queueRunnerAddr = lib.mkOption {
16
+ description = "Queue Runner address to the grpc server";
17
+ type = lib.types.singleLineStr;
18
+ };
19
+
20
+ pingInterval = lib.mkOption {
21
+ description = "Interval in which pings are send to the runner";
22
+ type = lib.types.ints.positive;
23
+ default = 10;
24
+ };
25
+
26
+ speedFactor = lib.mkOption {
27
+ description = "Additional Speed factor for this machine";
28
+ type = lib.types.oneOf [
29
+ lib.types.ints.positive
30
+ lib.types.float
31
+ ];
32
+ default = 1;
33
+ };
34
+
35
+ maxJobs = lib.mkOption {
36
+ description = "Maximum allowed of jobs. This only is used if the queue runner uses this metrics for determining free machines.";
37
+ type = lib.types.ints.positive;
38
+ default = 4;
39
+ };
40
+
41
+ tmpAvailThreshold = lib.mkOption {
42
+ description = "Threshold in percent free for /tmp before jobs are no longer scheduled on the machine";
43
+ type = lib.types.float;
44
+ default = 10.0;
45
+ };
46
+
47
+ storeAvailThreshold = lib.mkOption {
48
+ description = "Threshold in percent free for /nix/store before jobs are no longer scheduled on the machine";
49
+ type = lib.types.float;
50
+ default = 10.0;
51
+ };
52
+
53
+ load1Threshold = lib.mkOption {
54
+ description = "Maximum Load1 threshold before we stop scheduling jobs on that node. Only used if PSI is not available.";
55
+ type = lib.types.float;
56
+ default = 8.0;
57
+ };
58
+
59
+ cpuPsiThreshold = lib.mkOption {
60
+ description = "Maximum CPU PSI in the last 10s before we stop scheduling jobs on that node";
61
+ type = lib.types.float;
62
+ default = 75.0;
63
+ };
64
+
65
+ memPsiThreshold = lib.mkOption {
66
+ description = "Maximum Memory PSI in the last 10s before we stop scheduling jobs on that node";
67
+ type = lib.types.float;
68
+ default = 80.0;
69
+ };
70
+
71
+ ioPsiThreshold = lib.mkOption {
72
+ description = "Maximum IO PSI in the last 10s before we stop scheduling jobs on that node. If null then this pressure check is disabled.";
73
+ type = lib.types.nullOr lib.types.float;
74
+ default = null;
75
+ };
76
+
77
+ systems = lib.mkOption {
78
+ description = "List of supported systems. If none are passed, system and extra-platforms are read from nix.";
79
+ type = lib.types.listOf lib.types.singleLineStr;
80
+ default = [ ];
81
+ };
82
+
83
+ supportedFeatures = lib.mkOption {
84
+ description = "Pass supported features to the builder. If none are passed, system features will be used.";
85
+ type = lib.types.listOf lib.types.singleLineStr;
86
+ default = [ ];
87
+ };
88
+
89
+ mandatoryFeatures = lib.mkOption {
90
+ description = "Pass mandatory features to the builder.";
91
+ type = lib.types.listOf lib.types.singleLineStr;
92
+ default = [ ];
93
+ };
94
+
95
+ useSubstitutes = lib.mkOption {
96
+ description = "Use substitution for paths";
97
+ type = lib.types.bool;
98
+ default = true;
99
+ };
100
+
101
+ mtls = lib.mkOption {
102
+ description = "mtls options";
103
+ default = null;
104
+ type = lib.types.nullOr (
105
+ lib.types.submodule {
106
+ options = {
107
+ serverRootCaCertPath = lib.mkOption {
108
+ description = "Server root ca certificate path";
109
+ type = lib.types.path;
110
+ };
111
+ clientCertPath = lib.mkOption {
112
+ description = "Client certificate path";
113
+ type = lib.types.path;
114
+ };
115
+ clientKeyPath = lib.mkOption {
116
+ description = "Client key path";
117
+ type = lib.types.path;
118
+ };
119
+ domainName = lib.mkOption {
120
+ description = "Domain name for mtls";
121
+ type = lib.types.singleLineStr;
122
+ };
123
+ };
124
+ }
125
+ );
126
+ };
127
+
128
+ package = lib.mkOption {
129
+ type = lib.types.package;
130
+ default = (pkgs.recurseIntoAttrs (pkgs.callPackage ../packages/hydra-queue-runner { })).builder;
131
+ };
132
+ };
133
+ };
134
+
135
+ config = lib.mkIf cfg.enable {
136
+ systemd.services.hydra-queue-builder-v2 = {
137
+ description = "hydra-queue-builder-v2 main service";
138
+
139
+ requires = [ "nix-daemon.socket" ];
140
+ after = [ "network.target" ];
141
+ wantedBy = [ "multi-user.target" ];
142
+
143
+ environment = {
144
+ NIX_REMOTE = "daemon";
145
+ LIBEV_FLAGS = "4"; # go ahead and mandate epoll(2)
146
+ RUST_BACKTRACE = "1";
147
+
148
+ # Note: it's important to set this for nix-store, because it wants to use
149
+ # $HOME in order to use a temporary cache dir. bizarre failures will occur
150
+ # otherwise
151
+ HOME = "/run/hydra-queue-builder-v2";
152
+ };
153
+
154
+ serviceConfig = {
155
+ Type = "notify";
156
+ Restart = "always";
157
+ RestartSec = "5s";
158
+
159
+ ExecStart = lib.escapeShellArgs (
160
+ [
161
+ (lib.getExe cfg.package)
162
+ "--gateway-endpoint"
163
+ cfg.queueRunnerAddr
164
+ "--ping-interval"
165
+ cfg.pingInterval
166
+ "--speed-factor"
167
+ cfg.speedFactor
168
+ "--max-jobs"
169
+ cfg.maxJobs
170
+ "--tmp-avail-threshold"
171
+ cfg.tmpAvailThreshold
172
+ "--store-avail-threshold"
173
+ cfg.storeAvailThreshold
174
+ "--load1-threshold"
175
+ cfg.load1Threshold
176
+ "--cpu-psi-threshold"
177
+ cfg.cpuPsiThreshold
178
+ "--mem-psi-threshold"
179
+ cfg.memPsiThreshold
180
+ ]
181
+ ++ lib.optionals (cfg.ioPsiThreshold != null) [
182
+ "--io-psi-threshold"
183
+ cfg.ioPsiThreshold
184
+ ]
185
+ ++ (builtins.concatMap (v: [
186
+ "--systems"
187
+ v
188
+ ]) cfg.systems)
189
+ ++ (builtins.concatMap (v: [
190
+ "--supported-features"
191
+ v
192
+ ]) cfg.supportedFeatures)
193
+ ++ (builtins.concatMap (v: [
194
+ "--mandatory-features"
195
+ v
196
+ ]) cfg.mandatoryFeatures)
197
+ ++ lib.optionals (cfg.useSubstitutes != null) [
198
+ "--use-substitutes"
199
+ ]
200
+ ++ lib.optionals (cfg.mtls != null) [
201
+ "--server-root-ca-cert-path"
202
+ cfg.mtls.serverRootCaCertPath
203
+ "--client-cert-path"
204
+ cfg.mtls.clientCertPath
205
+ "--client-key-path"
206
+ cfg.mtls.clientKeyPath
207
+ "--domain-name"
208
+ cfg.mtls.domainName
209
+ ]
210
+ );
211
+
212
+ User = "hydra-queue-builder";
213
+ Group = "hydra";
214
+
215
+ ReadWritePaths = [
216
+ "/nix/var/nix/gcroots/"
217
+ "/nix/var/nix/daemon-socket/socket"
218
+ ];
219
+ ReadOnlyPaths = [ "/nix/" ];
220
+ RuntimeDirectory = "hydra-queue-builder-v2";
221
+
222
+ PrivateNetwork = false;
223
+ SystemCallFilter = [
224
+ "@system-service"
225
+ "~@privileged"
226
+ "~@resources"
227
+ ];
228
+
229
+ ProtectSystem = "strict";
230
+ ProtectHome = true;
231
+ PrivateTmp = true;
232
+ PrivateDevices = true;
233
+ ProtectKernelTunables = true;
234
+ ProtectControlGroups = true;
235
+ RestrictSUIDSGID = true;
236
+ PrivateMounts = true;
237
+ RemoveIPC = true;
238
+ UMask = "0077";
239
+
240
+ CapabilityBoundingSet = "";
241
+ NoNewPrivileges = true;
242
+
243
+ ProtectKernelModules = true;
244
+ SystemCallArchitectures = "native";
245
+ ProtectKernelLogs = true;
246
+ ProtectClock = true;
247
+
248
+ RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
249
+
250
+ LockPersonality = true;
251
+ ProtectHostname = true;
252
+ RestrictRealtime = true;
253
+ MemoryDenyWriteExecute = true;
254
+ PrivateUsers = true;
255
+ RestrictNamespaces = true;
256
+ };
257
+ };
258
+ systemd.tmpfiles.rules = [
259
+ "d /nix/var/nix/gcroots/per-user/hydra-queue-builder 0755 hydra-queue-builder hydra -"
260
+ ];
261
+ nix.settings = {
262
+ allowed-users = [ "hydra-queue-builder" ];
263
+ experimental-features = [ "nix-command" ];
264
+ trusted-users = [ "hydra-queue-builder" ];
265
+ };
266
+
267
+ users = {
268
+ groups.hydra = { };
269
+ users.hydra-queue-builder = {
270
+ group = "hydra";
271
+ isSystemUser = true;
272
+ };
273
+ };
274
+ };
275
+}
non-critical-infra/modules/hydra-queue-runner-v2.nix
new
+300
@@ -0,0 +1,300 @@
1
+{
2
+ config,
3
+ pkgs,
4
+ lib,
5
+ ...
6
+}:
7
+let
8
+ cfg = config.services.hydra-queue-runner-v2;
9
+
10
+ format = pkgs.formats.toml { };
11
+in
12
+{
13
+ options = {
14
+ services.hydra-queue-runner-v2 = {
15
+ enable = lib.mkEnableOption "QueueRunner";
16
+
17
+ settings = lib.mkOption {
18
+ description = "Reloadable settings for queue runner";
19
+ type = lib.types.submodule {
20
+ options = {
21
+ hydraDataDir = lib.mkOption {
22
+ description = "Hydra data directory";
23
+ type = lib.types.path;
24
+ default = "/var/lib/hydra";
25
+ };
26
+ dbUrl = lib.mkOption {
27
+ description = "Postgresql database url";
28
+ type = lib.types.singleLineStr;
29
+ default = "postgres://hydra@%2Frun%2Fpostgresql:5432/hydra";
30
+ };
31
+ maxDbConnections = lib.mkOption {
32
+ description = "Postgresql maximum db connections";
33
+ type = lib.types.ints.positive;
34
+ default = 128;
35
+ };
36
+ machineSortFn = lib.mkOption {
37
+ description = "Function name for sorting machines";
38
+ type = lib.types.enum [
39
+ "SpeedFactorOnly"
40
+ "CpuCoreCountWithSpeedFactor"
41
+ "BogomipsWithSpeedFactor"
42
+ ];
43
+ default = "SpeedFactorOnly";
44
+ };
45
+ machineFreeFn = lib.mkOption {
46
+ description = "Function name for determining \"idle\" machines";
47
+ type = lib.types.enum [
48
+ "Dynamic"
49
+ "DynamicWithMaxJobLimit"
50
+ "Static"
51
+ ];
52
+ default = "Static";
53
+ };
54
+ dispatchTriggerTimerInS = lib.mkOption {
55
+ description = "Timer for triggering dispatch in an interval in seconds. Setting this to a value <= 0 will disable this timer and only trigger the dispatcher if queue changes happend.";
56
+ type = lib.types.int;
57
+ default = 120;
58
+ };
59
+ queueTriggerTimerInS = lib.mkOption {
60
+ description = "Timer for triggering queue in an interval in seconds. Setting this to a value <= 0 will disable this timer and only trigger via pg notifications.";
61
+ type = lib.types.int;
62
+ default = -1;
63
+ };
64
+ remoteStoreAddr = lib.mkOption {
65
+ description = "Remote store address";
66
+ type = lib.types.listOf lib.types.singleLineStr;
67
+ default = [ ];
68
+ };
69
+ useSubstitutes = lib.mkOption {
70
+ description = "Use substitution for paths";
71
+ type = lib.types.bool;
72
+ default = false;
73
+ };
74
+ rootsDir = lib.mkOption {
75
+ description = "Gcroots directory, defaults to /nix/var/nix/gcroots/per-user/$LOGNAME/hydra-roots";
76
+ type = lib.types.nullOr lib.types.path;
77
+ default = null;
78
+ };
79
+ maxRetries = lib.mkOption {
80
+ description = "Number of maximum amount of retries for a build step.";
81
+ type = lib.types.ints.positive;
82
+ default = 5;
83
+ };
84
+ retryInterval = lib.mkOption {
85
+ description = "Interval in which retires should be able to be attempted again.";
86
+ type = lib.types.ints.positive;
87
+ default = 60;
88
+ };
89
+ retryBackoff = lib.mkOption {
90
+ description = "Additional backoff on top of the retry interval.";
91
+ type = lib.types.float;
92
+ default = 3.0;
93
+ };
94
+ maxUnsupportedTimeInS = lib.mkOption {
95
+ description = "Time until unsupported steps are aborted.";
96
+ type = lib.types.ints.unsigned;
97
+ default = 120;
98
+ };
99
+ stopQueueRunAfterInS = lib.mkOption {
100
+ description = "Seconds after which the queue run should be interupted early. Setting this to a value <= 0 will disable this feature and the queue run will never exit early.";
101
+ type = lib.types.int;
102
+ default = 60;
103
+ };
104
+ };
105
+ };
106
+ default = { };
107
+ };
108
+
109
+ grpc = lib.mkOption {
110
+ description = "grpc options";
111
+ default = { };
112
+ type = lib.types.submodule {
113
+ options = {
114
+ address = lib.mkOption {
115
+ type = lib.types.singleLineStr;
116
+ default = "[::1]";
117
+ description = "The IP address the grpc listener should bound to";
118
+ };
119
+
120
+ port = lib.mkOption {
121
+ description = "Which grpc port this app should listen on";
122
+ type = lib.types.port;
123
+ default = 50051;
124
+ };
125
+ };
126
+ };
127
+ };
128
+
129
+ rest = lib.mkOption {
130
+ description = "rest options";
131
+ default = { };
132
+ type = lib.types.submodule {
133
+ options = {
134
+ address = lib.mkOption {
135
+ type = lib.types.singleLineStr;
136
+ default = "[::1]";
137
+ description = "The IP address the rest listener should bound to";
138
+ };
139
+
140
+ port = lib.mkOption {
141
+ description = "Which rest port this app should listen on";
142
+ type = lib.types.port;
143
+ default = 8080;
144
+ };
145
+ };
146
+ };
147
+ };
148
+
149
+ mtls = lib.mkOption {
150
+ description = "mtls options";
151
+ default = null;
152
+ type = lib.types.nullOr (
153
+ lib.types.submodule {
154
+ options = {
155
+ serverCertPath = lib.mkOption {
156
+ description = "Server certificate path";
157
+ type = lib.types.path;
158
+ };
159
+ serverKeyPath = lib.mkOption {
160
+ description = "Server key path";
161
+ type = lib.types.path;
162
+ };
163
+ clientCaCertPath = lib.mkOption {
164
+ description = "Client ca certificate path";
165
+ type = lib.types.path;
166
+ };
167
+ };
168
+ }
169
+ );
170
+ };
171
+ package = lib.mkOption {
172
+ type = lib.types.package;
173
+ default = (pkgs.recurseIntoAttrs (pkgs.callPackage ../packages/hydra-queue-runner { })).runner;
174
+ };
175
+ };
176
+ };
177
+
178
+ config = lib.mkIf cfg.enable {
179
+ systemd.services.hydra-queue-runner-v2 = {
180
+ description = "hydra queue-runner-v2 main service";
181
+
182
+ requires = [ "nix-daemon.socket" ];
183
+ after = [
184
+ "network.target"
185
+ "postgresql.service"
186
+ ];
187
+ wantedBy = [ "multi-user.target" ];
188
+ reloadTriggers = [ config.environment.etc."hydra/queue-runner.toml".source ];
189
+
190
+ environment = {
191
+ NIX_REMOTE = "daemon";
192
+ LIBEV_FLAGS = "4"; # go ahead and mandate epoll(2)
193
+ RUST_BACKTRACE = "1";
194
+
195
+ # Note: it's important to set this for nix-store, because it wants to use
196
+ # $HOME in order to use a temporary cache dir. bizarre failures will occur
197
+ # otherwise
198
+ HOME = "/var/lib/hydra/queue-runner";
199
+ };
200
+
201
+ serviceConfig = {
202
+ Type = "notify";
203
+ Restart = "always";
204
+ RestartSec = "5s";
205
+
206
+ ExecStart = lib.escapeShellArgs (
207
+ [
208
+ (lib.getExe cfg.package)
209
+ "--rest-bind"
210
+ "${cfg.rest.address}:${toString cfg.rest.port}"
211
+ "--grpc-bind"
212
+ "${cfg.grpc.address}:${toString cfg.grpc.port}"
213
+ "--config-path"
214
+ "/etc/hydra/queue-runner.toml"
215
+ ]
216
+ ++ lib.optionals (cfg.mtls != null) [
217
+ "--server-cert-path"
218
+ cfg.mtls.serverCertPath
219
+ "--server-key-path"
220
+ cfg.mtls.serverKeyPath
221
+ "--client-ca-cert-path"
222
+ cfg.mtls.clientCaCertPath
223
+ ]
224
+ );
225
+ ExecReload = "${pkgs.util-linux}/bin/kill -HUP $MAINPID";
226
+
227
+ User = "hydra-queue-runner";
228
+ Group = "hydra";
229
+
230
+ StateDirectory = [ "hydra/queue-runner" ];
231
+ StateDirectoryMode = "0700";
232
+ ReadWritePaths = [
233
+ "/nix/var/nix/gcroots/"
234
+ "/run/postgresql/.s.PGSQL.${toString config.services.postgresql.port}"
235
+ "/nix/var/nix/daemon-socket/socket"
236
+ "/var/lib/hydra/build-logs/"
237
+ ];
238
+ ReadOnlyPaths = [ "/nix/" ];
239
+ WorkingDirectory = "/var/lib/hydra/queue-runner";
240
+
241
+ PrivateNetwork = false;
242
+ SystemCallFilter = [
243
+ "@system-service"
244
+ "~@privileged"
245
+ "~@resources"
246
+ ];
247
+
248
+ ProtectSystem = "strict";
249
+ ProtectHome = true;
250
+ PrivateTmp = true;
251
+ PrivateDevices = true;
252
+ ProtectKernelTunables = true;
253
+ ProtectControlGroups = true;
254
+ RestrictSUIDSGID = true;
255
+ PrivateMounts = true;
256
+ RemoveIPC = true;
257
+ UMask = "0022";
258
+
259
+ CapabilityBoundingSet = "";
260
+ NoNewPrivileges = true;
261
+
262
+ ProtectKernelModules = true;
263
+ SystemCallArchitectures = "native";
264
+ ProtectKernelLogs = true;
265
+ ProtectClock = true;
266
+
267
+ RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
268
+
269
+ LockPersonality = true;
270
+ ProtectHostname = true;
271
+ RestrictRealtime = true;
272
+ MemoryDenyWriteExecute = true;
273
+ PrivateUsers = true;
274
+ RestrictNamespaces = true;
275
+ };
276
+ };
277
+
278
+ environment.etc."hydra/queue-runner.toml".source = format.generate "queue-runner.toml" (
279
+ lib.filterAttrsRecursive (_: v: v != null) cfg.settings
280
+ );
281
+ systemd.tmpfiles.rules = [
282
+ "d /nix/var/nix/gcroots/per-user/hydra-queue-runner 0755 hydra-queue-runner hydra -"
283
+ "d /var/lib/hydra/build-logs/ 0755 hydra-queue-runner hydra -"
284
+ ];
285
+
286
+ nix.settings = {
287
+ allowed-users = [ "hydra-queue-runner" ];
288
+ experimental-features = [ "nix-command" ];
289
+ trusted-users = [ "hydra-queue-runner" ];
290
+ };
291
+
292
+ users = {
293
+ groups.hydra = { };
294
+ users.hydra-queue-runner = {
295
+ group = "hydra";
296
+ isSystemUser = true;
297
+ };
298
+ };
299
+ };
300
+}
non-critical-infra/packages/hydra-queue-runner/default.nix
new
+104
@@ -0,0 +1,104 @@
1
+{
2
+ rustPackages,
3
+ fetchFromGitHub,
4
+ pkg-config,
5
+ openssl,
6
+ zlib,
7
+ protobuf,
8
+ lib,
9
+ makeWrapper,
10
+ nixVersions,
11
+ nlohmann_json,
12
+ libsodium,
13
+ boost,
14
+}:
15
+let
16
+ version = "unstable-2025-08-07";
17
+ src = fetchFromGitHub {
18
+ owner = "helsinki-systems";
19
+ repo = "hydra-queue-runner";
20
+ rev = "54b3c9351d2ae10be5c4d1b97cc0f86300cd70ca";
21
+ hash = "sha256-gR2DzWkTykM9GdW3Nf/V8eRv68fl3aO+NW0zNPFSRT0=";
22
+ };
23
+ useFetchCargoVendor = true;
24
+ cargoHash = "sha256-oNUMmFfts4rjBX0k5mzsxpYA2JqgsRu1nMRFf/2rZa8=";
25
+ nativeBuildInputs = [
26
+ pkg-config
27
+ protobuf
28
+ makeWrapper
29
+ ];
30
+ buildInputs = [
31
+ openssl
32
+ zlib
33
+ protobuf
34
+
35
+ nixVersions.nix_2_29
36
+ nlohmann_json
37
+ libsodium
38
+ boost
39
+ ];
40
+ meta = {
41
+ description = "Hydra Queue-Runner implemented in rust";
42
+ homepage = "https://github.com/helsinki-systems/hydra-queue-runner";
43
+ license = [ lib.licenses.gpl3 ];
44
+ maintainers = [ lib.maintainers.conni2461 ];
45
+ platforms = lib.platforms.all;
46
+ };
47
+in
48
+{
49
+ runner = rustPackages.rustPlatform.buildRustPackage (finalAttrs: {
50
+ pname = "hydra-queue-runner";
51
+ inherit version src;
52
+ __structuredAttrs = true;
53
+ strictDeps = true;
54
+
55
+ inherit
56
+ useFetchCargoVendor
57
+ cargoHash
58
+ nativeBuildInputs
59
+ buildInputs
60
+ ;
61
+
62
+ cargoBuildFlags = [
63
+ "-p"
64
+ "queue-runner"
65
+ ];
66
+ cargoTestFlags = finalAttrs.cargoBuildFlags;
67
+
68
+ postInstall = ''
69
+ wrapProgram $out/bin/queue-runner --prefix PATH : ${lib.makeBinPath [ nixVersions.nix_2_29 ]}
70
+ '';
71
+
72
+ meta = meta // {
73
+ mainProgram = "queue-runner";
74
+ };
75
+ });
76
+
77
+ builder = rustPackages.rustPlatform.buildRustPackage (finalAttrs: {
78
+ pname = "hydra-queue-builder";
79
+ inherit src version;
80
+ __structuredAttrs = true;
81
+ strictDeps = true;
82
+
83
+ inherit
84
+ useFetchCargoVendor
85
+ cargoHash
86
+ nativeBuildInputs
87
+ buildInputs
88
+ ;
89
+
90
+ cargoBuildFlags = [
91
+ "-p"
92
+ "builder"
93
+ ];
94
+ cargoTestFlags = finalAttrs.cargoBuildFlags;
95
+
96
+ postInstall = ''
97
+ wrapProgram $out/bin/builder --prefix PATH : ${lib.makeBinPath [ nixVersions.nix_2_29 ]}
98
+ '';
99
+
100
+ meta = meta // {
101
+ mainProgram = "builder";
102
+ };
103
+ });
104
+}
non-critical-infra/secrets/queue-runner-ca.key.staging-hydra
new
+35
@@ -0,0 +1,35 @@
1
+{
2
+ "data": "ENC[AES256_GCM,data:pe1lPpTo2O6CjOwyW3Go673wo4kJJ8O7XGk3M89pcdaoHPr0gdvvsSg8tG98qng4E5vfYnQpzXNFPBjmv9DvFkm3LDqOSmJsNw6Vp4LAIpkxQmuehGjDnsu2WxWC/JlG2Qm+2FS2saxZrfaeHEiZDvPEm1rN3oA=,iv:rrKEmM0PLIS+ur+cjW5tBR3UqOftOi6FTaqrymr6OIg=,tag:zGZtHCxldMKeWoNICBe3+A==,type:str]",
3
+ "sops": {
4
+ "age": [
5
+ {
6
+ "recipient": "age1xj4dl6xdl5ztmetp9axa0epjj922hu6a2gut3rrs5rdc5xv85yjsq5ggpx",
7
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBETllNUWc0YUlEUW9KdmlE\nSnZNdW9kekxxUzJ0ZzBXTkxMWEpOcFhQK25RCi9iejVhTUk4cnQ5VU1rcTBiTGNw\nMXNnS1ducEhTWk14c3d2V1pWdzFQUm8KLS0tIGNXOU9rQmtVRExXZWpYTTlvbk9i\nYlZjUDVyRWZwSHlsWDhzbWZCdXJ2N3MK71/bfgXtdfcS/bJpf7pq0IViBpRPDzc6\n4Hi+E+aZodq6167TrYT26LV5pSKYER+dIvk02FSBvOxCDvk6u6NyCQ==\n-----END AGE ENCRYPTED FILE-----\n"
8
+ },
9
+ {
10
+ "recipient": "age17n64ahe3wesh8l8lj0zylf4nljdmqn28hvqns2g7hgm9mdkhlsvsjuvkxz",
11
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBGWDdPUWk1R2JCMW1pNDRI\nZFp3czA4YUdrekFMLzlFTHJtM083bDBSZUNNCjEwcUlSazBoUnZMM3BsWit1eTB4\nS3VEaFVad1ZRZDBXYk1vaHFKNklPZDQKLS0tIC9ucGpzd3NiRjEvN0dtQUtZZ3pj\nVE1zbHZvQ0R3T0tyL3dnZGU5dDVnMlUKjlH1sgor3H+zHzwAV9cZbdiGbcQo27pf\n7shoRdXedex44lm8+LlYQ9YfkyhZs3mR9/++0JsvijR7o7Lrb9w1gw==\n-----END AGE ENCRYPTED FILE-----\n"
12
+ },
13
+ {
14
+ "recipient": "age1nnm255ah9wa4gpsaq0v023a75lnmlcxszt9lc6az3mtwzxgrucfq45rp7h",
15
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBGSm8xaFBWTU5mdS9weFRG\nbnVkamVVMG1BbDgrZ3pXOVdWMmhJM3d2V2dnClozd0h1elNYSWN5SWZOK2s2WTI1\nTVROTFBCOWM5anJ4endoOWs4cmFjSlEKLS0tIGE4TURtcjFyclg1NEFnRlhiMnZ0\ncWQ3RHIyUnZUSEE5Q1hWaG9kR3k2eDAKJ5JgJzDBTv+6lb29mWhe9B9VtrncXGhG\nQbFqF9+U4Q23A/gHa+FBAqT1dzc7U+IE5WILmQa7wJg29W6A0aVt/A==\n-----END AGE ENCRYPTED FILE-----\n"
16
+ },
17
+ {
18
+ "recipient": "age1j3mkgedmeru63vwww6m44zfw09tg8yw6xdzstaq7ejfkvgcau40qwakm8x",
19
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB3TWRBemFSWk0yR2tJcXNM\nZzNBR3dTODRMa2JraGROTmphTHpjREdGQ2dFCkZudFF4Y05aOEZ2M3doR0NhY1V5\ndmtRV2s5ZVN4NEVmT2ZuNGdmQjhDY1kKLS0tICswZHpsc2RJMGZPc1hnd3FjZGRo\nVTFvdWFPeTlJa0p0RTdBaXlJb3hncDQKmO1/apc3mqJ4CyAWf3eVNlXdUhZCIRZF\nTK0HBh7xg8S/HkPJiBcMCdF/7slQeOLL3lzfeBjnAQ+mg8hoI2YCmA==\n-----END AGE ENCRYPTED FILE-----\n"
20
+ },
21
+ {
22
+ "recipient": "age1jrh8yyq3swjru09s75s4mspu0mphh7h6z54z946raa9wx3pcdegq0x8t4h",
23
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBlMjNQeGdheUVuMmNWSVN2\nekd5SVVkVTNnMVdmRnUwSTFFaDcrSE90bGxZCmJZRFp5NkFYUFdnOVJ4Y1NQZ1pk\nTHlja29waUxlWlF3alJwSXMyY3VDcGsKLS0tIE9LZWJnb1hRcTJBQlA2Z2NWSFhB\ndE9xSEUzVEI2UHVuQUw0cnZ5S052bEUKimqgYE85vdiTS3YV08bD/I3IpM1sPXcD\nEroNwJH8+boHOGZODLQUoezjHkajnIoo/wjK1gELEHlvShAlzNPQuQ==\n-----END AGE ENCRYPTED FILE-----\n"
24
+ },
25
+ {
26
+ "recipient": "age17ez23w2kpxl0gcdx4ehcglkcfcfnv4qz0gq2n8ylxwx4yrtjpvjqxfasua",
27
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBuZXVvSEJ5RFZBRGZCUFNS\nazVxcEpGTmNBaVd2OUVwRnU3Nm9zaUNPOG5zCmFwYkdlUWEweWptVjMxSDY4MERF\nbTNqTmUwSytWRjRiWFFHWmJKZE0waUkKLS0tIDZaNTZVRG5SWjF1Vm9QWm9ERDZ1\nZFBTSkRJVytKaVBlYkZibTRNSmwxZlUKdr9dALaKngENjcRYUa8KRKKfngc/BMqh\ngQrqhE2BxCKffGxsyuyqIozSm+nEw5ihQviWgWU78/XLraAWnubfRg==\n-----END AGE ENCRYPTED FILE-----\n"
28
+ }
29
+ ],
30
+ "lastmodified": "2025-07-31T12:09:59Z",
31
+ "mac": "ENC[AES256_GCM,data:EdssbCd38+X5Sr/qPSewtFgGyT0WFvR+0/ZkzpKGtj/7yS/Q9w0BoyZXbwuMF4R+n2aJ+NTmxPjCz9Ald0ENnXKXJcEHlKtTf9z2h+ft6rrFsBVBlrp3KfHY16EwcfBprvbbCkU6Bvxv5UGFGfJsw5l3jpL45LQQ7z528HiQz6c=,iv:02k7g9Fck1XFBor/TAHZGpgIiH2zPRDHsdRt4rjApeU=,tag:uJJ4J6znugGBQtARL6vwRg==,type:str]",
32
+ "unencrypted_suffix": "_unencrypted",
33
+ "version": "3.10.2"
34
+ }
35
+}
non-critical-infra/secrets/queue-runner-client.key.staging-hydra
new
+35
@@ -0,0 +1,35 @@
1
+{
2
+ "data": "ENC[AES256_GCM,data:mER5O7YO36svhuSk8u5FLgBUkRaFs+k4sBccPqx0JZ5BWPhWDKQwlEKHeNuuMRPwbhtTEoKXFHN7PdcOKG3jtDNZuNuOvupNxeF8By47XpBFRJm7W9BhPdlN4UA8qoDdlWMZLBFjNSSGhV6+wGL/HGao/hpWDn0=,iv:JmAHNp6G4kVjhsLv5BgizEUatt+NbIyz8wi0YVdtN50=,tag:yAN1D0DMvOs0g4715HD6PQ==,type:str]",
3
+ "sops": {
4
+ "age": [
5
+ {
6
+ "recipient": "age1xj4dl6xdl5ztmetp9axa0epjj922hu6a2gut3rrs5rdc5xv85yjsq5ggpx",
7
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBiUEkwL0xvV2trSUFUN1Ny\nNnBLOHhvaVFuNWxuQnE2Yys3MVAycjRCM0QwCmI1M0haRzJhUEw3aURhRmtWUG1C\nMWhpZHJiSnM4RXJvZ09WQWxxN3QyS28KLS0tIFo5Nm15U2hPSkxRUUZpRWdZTVJO\nV2p0QVlVbHV6am1LTTVoQzRLWkloUnMK6mK+TeQKok/XNH+wmGa1N1lVX3ME562o\nEev3kaAGWqz6f4bMacbCkgXmhOEryFiDCgok/TMQ6hSGa3COFXrzmQ==\n-----END AGE ENCRYPTED FILE-----\n"
8
+ },
9
+ {
10
+ "recipient": "age17n64ahe3wesh8l8lj0zylf4nljdmqn28hvqns2g7hgm9mdkhlsvsjuvkxz",
11
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBPcCtST1pMdk1vNFBLRlJN\nd2IvTmUwcGQ2cm5aaXgvQTdoMkFFbnJYVm00CjJmYS95Z2FrMUdrcDJwWDFYWXY0\nNGZkSkZMRDA3NUxjVG1NdExKTjNVM1kKLS0tIEN6eHJlazlRa3NIaUUvSWtTdTYw\nZXpmcXJpY1pwUzkva2hYM1R3THhIM00KiwOB/Twye2mzFzLUiF01DTaqb0OLybSF\njRYHaZ5KWZ756c2DEnnB8TbQsN2JDpfe8pYW7tdgyfqNKaYV/l8nxQ==\n-----END AGE ENCRYPTED FILE-----\n"
12
+ },
13
+ {
14
+ "recipient": "age1nnm255ah9wa4gpsaq0v023a75lnmlcxszt9lc6az3mtwzxgrucfq45rp7h",
15
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB6Q1htRVFycERhRHRSanFt\nTEhaTnIvMG1iYy9MZ0pLLzZqaVN0bVB1ZERNCjhkaVRXaXZoQjl6aUZYWnlvMGdG\nSDh1M09MU2I3aUF2YVgxUTVHZHYxazAKLS0tIFJtUzk1Wk9xazNUK3BJWTJMbGx6\nTzh5SlVBUkFIckQ3b0VYQWlyaGhuMEUKg+bdoltiqfMwrzytk4kwRKqUjS3XyUuN\ngX3ksj9ODZDvbwNXhgBLXkXpmefwUt0k2TJL/fTr4tqTU6hchkg7aA==\n-----END AGE ENCRYPTED FILE-----\n"
16
+ },
17
+ {
18
+ "recipient": "age1j3mkgedmeru63vwww6m44zfw09tg8yw6xdzstaq7ejfkvgcau40qwakm8x",
19
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBqS1pTY0Rzci94Ykd3Wm1t\nVVl1TWlQc2xjdTBBbjZCWGF3bWZXaTlNaWxjCjJ0OFd3bWRTYjF5cnRaSy8zeFFF\nSWd0bkpSbnVyNTZOMU0yR1dVcUtlQlkKLS0tICt2QkdsUDcyZ1J2YjRJRkIyYW5u\naDBPWUEwNkJ5dkxqaGhCcWlNZVNXOEkK6SEQCqKZ0OsWKs6vmG18ikaeSkS7Zo9+\npUc4e/QWsRDOd/frLWzKIo8JujckNpMbbalQfykW7s0xCvGnZ1NYfQ==\n-----END AGE ENCRYPTED FILE-----\n"
20
+ },
21
+ {
22
+ "recipient": "age1jrh8yyq3swjru09s75s4mspu0mphh7h6z54z946raa9wx3pcdegq0x8t4h",
23
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBwdXJ2bHIrdGdCSlRLL3Za\nVWZCUWRXajVmS2JCMkQ2NmZqMkVHcHAyTFc0Cngyd0QzbU9VMEVrOUxsSGVsWWNy\neGRNK3JleDFXN2p0dFYrYktVbzcrSGMKLS0tIFQ4WFc2RTFFNkx3ajUvQWJqWUpV\nUDBiOTFKQ0hIOWsxS2xYM1ptVDBwcGcK41AK30TtmKw9DCPCMnAZXl/C26t3NBNK\n3Sh4wL7yyhKmRUNutq5cnAw8vjzhRsgjJkZGmOuv5qN3s7nFTGdC5A==\n-----END AGE ENCRYPTED FILE-----\n"
24
+ },
25
+ {
26
+ "recipient": "age17ez23w2kpxl0gcdx4ehcglkcfcfnv4qz0gq2n8ylxwx4yrtjpvjqxfasua",
27
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBqNFB6OW1sOHpseEdJSll4\neDlDN0xKQnJPMUFQcnpHaHFURUg4NmhNT3k0CmFJV2xSMnhocnlMQWI5ZThLK2R4\nZE1mRHBGbGM4UmxvalJ5TWpOUW1JR2cKLS0tIEd6UFNFc0E0QVI2bFBRUlFsWHh6\nLy9WYWpTK3E2ZjJEb01rNC84UG1DUTAKv1T3UPMBBYGHdmKCsSCUtBg/7SoQ7RjO\n0PyeOnGlvUUxj4H/z2sPRxuKj2QiqIiGqdSqOoGXNmp3omrQHtVfxg==\n-----END AGE ENCRYPTED FILE-----\n"
28
+ }
29
+ ],
30
+ "lastmodified": "2025-07-31T12:14:02Z",
31
+ "mac": "ENC[AES256_GCM,data:KWe6LDUZtpGR8btMzp4Arb4b3rooS+pGOOs0W0gZYLovh4RdvMSdOHbslIZt3HzNvOWDNz3BM77jdNiSctZpLK6sXxzXB0JH7dq3H9+7cPRGyEIUYRvysjmFF1HHEw0isVkV7mPHNAQBL7y716Gw5plAfyEgCqpknbnQpKMIGmI=,iv:rRfVfr30XfMuAgkeNWq6x3l4LVFArC3X2sPz8dCamfo=,tag:lKKy+PvsuwG99mEu0/OZ7w==,type:str]",
32
+ "unencrypted_suffix": "_unencrypted",
33
+ "version": "3.10.2"
34
+ }
35
+}
non-critical-infra/secrets/queue-runner-server.key.staging-hydra
new
+35
@@ -0,0 +1,35 @@
1
+{
2
+ "data": "ENC[AES256_GCM,data:forqylxAxHHWDqqTG8nxgqnbuyCTtRiEZ+0VA6qYRhlRY7KAYmTM4GK3wDa8dZPBi0e+LXG5aaigyc9FFsl7hHKdtQo84OPHyJOSCZyBYjMg9qlBsy/USqxftzfMjMAxVk/ibAi5LDrNl9Jh/7w74BBtbdF3qiE=,iv:5YbKjIdd+EfVpMGzTzP0VDy0Wev22bRc9IO5e3StpA4=,tag:/jsQItUIschI6B0rs7dwQg==,type:str]",
3
+ "sops": {
4
+ "age": [
5
+ {
6
+ "recipient": "age1xj4dl6xdl5ztmetp9axa0epjj922hu6a2gut3rrs5rdc5xv85yjsq5ggpx",
7
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBuajRobWMzdHhqSVUydlVZ\nanZKY2REQWJ5KzgxNmtwZ0d4Mm1mTWFYYTM4CjhIVG1COTZkbWp3SkxtS3VDeTRB\ndGcxY0hqUk1DeU9CQldkcTUwMys1OTAKLS0tIFBibTB6bWY2ZjRxL0JFUDZmYTJ2\nMG5IclV2T2twa0NhOGtrdXZQeXhqV1UK/9RyMKw8K3AOe8PntM+5BMSSGuWuYdt4\nkDMjS3NH7Ab1tM3O/4b6lxyW2nheBXnhhqbq5tfqOVafpoIqgjZgxg==\n-----END AGE ENCRYPTED FILE-----\n"
8
+ },
9
+ {
10
+ "recipient": "age17n64ahe3wesh8l8lj0zylf4nljdmqn28hvqns2g7hgm9mdkhlsvsjuvkxz",
11
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSArd3ZqdUhGREtLRlpla1Js\nK2JRRG1pYWx2NVNCT3F5dGlBc1EwOVo1Mm44CkNkSXQyK0VYZGYrMW05ZnhmbXFC\nOFpKSVVKZTE5WHkvN0hzVjRqbGV0eGMKLS0tIHJBNXNsSkcyd1EwckRTT2FFNDRk\nK1A5Q0dsZC80NWk3dE0rK2JKWG9GdjgK6exWpfYFkhSVZkU80rnLkHKqkZ6hrAGA\nNhiohmDfflTAurqEKzxPsVMiSWlmVEpKykzMrsE150evlZbj7YB9rw==\n-----END AGE ENCRYPTED FILE-----\n"
12
+ },
13
+ {
14
+ "recipient": "age1nnm255ah9wa4gpsaq0v023a75lnmlcxszt9lc6az3mtwzxgrucfq45rp7h",
15
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBQUjBtZFhER05McTJqNk1V\neVJIMEJLcnBoMVAxazduckhJWm13Y2drcUFVCm9vRlI2ZjJDbDU0Qk5icmI2dVRn\ndUlvbWFmMjZob0ZQclhFOHJ5T25vcXcKLS0tIGNSU3NNOTNFcmZRY3BUWHRYdUpz\nT2g0TlhnSjVuWlpCYTRWN1FUSUE2V2sKxiobZEtFJDOTmxjRcfTS7HwIXOZuySXt\nOxkJoFfhaFRFOIqP6Ai8/9MtYP2UypRzdTBLP6T8iLYbT0jeM2h93Q==\n-----END AGE ENCRYPTED FILE-----\n"
16
+ },
17
+ {
18
+ "recipient": "age1j3mkgedmeru63vwww6m44zfw09tg8yw6xdzstaq7ejfkvgcau40qwakm8x",
19
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAzTlBRb2lsV1ZYZ1htWUJ3\nS3dlQ1QrWXc3QVZFTWlxdzVGSXlNWFZ1aEdFCkpCSFB3WUlKa3ZUeGQ0SzFmZ0xP\nWGYwZk5MM3prMUUwbWovQzk1dGtvS3cKLS0tIC9jRlhLL3BtVyt4WS9rQisvc0Jo\ndjBHMVhGZlRlM3hsKzh2aU90ZzVhZTQKI1QZ9IhpNFC1hO8pl+2kjALVbTKnQjl7\nwsiwg7DUH8j16Cqe+BKqPLwV6wUZNcSgCc4b4kAdCeIme3Qc9VPofQ==\n-----END AGE ENCRYPTED FILE-----\n"
20
+ },
21
+ {
22
+ "recipient": "age1jrh8yyq3swjru09s75s4mspu0mphh7h6z54z946raa9wx3pcdegq0x8t4h",
23
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBBOXc1QklpenBjTGh3NFNS\nZW5vZFdDNHJPWGsrN0MzSU0yaHVxR0tkOEU0CnIwTGxuUUZxTUd4b0YxZ0h6QUVa\nV1FocWJKdlpLaUVJZUNwTi8zTmlDV2cKLS0tIHYzNVYzZHgyVnlLcmJtMmk1aWwy\nTDZBSkJLY001MGxYNFQ1a3hSdG4vaEUKOdJSdnxDBansg5boUQp9xLGFMkQzKDf9\n9D7W+cwqSQEUpSTofP5elJKOsg/tdpiZaiSck8/4EHhQt2/qncgbAg==\n-----END AGE ENCRYPTED FILE-----\n"
24
+ },
25
+ {
26
+ "recipient": "age17ez23w2kpxl0gcdx4ehcglkcfcfnv4qz0gq2n8ylxwx4yrtjpvjqxfasua",
27
+ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBjcmJBbFJHbUJzYnpZWVBQ\nZjNtVTVmaUM2RzRYM1JoL2MrSmp4RFFMWkRFClBTcDdwaEMyMStNcEsrMzcwa2xG\nU083YnUvNStuNXNsOHR0TzB6NWROeVEKLS0tIFc5V0sxN1dUcksrdTFNdUZ4cyt2\nRy9rbFY2dEFZRlZmaitjUVZYZFZpK00KdLhQzJZLO4BMiWaJuXCxn/NDG5EJa/ee\nuNJj+AfwOzLk3M8rAapwAR7O0b9PL0gcU6oDybAnBlMo+UzdH8X9aQ==\n-----END AGE ENCRYPTED FILE-----\n"
28
+ }
29
+ ],
30
+ "lastmodified": "2025-07-31T12:10:09Z",
31
+ "mac": "ENC[AES256_GCM,data:QRLZ7S6CoHaYQ+m0npUo2ISRkke4JvYe/cN5nBM7ngIdKQ+yyLK1d8ucG3YwB6HaVZXDM4F0BAKkwl3VXTDujKk24BQhb4G50EL91UTcaQQ4kIOdaSVh17/D6cXV1Han8hSrxrsXQ9vvyR9EmCVbjZMIP+TyyTbdAkFfHDch2Fk=,iv:Wm7rVVZRUjUeb/SU2GF5TnOcNawf8rsndlReEUtrGeg=,tag:PsL1RufQyx+7wayK0IOSlg==,type:str]",
32
+ "unencrypted_suffix": "_unencrypted",
33
+ "version": "3.10.2"
34
+ }
35
+}