kettle-dev 2.5.11 → 2.5.13

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.
@@ -0,0 +1,204 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rbconfig"
4
+ require "shellwords"
5
+ require "time"
6
+
7
+ module Kettle
8
+ module Dev
9
+ class ReleaseSecretsDoctor
10
+ DEFAULT_SLEEP_SECONDS = 30.0
11
+ DEFAULT_KEEPALIVE_SECONDS = 0.0
12
+ DEFAULT_PROVIDER = "op"
13
+ DEFAULT_SHAPE = "same-process"
14
+ CHILD_SHAPE = "same-process"
15
+ SHAPES = %w[same-process child-process parent-child thread bundler-child env-reset-child].freeze
16
+ BUNDLER_ENV_UNSETS = %w[
17
+ BUNDLE_BIN_PATH
18
+ BUNDLE_FROZEN
19
+ BUNDLE_GEMFILE
20
+ BUNDLE_LOCKFILE
21
+ BUNDLER_SETUP
22
+ BUNDLER_VERSION
23
+ RUBYLIB
24
+ RUBYOPT
25
+ ].freeze
26
+
27
+ def self.options_from_env(env = ENV)
28
+ {
29
+ provider: env.fetch("KETTLE_RELEASE_SECRETS_PROVIDER", DEFAULT_PROVIDER),
30
+ sleep_seconds: Float(env.fetch("KETTLE_RELEASE_SECRETS_DOCTOR_SLEEP", DEFAULT_SLEEP_SECONDS.to_s)),
31
+ keepalive_seconds: Float(env.fetch("KETTLE_RELEASE_SECRETS_DOCTOR_KEEPALIVE", DEFAULT_KEEPALIVE_SECONDS.to_s)),
32
+ shape: env.fetch("KETTLE_RELEASE_SECRETS_DOCTOR_SHAPE", DEFAULT_SHAPE),
33
+ otp: false
34
+ }
35
+ end
36
+
37
+ def initialize(options:, program_name:, output: $stdout, system_runner: Kernel)
38
+ @options = normalize_options(options)
39
+ @program_name = program_name
40
+ @output = output
41
+ @system_runner = system_runner
42
+ end
43
+
44
+ def run
45
+ case options.fetch(:shape)
46
+ when "same-process"
47
+ run_same_process(options)
48
+ when "child-process"
49
+ run_child_process(options)
50
+ when "parent-child"
51
+ run_parent_child(options)
52
+ when "thread"
53
+ run_thread(options)
54
+ when "bundler-child"
55
+ run_bundler_child(options)
56
+ when "env-reset-child"
57
+ run_env_reset_child(options)
58
+ else
59
+ raise Kettle::Dev::Error, "unknown shape #{options.fetch(:shape).inspect}; expected #{SHAPES.join(", ")}"
60
+ end
61
+ end
62
+
63
+ def child_env(shape:, options: self.options)
64
+ env = {
65
+ "KETTLE_RELEASE_SECRETS_PROVIDER" => options.fetch(:provider),
66
+ "KETTLE_RELEASE_SECRETS_DOCTOR_SHAPE" => shape,
67
+ "KETTLE_RELEASE_SECRETS_DOCTOR_SLEEP" => options.fetch(:sleep_seconds).to_s,
68
+ "KETTLE_RELEASE_SECRETS_DOCTOR_KEEPALIVE" => options.fetch(:keepalive_seconds).to_s
69
+ }
70
+ env["KETTLE_RELEASE_SECRETS_DOCTOR_CHILD"] = "true"
71
+ env
72
+ end
73
+
74
+ def child_args(otp: options.fetch(:otp))
75
+ args = [RbConfig.ruby, program_name]
76
+ args << "--otp" if otp
77
+ args
78
+ end
79
+
80
+ def bundler_child_args(otp: options.fetch(:otp))
81
+ args = ["bundle", "exec", RbConfig.ruby, program_name]
82
+ args << "--otp" if otp
83
+ args
84
+ end
85
+
86
+ private
87
+
88
+ attr_reader :options, :program_name, :output, :system_runner
89
+
90
+ def normalize_options(raw_options)
91
+ {
92
+ provider: raw_options.fetch(:provider, DEFAULT_PROVIDER).to_s,
93
+ sleep_seconds: Float(raw_options.fetch(:sleep_seconds, DEFAULT_SLEEP_SECONDS)),
94
+ keepalive_seconds: Float(raw_options.fetch(:keepalive_seconds, DEFAULT_KEEPALIVE_SECONDS)),
95
+ shape: raw_options.fetch(:shape, DEFAULT_SHAPE).to_s,
96
+ otp: !!raw_options.fetch(:otp, false)
97
+ }
98
+ end
99
+
100
+ def provider_for(current_options)
101
+ Kettle::Dev::ReleaseSecrets::Factory.build(provider_name: current_options.fetch(:provider))
102
+ end
103
+
104
+ def run_same_process(current_options)
105
+ provider = provider_for(current_options)
106
+ output.puts("[#{timestamp}] initial keepalive")
107
+ provider.keepalive!
108
+ wait_with_keepalive(provider, current_options)
109
+ output.puts("[#{timestamp}] final keepalive")
110
+ provider.keepalive!
111
+ run_otp_lookup(provider) if current_options.fetch(:otp)
112
+ true
113
+ end
114
+
115
+ def run_parent_child(current_options)
116
+ provider = provider_for(current_options)
117
+ output.puts("[#{timestamp}] parent initial keepalive")
118
+ provider.keepalive!
119
+ wait_with_keepalive(provider, current_options)
120
+ output.puts("[#{timestamp}] parent spawning child after keepalive")
121
+ run_child_process(current_options)
122
+ end
123
+
124
+ def run_child_process(current_options)
125
+ env = child_env(shape: CHILD_SHAPE, options: current_options)
126
+ args = child_args(otp: current_options.fetch(:otp))
127
+ output.puts("[#{timestamp}] spawning child: #{args.shelljoin}")
128
+ run_system(env, args)
129
+ end
130
+
131
+ def run_bundler_child(current_options)
132
+ env = child_env(shape: CHILD_SHAPE, options: current_options)
133
+ args = bundler_child_args(otp: current_options.fetch(:otp))
134
+ output.puts("[#{timestamp}] spawning bundler child: #{args.shelljoin}")
135
+ run_system(env, args)
136
+ end
137
+
138
+ def run_env_reset_child(current_options)
139
+ env = child_env(shape: CHILD_SHAPE, options: current_options)
140
+ BUNDLER_ENV_UNSETS.each { |key| env[key] = nil }
141
+ args = child_args(otp: current_options.fetch(:otp))
142
+ output.puts("[#{timestamp}] spawning env-reset child: #{args.shelljoin}")
143
+ run_system(env, args)
144
+ end
145
+
146
+ def run_thread(current_options)
147
+ error = nil
148
+ # rubocop:disable ThreadSafety/NewThread -- this doctor intentionally probes threaded secret-provider behavior.
149
+ thread = Thread.new do
150
+ begin
151
+ run_same_process(current_options)
152
+ rescue => e
153
+ error = e
154
+ end
155
+ end
156
+ # rubocop:enable ThreadSafety/NewThread
157
+ thread.join
158
+ raise error if error
159
+
160
+ true
161
+ end
162
+
163
+ def run_system(env, args)
164
+ success = system_runner.system(env, *args)
165
+ raise Kettle::Dev::Error, "child shape failed: #{args.shelljoin}" unless success
166
+
167
+ true
168
+ end
169
+
170
+ def wait_with_keepalive(provider, current_options)
171
+ sleep_seconds = current_options.fetch(:sleep_seconds)
172
+ keepalive_seconds = current_options.fetch(:keepalive_seconds)
173
+ deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + sleep_seconds
174
+ if keepalive_seconds <= 0
175
+ output.puts("[#{timestamp}] sleeping #{sleep_seconds}s without keepalive")
176
+ sleep(sleep_seconds)
177
+ return
178
+ end
179
+
180
+ output.puts("[#{timestamp}] sleeping #{sleep_seconds}s with #{keepalive_seconds}s keepalive")
181
+ loop do
182
+ remaining = deadline - Process.clock_gettime(Process::CLOCK_MONOTONIC)
183
+ break if remaining <= 0
184
+
185
+ sleep([remaining, keepalive_seconds].min)
186
+ break if Process.clock_gettime(Process::CLOCK_MONOTONIC) >= deadline
187
+
188
+ output.puts("[#{timestamp}] keepalive")
189
+ provider.keepalive!
190
+ end
191
+ end
192
+
193
+ def run_otp_lookup(provider)
194
+ output.puts("[#{timestamp}] OTP lookup")
195
+ otp = provider.rubygems_otp
196
+ output.puts("[#{timestamp}] OTP lookup returned #{otp.to_s.empty? ? "empty" : "#{otp.length} chars"}")
197
+ end
198
+
199
+ def timestamp
200
+ Time.now.iso8601
201
+ end
202
+ end
203
+ end
204
+ end
@@ -5,7 +5,7 @@ module Kettle
5
5
  # Version namespace for this gem.
6
6
  module Version
7
7
  # Current gem version.
8
- VERSION = "2.5.11"
8
+ VERSION = "2.5.13"
9
9
  end
10
10
  # Current gem version exposed at the traditional constant location.
11
11
  VERSION = Version::VERSION # Traditional Constant Location
data/lib/kettle/dev.rb CHANGED
@@ -46,8 +46,10 @@ module Kettle
46
46
  autoload :LockfileReset, "kettle/dev/lockfile_reset"
47
47
  autoload :ReadmeBackers, "kettle/dev/readme_backers"
48
48
  autoload :OpenCollectiveConfig, "kettle/dev/open_collective_config"
49
+ autoload :ReleaseNotifier, "kettle/dev/release_notifier"
49
50
  autoload :ReleaseCLI, "kettle/dev/release_cli"
50
51
  autoload :ReleaseSecrets, "kettle/dev/release_secrets"
52
+ autoload :ReleaseSecretsDoctor, "kettle/dev/release_secrets_doctor"
51
53
  autoload :ResetCLI, "kettle/dev/reset_cli"
52
54
  autoload :PreReleaseCLI, "kettle/dev/pre_release_cli"
53
55
  autoload :Version, "kettle/dev/version"
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kettle-dev
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.5.11
4
+ version: 2.5.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter H. Boling
@@ -80,7 +80,7 @@ dependencies:
80
80
  version: '0.1'
81
81
  - - ">="
82
82
  - !ruby/object:Gem::Version
83
- version: 0.1.3
83
+ version: 0.1.9
84
84
  type: :runtime
85
85
  prerelease: false
86
86
  version_requirements: !ruby/object:Gem::Requirement
@@ -90,7 +90,7 @@ dependencies:
90
90
  version: '0.1'
91
91
  - - ">="
92
92
  - !ruby/object:Gem::Version
93
- version: 0.1.3
93
+ version: 0.1.9
94
94
  - !ruby/object:Gem::Dependency
95
95
  name: kettle-rb
96
96
  requirement: !ruby/object:Gem::Requirement
@@ -327,6 +327,7 @@ executables:
327
327
  - kettle-pre-release
328
328
  - kettle-readme-backers
329
329
  - kettle-release
330
+ - kettle-release-secrets-doctor
330
331
  - kettle-reset
331
332
  extensions: []
332
333
  extra_rdoc_files: []
@@ -346,6 +347,7 @@ files:
346
347
  - exe/kettle-pre-release
347
348
  - exe/kettle-readme-backers
348
349
  - exe/kettle-release
350
+ - exe/kettle-release-secrets-doctor
349
351
  - exe/kettle-reset
350
352
  - lib/kettle-dev.rb
351
353
  - lib/kettle/dev.rb
@@ -381,7 +383,9 @@ files:
381
383
  - lib/kettle/dev/rakelib/yard.rake
382
384
  - lib/kettle/dev/readme_backers.rb
383
385
  - lib/kettle/dev/release_cli.rb
386
+ - lib/kettle/dev/release_notifier.rb
384
387
  - lib/kettle/dev/release_secrets.rb
388
+ - lib/kettle/dev/release_secrets_doctor.rb
385
389
  - lib/kettle/dev/reset_cli.rb
386
390
  - lib/kettle/dev/ruby_gems_versions.rb
387
391
  - lib/kettle/dev/tasks.rb
@@ -397,10 +401,10 @@ licenses:
397
401
  - AGPL-3.0-only
398
402
  metadata:
399
403
  homepage_uri: https://kettle-dev.galtzo.com
400
- source_code_uri: https://github.com/kettle-dev/kettle-dev/tree/v2.5.11
401
- changelog_uri: https://github.com/kettle-dev/kettle-dev/blob/v2.5.11/CHANGELOG.md
404
+ source_code_uri: https://github.com/kettle-dev/kettle-dev/tree/v2.5.13
405
+ changelog_uri: https://github.com/kettle-dev/kettle-dev/blob/v2.5.13/CHANGELOG.md
402
406
  bug_tracker_uri: https://github.com/kettle-dev/kettle-dev/issues
403
- documentation_uri: https://www.rubydoc.info/gems/kettle-dev/2.5.11
407
+ documentation_uri: https://www.rubydoc.info/gems/kettle-dev/2.5.13
404
408
  funding_uri: https://github.com/sponsors/pboling
405
409
  wiki_uri: https://github.com/kettle-dev/kettle-dev/wiki
406
410
  news_uri: https://www.railsbling.com/tags/kettle-dev
metadata.gz.sig CHANGED
Binary file