ci-queue 0.99.0 → 0.100.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 12bdc1e58974c1c3fca314133800774ca993f23fd01440931443d080cc23ee6f
4
- data.tar.gz: 6e4f28118f8281ff3959f631e2e8b7c6fc8fbc47d0b1692f533e866edbfce916
3
+ metadata.gz: 64510328261d26c0b3299aa0e1bb4bbbb2fdd4f784293a304cec028527d25e8b
4
+ data.tar.gz: 8cf5e99fcf74935b71a2ee6814cfc7565b03b1b314af8380f999f4228400417c
5
5
  SHA512:
6
- metadata.gz: 88f858df9c99323f322479bd0f20f41d28137d45ee216a45f5f49317128bbfbe5312f5becee71ef559e03e0ea377ddf8e59e1e7ac177aa735b3c2b024e48f7e3
7
- data.tar.gz: e8738af5e5031e7fbe2c5118ea9c08c9b9e5943078d8b0ead60d6b72ca9c2cb29a3dfe847f03d83b8824fd7cd2e6b6b323a35e05904710bf9774626ebfdfb5f5
6
+ metadata.gz: c044a9cafe05602f22debf2ea91b5cc63c42dabc67f8689b88430c7c34ece68da7bf7ad03b62036648073c8225e3588382bce588f486359b339a65aa62e71951
7
+ data.tar.gz: 5d9f475df1260d6cc6cd04d1f1ceec0ca28e7b12e9d5d0b0931ac7b18a2e864a5a2386f102f878a8392722dbb535e260b8661e5ccc5722097ee8d8e866d977dc
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ci-queue (0.99.0)
4
+ ci-queue (0.100.0)
5
5
  logger
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -260,3 +260,17 @@ After merging changes to `main`, follow these steps to release and propagate the
260
260
  `ci-queue` expects the Redis server to have an [eviction policy](https://redis.io/docs/manual/eviction/#eviction-policies) of `allkeys-lru`.
261
261
 
262
262
  You can also use `--redis-ttl` to set a custom expiration time for all CI Queue keys, this defaults to 8 hours (28,800 seconds)
263
+
264
+ ## Redis over TLS
265
+
266
+ Use a `rediss://` queue URL to connect to Redis over TLS. The server certificate and hostname are verified using the system's trusted CAs.
267
+
268
+ > **Upgrading from 0.99.0 or earlier:** those versions did not verify certificates for `rediss://` URLs. If your Redis presents a self-signed or otherwise untrusted certificate, connections now fail with `certificate verify failed`. Workers treat this like an unreachable Redis: they report `Ran 0 tests` and exit successfully, and the error only surfaces when `report` fails with `Redis::CannotConnectError`. Trust the issuing CA or opt out as described below.
269
+
270
+ If your Redis server presents a certificate signed by a private CA, point OpenSSL at that CA (for example with `SSL_CERT_FILE=/path/to/ca.pem`).
271
+
272
+ If your hosted Redis only offers a self-signed certificate that can't be verified, you can opt out of verification with `CI_QUEUE_REDIS_SSL_VERIFY=0` (or `CI::Queue::Configuration#redis_ssl_verify = false`). The connection stays encrypted, but the server isn't authenticated, so anyone who can intercept traffic between your CI workers and Redis can impersonate the server and read the credentials in the queue URL. Only use this when you accept that risk.
273
+
274
+ | Environment variable | Description |
275
+ |---|---|
276
+ | `CI_QUEUE_REDIS_SSL_VERIFY=0` | Disable TLS certificate verification for `rediss://` connections. Defaults to enabled. No CLI equivalent. |
data/ci-queue.gemspec CHANGED
@@ -3,10 +3,11 @@
3
3
  lib = File.expand_path('../lib', __FILE__)
4
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
5
  require 'ci/queue/version'
6
- require 'pathname'
7
6
 
8
- dir = Pathname.new(CI::Queue::RELEASE_SCRIPTS_ROOT).relative_path_from(Pathname.new(__dir__).realpath)
9
- lua_scripts = Dir[dir.join('*.lua').to_s]
7
+ # Release Lua scripts are gitignored copies made by `rake scripts:copy`, so
8
+ # `git ls-files` misses them. Glob without touching CI::Queue constants:
9
+ # Dependabot evaluates this file with the `require` above rescued away.
10
+ lua_scripts = Dir.glob('lib/ci/queue/redis/*.lua', base: __dir__)
10
11
 
11
12
  Gem::Specification.new do |spec|
12
13
  spec.name = 'ci-queue'
@@ -11,6 +11,7 @@ module CI
11
11
  attr_writer :lazy_load_streaming_timeout
12
12
  attr_accessor :lazy_load_test_helpers
13
13
  attr_accessor :skip_stale_tests
14
+ attr_accessor :redis_ssl_verify
14
15
  attr_reader :circuit_breakers
15
16
  attr_writer :seed, :build_id
16
17
  attr_writer :queue_init_timeout, :report_timeout, :inactive_workers_timeout
@@ -34,6 +35,7 @@ module CI
34
35
  lazy_load_streaming_timeout: (env['CI_QUEUE_LAZY_LOAD_STREAM_TIMEOUT'] || env['CI_QUEUE_STREAM_TIMEOUT'])&.to_i,
35
36
  lazy_load_test_helpers: env['CI_QUEUE_LAZY_LOAD_TEST_HELPERS'] || env['CI_QUEUE_TEST_HELPERS'],
36
37
  skip_stale_tests: %w(1 true).include?(env['CI_QUEUE_SKIP_STALE_TESTS']&.strip&.downcase),
38
+ redis_ssl_verify: !%w(0 false).include?(env['CI_QUEUE_REDIS_SSL_VERIFY']&.strip&.downcase),
37
39
  )
38
40
  end
39
41
 
@@ -60,7 +62,7 @@ module CI
60
62
  queue_init_timeout: nil, redis_ttl: 8 * 60 * 60, report_timeout: nil, inactive_workers_timeout: nil,
61
63
  export_flaky_tests_file: nil, warnings_file: nil, debug_log: nil, max_missed_heartbeat_seconds: nil, heartbeat_max_test_duration: nil,
62
64
  lazy_load: false, lazy_load_stream_batch_size: nil, lazy_load_streaming_timeout: nil, lazy_load_test_helpers: nil,
63
- skip_stale_tests: false)
65
+ skip_stale_tests: false, redis_ssl_verify: true)
64
66
  @build_id = build_id
65
67
  @circuit_breakers = [CircuitBreaker::Disabled]
66
68
  @failure_file = failure_file
@@ -94,6 +96,7 @@ module CI
94
96
  @lazy_load_streaming_timeout = lazy_load_streaming_timeout
95
97
  @lazy_load_test_helpers = lazy_load_test_helpers
96
98
  @skip_stale_tests = skip_stale_tests
99
+ @redis_ssl_verify = redis_ssl_verify
97
100
  end
98
101
 
99
102
  def lazy_load_test_helper_paths
@@ -41,19 +41,33 @@ module CI
41
41
  # it makes sense to retry for a while before giving up.
42
42
  reconnect_attempts: reconnect_attempts,
43
43
  middlewares: custom_middlewares,
44
- # Hosted Redis servers use self signed certificates
45
- # (because they do not own the domain they're running on such as compute-1.amazonaws.com)
46
- # therefore a full SSL connection verification will fail.
47
- # ci-queue should not contain any sensitive data, so we can just disable the verification.
48
- ssl_params: { verify_mode: OpenSSL::SSL::VERIFY_NONE },
44
+ ssl_params: self.class.redis_ssl_params(ssl_verify: redis_ssl_verify?),
49
45
  custom: custom_config,
50
46
  timeout: DEFAULT_TIMEOUT,
51
47
  )
52
48
  else
53
- @redis = ::Redis.new(url: redis_url, timeout: DEFAULT_TIMEOUT)
49
+ @redis = ::Redis.new(
50
+ url: redis_url,
51
+ timeout: DEFAULT_TIMEOUT,
52
+ ssl_params: self.class.redis_ssl_params(ssl_verify: redis_ssl_verify?),
53
+ )
54
54
  end
55
55
  end
56
56
 
57
+ # TLS (`rediss://`) connections verify the server certificate and hostname
58
+ # by default. Some hosted Redis providers present self-signed certificates;
59
+ # those deployments can either trust the issuing CA (e.g. via `SSL_CERT_FILE`)
60
+ # or explicitly opt out of verification with `CI_QUEUE_REDIS_SSL_VERIFY=0`.
61
+ def self.redis_ssl_params(ssl_verify:)
62
+ ssl_verify ? {} : { verify_mode: OpenSSL::SSL::VERIFY_NONE }
63
+ end
64
+
65
+ def redis_ssl_verify?
66
+ return true unless @config.respond_to?(:redis_ssl_verify)
67
+
68
+ @config.redis_ssl_verify != false
69
+ end
70
+
57
71
  def reconnect_attempts
58
72
  return [] if ENV["CI_QUEUE_DISABLE_RECONNECT_ATTEMPTS"]
59
73
 
@@ -271,8 +285,9 @@ module CI
271
285
  # on every heartbeat, which fires once per running test per worker.
272
286
  TICK_COMMAND = 'tick!'.freeze
273
287
 
274
- def initialize(redis_url, zset_key, owners_key, leases_key)
288
+ def initialize(redis_url, zset_key, owners_key, leases_key, ssl_verify: true)
275
289
  @redis_url = redis_url
290
+ @ssl_verify = ssl_verify
276
291
  @zset_key = zset_key
277
292
  @owners_key = owners_key
278
293
  @leases_key = leases_key
@@ -283,6 +298,7 @@ module CI
283
298
  ready_pipe, child_write = IO.pipe
284
299
  @pipe.binmode
285
300
  @pid = Process.spawn(
301
+ { 'CI_QUEUE_REDIS_SSL_VERIFY' => @ssl_verify ? '1' : '0' },
286
302
  RbConfig.ruby,
287
303
  ::File.join(__dir__, "monitor.rb"),
288
304
  @redis_url,
@@ -380,6 +396,7 @@ module CI
380
396
  key('running'),
381
397
  key('owners'),
382
398
  key('leases'),
399
+ ssl_verify: redis_ssl_verify?,
383
400
  )
384
401
  end
385
402
 
@@ -3,6 +3,7 @@
3
3
  # frozen_string_literal: true
4
4
 
5
5
  require 'logger'
6
+ require 'openssl'
6
7
  require 'redis'
7
8
  require 'json'
8
9
 
@@ -18,7 +19,11 @@ module CI
18
19
  @owners_key = owners_key
19
20
  @leases_key = leases_key
20
21
  @logger = logger
21
- @redis = ::Redis.new(url: redis_url, reconnect_attempts: [0, 0, 0.1, 0.5, 1, 3, 5])
22
+ @redis = ::Redis.new(
23
+ url: redis_url,
24
+ reconnect_attempts: [0, 0, 0.1, 0.5, 1, 3, 5],
25
+ ssl_params: ssl_params,
26
+ )
22
27
  @shutdown = false
23
28
  @pipe = pipe
24
29
  @self_pipe_reader, @self_pipe_writer = IO.pipe
@@ -30,6 +35,17 @@ module CI
30
35
  end
31
36
  end
32
37
 
38
+ # Mirrors CI::Queue::Redis::Base.redis_ssl_params. This script runs as a
39
+ # standalone subprocess that doesn't load ci-queue or its Configuration,
40
+ # so the parent passes the setting through the environment.
41
+ def ssl_params
42
+ if %w(0 false).include?(ENV['CI_QUEUE_REDIS_SSL_VERIFY']&.strip&.downcase)
43
+ { verify_mode: OpenSSL::SSL::VERIFY_NONE }
44
+ else
45
+ {}
46
+ end
47
+ end
48
+
33
49
  def soft_signal(sig)
34
50
  @queue << sig
35
51
  @self_pipe_writer << '.'
@@ -2,7 +2,7 @@
2
2
 
3
3
  module CI
4
4
  module Queue
5
- VERSION = '0.99.0'
5
+ VERSION = '0.100.0'
6
6
  DEV_SCRIPTS_ROOT = ::File.expand_path('../../../../../redis', __FILE__)
7
7
  RELEASE_SCRIPTS_ROOT = ::File.expand_path('../redis', __FILE__)
8
8
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ci-queue
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.99.0
4
+ version: 0.100.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jean Boussier