kettle-dev 3.0.0 → 3.0.2

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: c7cdd1aace2e06deda5e6bb04aa3b2e6ef67408f0521c8d0ed6a8fa27fad23be
4
- data.tar.gz: e23d202928cd64875dffdb94bb426e0925e2033a7b07ba36b154eba7c83175d8
3
+ metadata.gz: ac5e19991ef314add0cbb6f8c764a0389df6003ea291e5ea08bb76bf32c2786a
4
+ data.tar.gz: 894c0f1521ec987771056394037f3aa2108634bea11830c47f630b43b65727e7
5
5
  SHA512:
6
- metadata.gz: a6c052d533011b2e59762247ee8cb7d8f794e2383720dc7d589beb1643e8086451f5f2922f5b6f77b3d46cebb4f657c07d290ab3c0146e99e2a9196149ce1002
7
- data.tar.gz: 6a38aaf07275a14e588d8e03ab35f8c208755a78c5ac222328688fea61eafde8770bd826abedc8ae91742723dcf69ae09b97782a9eec97e75ebeb380422e6ba2
6
+ metadata.gz: 2bbb2b78730584bfdddbf66664679393ec7c282ea8e24130b01019bc4e61c48da2d4be751d354679c0a76f6ac4ed23a28bfcf60efae081468ffa98cfbe66dfb5
7
+ data.tar.gz: cc6156801f9ef0b6cd6e39ee614b63729acff1862e83cd4390319a98a6978ef06e148d82c255beb38a0d68a09531e435a4d57c7f315a9e4f4cb1cd929b16edff
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -30,6 +30,36 @@ Please file a bug if you notice a violation of semantic versioning.
30
30
 
31
31
  ### Security
32
32
 
33
+ ## [3.0.2] - 2026-08-10
34
+
35
+ - TAG: [v3.0.2][3.0.2t]
36
+ - COVERAGE: 91.56% -- 5629/6148 lines in 47 files
37
+ - BRANCH COVERAGE: 76.14% -- 2128/2795 branches in 47 files
38
+ - 51.00% documented
39
+
40
+ ### Fixed
41
+
42
+ - Stop polling 1Password during release monitoring and support family-owned release secret brokers.
43
+
44
+ - Allow pre-release GitHub Actions pin validation to use the explicitly requested persistent cache when live TLS access is unavailable.
45
+
46
+ - Detect locally installed unreleased workspace gems through an unbundled RubyGems probe during release lockfile normalization.
47
+
48
+ - Isolate standalone kettle-changelog coverage and tests from family release orchestration environment.
49
+
50
+ ## [3.0.1] - 2026-08-10
51
+
52
+ - TAG: [v3.0.1][3.0.1t]
53
+ - COVERAGE: 91.87% -- 5602/6098 lines in 47 files
54
+ - BRANCH COVERAGE: 76.29% -- 2117/2775 branches in 47 files
55
+ - 50.64% documented
56
+
57
+ ### Fixed
58
+
59
+ - Run 1Password authorization keepalives through the interactive terminal so release prompts remain visible.
60
+
61
+ - Re-normalize release lockfiles after release tasks before commit and CI validation.
62
+
33
63
  ## [3.0.0] - 2026-08-09
34
64
 
35
65
  - TAG: [v3.0.0][3.0.0t]
@@ -3401,7 +3431,11 @@ Please file a bug if you notice a violation of semantic versioning.
3401
3431
  - Selecting will run the selected workflow via `act`
3402
3432
  - This may move to its own gem in the future.
3403
3433
 
3404
- [Unreleased]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.0...HEAD
3434
+ [Unreleased]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.2...HEAD
3435
+ [3.0.2]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.1...v3.0.2
3436
+ [3.0.2t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v3.0.2
3437
+ [3.0.1]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.0...v3.0.1
3438
+ [3.0.1t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v3.0.1
3405
3439
  [3.0.0]: https://github.com/kettle-dev/kettle-dev/compare/v2.5.28...v3.0.0
3406
3440
  [3.0.0t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v3.0.0
3407
3441
  [2.5.28]: https://github.com/kettle-dev/kettle-dev/compare/v2.5.27...v2.5.28
data/README.md CHANGED
@@ -1007,7 +1007,7 @@ Thanks for RTFM. ☺️
1007
1007
  [📌gitmoji]: https://gitmoji.dev
1008
1008
  [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
1009
1009
  [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
1010
- [🧮kloc-img]: https://img.shields.io/badge/KLOC-6.069-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1010
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-6.148-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1011
1011
  [🔐security]: https://github.com/kettle-dev/kettle-dev/blob/main/SECURITY.md
1012
1012
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
1013
1013
  [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
@@ -59,6 +59,10 @@ parser = OptionParser.new do |opts|
59
59
  puts " KETTLE_IMAGE_URL_CACHE=/path/to/cache.json Use a custom cache path"
60
60
  puts " KETTLE_IMAGE_URL_CACHE=false Disable the image URL cache"
61
61
  puts " KETTLE_IMAGE_URL_CACHE_REFRESH=true Ignore cached successes and refresh"
62
+ puts
63
+ puts "GitHub Actions pin cache:"
64
+ puts " Live cache validation is the default and refreshes stale entries from GitHub."
65
+ puts " KETTLE_PRE_RELEASE_GHA_SHA_PINS_OFFLINE=true Trust the persistent pin cache without network access"
62
66
  exit(0)
63
67
  end
64
68
  end
@@ -1,39 +1,54 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "open3"
4
+ require "shellwords"
4
5
 
5
6
  module Kettle
6
7
  module Dev
7
8
  class InteractiveReleaseCommand
8
- def initialize(secrets_provider:, input: $stdin, output: $stdout, error: $stderr, secret_event_handler: nil)
9
+ def initialize(secrets_provider:, input: $stdin, output: $stdout, error: $stderr, secret_event_handler: nil, forward_stdin: false)
9
10
  @secrets_provider = secrets_provider
10
11
  @input = input
11
12
  @output = output
12
13
  @error = error
13
14
  @secret_event_handler = secret_event_handler
15
+ @forward_stdin = forward_stdin
14
16
  @gem_signing_passphrase = nil
15
17
  end
16
18
 
17
19
  def call(env, cmd)
18
- return call_with_pty(env, cmd) if pty_available?
20
+ call_argv(env, Shellwords.split(cmd.to_s))
21
+ end
22
+
23
+ def call_argv(env, argv)
24
+ return call_with_pty(env, argv) if pty_available?
19
25
 
20
- call_with_open3(env, cmd)
26
+ call_with_open3(env, argv)
21
27
  end
22
28
 
23
29
  private
24
30
 
25
31
  attr_reader :secrets_provider, :secret_event_handler
26
32
 
27
- def call_with_pty(env, cmd)
33
+ def call_with_pty(env, argv)
28
34
  stdout_str = +""
35
+ prompt_buffer = +""
29
36
  status = nil
30
- PTY.spawn(env, cmd) do |output, input, pid|
37
+ PTY.spawn(env, *argv) do |output, input, pid|
31
38
  begin
32
39
  loop do
33
- chunk = output.readpartial(1024)
34
- stdout_str << chunk
35
- @output.print(chunk)
36
- handle_prompt(input, chunk)
40
+ readers = [output]
41
+ readers << @input if @forward_stdin && @input.tty?
42
+ IO.select(readers).first.each do |reader|
43
+ if reader.equal?(@input)
44
+ input.write(@input.readpartial(1024))
45
+ else
46
+ chunk = output.readpartial(1024)
47
+ stdout_str << chunk
48
+ @output.print(chunk)
49
+ prompt_buffer = handle_prompt(input, chunk, prompt_buffer: prompt_buffer)
50
+ end
51
+ end
37
52
  end
38
53
  rescue Errno::EIO
39
54
  # PTY raises EIO when the child process exits after closing the slave.
@@ -47,27 +62,33 @@ module Kettle
47
62
  [stdout_str, "", status]
48
63
  end
49
64
 
50
- def call_with_open3(env, cmd)
65
+ def call_with_open3(env, argv)
51
66
  stdout_str = +""
52
67
  stderr_str = +""
68
+ prompt_buffer = +""
53
69
  status = nil
54
- Open3.popen3(env, cmd) do |input, output, error, wait_thread|
70
+ Open3.popen3(env, *argv) do |input, output, error, wait_thread|
55
71
  readers = [output, error]
72
+ readers << @input if @forward_stdin && @input.tty?
56
73
  until readers.empty?
57
74
  ready = IO.select(readers)
58
75
  ready.first.each do |reader|
59
- begin
60
- chunk = reader.readpartial(1024)
61
- if reader.equal?(output)
62
- stdout_str << chunk
63
- @output.print(chunk)
64
- else
65
- stderr_str << chunk
66
- @error.print(chunk)
76
+ if reader.equal?(@input)
77
+ input.write(@input.readpartial(1024))
78
+ else
79
+ begin
80
+ chunk = reader.readpartial(1024)
81
+ if reader.equal?(output)
82
+ stdout_str << chunk
83
+ @output.print(chunk)
84
+ else
85
+ stderr_str << chunk
86
+ @error.print(chunk)
87
+ end
88
+ prompt_buffer = handle_prompt(input, chunk, prompt_buffer: prompt_buffer)
89
+ rescue EOFError
90
+ readers.delete(reader)
67
91
  end
68
- handle_prompt(input, chunk)
69
- rescue EOFError
70
- readers.delete(reader)
71
92
  end
72
93
  end
73
94
  end
@@ -76,13 +97,21 @@ module Kettle
76
97
  [stdout_str, stderr_str, status]
77
98
  end
78
99
 
79
- def handle_prompt(input, chunk)
80
- if otp_prompt?(chunk)
81
- write_secret(input, label: "RubyGems MFA code", source: "rubygems_otp") { secrets_provider.rubygems_otp } if otp_response_prompt?(chunk)
82
- return
100
+ def handle_prompt(input, chunk, prompt_buffer: nil)
101
+ prompt_buffer = prompt_buffer.to_s.dup
102
+ prompt_buffer << chunk.to_s
103
+ prompt_buffer = prompt_buffer.byteslice([prompt_buffer.bytesize - 4096, 0].max, 4096).to_s
104
+
105
+ if otp_prompt?(prompt_buffer)
106
+ if otp_response_prompt?(prompt_buffer)
107
+ write_secret(input, label: "RubyGems MFA code", source: "rubygems_otp") { secrets_provider.rubygems_otp }
108
+ return +""
109
+ end
110
+ return prompt_buffer
83
111
  end
84
112
 
85
- write_secret(input, label: "gem signing passphrase", source: "gem_signing_passphrase") { gem_signing_passphrase } if signing_password_prompt?(chunk)
113
+ write_secret(input, label: "gem signing passphrase", source: "gem_signing_passphrase") { gem_signing_passphrase } if signing_password_prompt?(prompt_buffer)
114
+ prompt_buffer
86
115
  end
87
116
 
88
117
  def gem_signing_passphrase
@@ -3,6 +3,7 @@
3
3
  require "set"
4
4
  require "shellwords"
5
5
  require "fileutils"
6
+ require "open3"
6
7
  require "bundler"
7
8
 
8
9
  require_relative "bundler_env_guard"
@@ -418,12 +419,26 @@ module Kettle
418
419
  end
419
420
 
420
421
  def locally_installed?(name, version)
421
- Gem::Specification.reset
422
- Gem::Specification.find_all_by_name(name, "= #{version}").any?
423
- rescue
422
+ _stdout, _stderr, status = Open3.capture3(
423
+ unbundled_env,
424
+ "gem",
425
+ "specification",
426
+ name,
427
+ "--version",
428
+ version.to_s,
429
+ "--local"
430
+ )
431
+ status.success?
432
+ rescue SystemCallError
424
433
  false
425
434
  end
426
435
 
436
+ def unbundled_env
437
+ UNBUNDLED_ENV_KEYS.each_with_object({}) do |key, env|
438
+ env[key] = nil
439
+ end
440
+ end
441
+
427
442
  def gem_source_version_available?(name, version, source_urls)
428
443
  urls = Array(source_urls).compact.uniq
429
444
  return false if urls.empty?
@@ -316,8 +316,12 @@ module Kettle
316
316
  # Check 1: Ensure GitHub Actions workflow action refs are current SHA pins.
317
317
  # @return [void]
318
318
  def check_github_actions_sha_pins!
319
- puts "[kettle-pre-release] Check 1: Validate GitHub Actions SHA pins"
320
- status = Kettle::Dev::GhaShaPinsCLI.new(["--root", Dir.pwd, "--check", "--upgrade", "major"]).run!
319
+ offline = env_truthy?(ENV["KETTLE_PRE_RELEASE_GHA_SHA_PINS_OFFLINE"])
320
+ mode = offline ? "offline cache" : "live cache validation"
321
+ puts "[kettle-pre-release] Check 1: Validate GitHub Actions SHA pins (#{mode})"
322
+ args = ["--root", Dir.pwd, "--check", "--upgrade", "major"]
323
+ args << "--offline" if offline
324
+ status = Kettle::Dev::GhaShaPinsCLI.new(args).run!
321
325
  return nil if status.zero?
322
326
 
323
327
  Kettle::Dev::ExitAdapter.abort("GitHub Actions SHA pin validation failed")
@@ -46,6 +46,23 @@ module Kettle
46
46
  "BUNDLE_SILENCE_ROOT_WARNING" => "true",
47
47
  "BUNDLE_SUPPRESS_INSTALL_USING_MESSAGES" => "true"
48
48
  }.freeze
49
+ RELEASE_CHILD_ENV_KEYS = %w[
50
+ K_RELEASE_CI_CONTINUE
51
+ K_RELEASE_REQUIRED_REMOTES
52
+ KETTLE_FAMILY_CONFIG
53
+ KETTLE_PRE_RELEASE_GHA_SHA_PINS_OFFLINE
54
+ KETTLE_RELEASE_SECRETS_PROVIDER
55
+ KETTLE_RELEASE_SECRETS_BROKER
56
+ KETTLE_RELEASE_GEM_SIGNING_PASSPHRASE
57
+ KETTLE_RELEASE_GEM_SIGNING_PASSPHRASE_SOURCE
58
+ KETTLE_RELEASE_1PASSWORD_ACCOUNT
59
+ KETTLE_RELEASE_1PASSWORD_CLI
60
+ KETTLE_RELEASE_1PASSWORD_ITEM
61
+ KETTLE_RELEASE_1PASSWORD_GEM_SIGNING_PASSPHRASE_FIELD
62
+ KETTLE_RELEASE_1PASSWORD_RUBYGEMS_OTP_FIELD
63
+ KETTLE_RELEASE_1PASSWORD_GEM_SIGNING_PASSPHRASE_REFERENCE
64
+ KETTLE_RELEASE_1PASSWORD_RUBYGEMS_OTP_REFERENCE
65
+ ].freeze
49
66
  DEBUG_TRUE_VALUES = %w[1 true yes on].freeze
50
67
  RELEASE_VALIDATION_SOURCE = "https://gem.coop"
51
68
 
@@ -110,7 +127,9 @@ module Kettle
110
127
  env_hash = command_env
111
128
  return env_hash unless project_bundle_command?(cmd)
112
129
 
113
- env_hash.merge(BundlerEnvGuard.unbundled_env)
130
+ env_hash.merge(BundlerEnvGuard.unbundled_env).merge(
131
+ RELEASE_CHILD_ENV_KEYS.each_with_object({}) { |key, env| env[key] = nil }
132
+ )
114
133
  end
115
134
 
116
135
  def project_bundle_command?(cmd)
@@ -622,7 +641,10 @@ module Kettle
622
641
  end
623
642
 
624
643
  def prepare_release_lockfiles_for_commit!
625
- reset_release_lockfiles!(stage: "before release prep commit") unless @release_lockfiles_reset_for_release_tasks
644
+ # Release setup and documentation tasks can re-materialize local PATH
645
+ # sources in the parent development bundle after the preflight reset.
646
+ # Always normalize again at the commit boundary.
647
+ reset_release_lockfiles!(stage: "before release prep commit")
626
648
  validate_release_lockfiles!(stage: "before release prep commit")
627
649
  end
628
650
 
@@ -1167,7 +1189,7 @@ module Kettle
1167
1189
  Kettle::Dev::CIMonitor.monitor_all!(
1168
1190
  restart_hint: restart_hint,
1169
1191
  workflows: @ci_workflows,
1170
- keepalive: release_secrets_configured? ? -> { keep_release_secrets_alive!("CI monitoring") } : nil,
1192
+ keepalive: release_secrets_keepalive_required? ? -> { keep_release_secrets_alive!("CI monitoring") } : nil,
1171
1193
  event_recorder: @event_recorder
1172
1194
  )
1173
1195
  emit_ci_monitor_event(action: "finish", status: "ok", workflows: @ci_workflows, restart_hint: restart_hint)
@@ -1365,7 +1387,7 @@ module Kettle
1365
1387
  end
1366
1388
 
1367
1389
  def keep_release_secrets_alive!(purpose)
1368
- return unless release_secrets_configured?
1390
+ return unless release_secrets_keepalive_required?
1369
1391
  return unless @secrets_provider.respond_to?(:keepalive!)
1370
1392
 
1371
1393
  emit_secret_event(action: "keepalive", status: "started", purpose: purpose, source: release_secrets_provider_label, elapsed: release_elapsed_label)
@@ -1376,6 +1398,16 @@ module Kettle
1376
1398
  abort("Release secrets provider keepalive failed before #{purpose}: #{error.message}")
1377
1399
  end
1378
1400
 
1401
+ def release_secrets_keepalive_required?
1402
+ return false unless release_secrets_configured?
1403
+ if @secrets_provider.respond_to?(:keepalive_required?)
1404
+ configured = @secrets_provider.keepalive_required?
1405
+ return configured unless configured.nil?
1406
+ end
1407
+
1408
+ true
1409
+ end
1410
+
1379
1411
  def release_elapsed_label
1380
1412
  return nil unless @started_at
1381
1413
 
@@ -1,6 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "open3"
4
+ require "json"
5
+ require "socket"
6
+ require "kettle/dev/interactive_release_command"
4
7
  require "kettle/dev/release_notifier"
5
8
 
6
9
  module Kettle
@@ -9,6 +12,10 @@ module Kettle
9
12
 
10
13
  module ReleaseSecrets
11
14
  class Provider
15
+ def keepalive_required?
16
+ true
17
+ end
18
+
12
19
  def gem_signing_passphrase
13
20
  nil
14
21
  end
@@ -22,6 +29,63 @@ module Kettle
22
29
  end
23
30
  end
24
31
 
32
+ # Secret provider used by a family-owned release broker. The broker keeps
33
+ # all 1Password lookups in the family process; member release processes
34
+ # never authenticate independently.
35
+ class BrokerClient < Provider
36
+ def initialize(endpoint)
37
+ @endpoint = endpoint.to_s
38
+ raise Kettle::Dev::Error, "release secrets broker endpoint is required" if @endpoint.empty?
39
+ end
40
+
41
+ def gem_signing_passphrase
42
+ return cached_gem_signing_passphrase if cached_gem_signing_passphrase?
43
+
44
+ request("gem_signing_passphrase")
45
+ end
46
+
47
+ def rubygems_otp
48
+ request("rubygems_otp")
49
+ end
50
+
51
+ # A family broker owns authorization. Polling must never start a new
52
+ # authentication lookup in the member process.
53
+ def keepalive!(elapsed: nil)
54
+ true
55
+ end
56
+
57
+ def keepalive_required?
58
+ false
59
+ end
60
+
61
+ private
62
+
63
+ def cached_gem_signing_passphrase?
64
+ %w[cached family kettle-family].include?(ENV.fetch("KETTLE_RELEASE_GEM_SIGNING_PASSPHRASE_SOURCE", "").downcase)
65
+ end
66
+
67
+ def cached_gem_signing_passphrase
68
+ value = ENV.fetch("KETTLE_RELEASE_GEM_SIGNING_PASSPHRASE", "").to_s
69
+ raise Kettle::Dev::Error, "cached gem signing passphrase was requested but KETTLE_RELEASE_GEM_SIGNING_PASSPHRASE is empty" if value.empty?
70
+
71
+ value
72
+ end
73
+
74
+ def request(operation)
75
+ socket = UNIXSocket.new(@endpoint)
76
+ socket.write(JSON.generate("operation" => operation))
77
+ socket.write("\n")
78
+ response = JSON.parse(socket.gets.to_s)
79
+ return response.fetch("value").to_s if response["ok"]
80
+
81
+ raise Kettle::Dev::Error, response.fetch("error", "release secrets broker request failed")
82
+ rescue Errno::ENOENT, Errno::ECONNREFUSED => error
83
+ raise Kettle::Dev::Error, "release secrets broker is unavailable: #{error.message}"
84
+ ensure
85
+ socket&.close
86
+ end
87
+ end
88
+
25
89
  class OnePassword < Provider
26
90
  PROVIDER_NAMES = %w[1password onepassword op].freeze
27
91
  DEFAULTS = {
@@ -70,13 +134,16 @@ module Kettle
70
134
  end
71
135
 
72
136
  def keepalive!(elapsed: nil)
73
- argv = [op_cli, "account", "get"]
74
- account = string_config("account")
75
- argv.concat(["--account", account]) unless account.empty?
76
- run_op(argv, purpose: "authorization keepalive", elapsed: elapsed)
137
+ # 1Password CLI authentication is session-scoped. Starting a fresh
138
+ # `op account get` for every release poll does not keep it alive; it
139
+ # only creates repeated authorization prompts and noise.
77
140
  true
78
141
  end
79
142
 
143
+ def keepalive_required?
144
+ false
145
+ end
146
+
80
147
  private
81
148
 
82
149
  attr_reader :config
@@ -112,9 +179,11 @@ module Kettle
112
179
  required_config("cli")
113
180
  end
114
181
 
115
- def run_op(argv, purpose:, elapsed: nil)
182
+ def run_op(argv, purpose:, elapsed: nil, interactive: false)
116
183
  elapsed_suffix = elapsed.to_s.empty? ? "" : " (elapsed #{elapsed})"
117
184
  Kettle::Dev::ReleaseNotifier.alert("1Password #{purpose} lookup starting#{elapsed_suffix}; watch for authorization prompt.")
185
+ return run_interactive_op(argv, purpose: purpose) if interactive
186
+
118
187
  stdout, stderr, status = Open3.capture3(*argv)
119
188
  return stdout.to_s.strip if status.success? && !stdout.to_s.strip.empty?
120
189
 
@@ -125,6 +194,23 @@ module Kettle
125
194
  raise Kettle::Dev::Error, "1Password CLI executable #{argv.first.inspect} was not found"
126
195
  end
127
196
 
197
+ def run_interactive_op(argv, purpose:)
198
+ _stdout, stderr, status = Kettle::Dev::InteractiveReleaseCommand.new(
199
+ secrets_provider: Provider.new,
200
+ input: $stdin,
201
+ output: $stdout,
202
+ error: $stderr,
203
+ forward_stdin: true
204
+ ).call_argv({}, argv)
205
+ return if status.success?
206
+
207
+ details = stderr.to_s.strip
208
+ details = "op exited #{status.exitstatus}" if details.empty?
209
+ raise Kettle::Dev::Error, "1Password #{purpose} lookup failed: #{details}"
210
+ rescue Errno::ENOENT
211
+ raise Kettle::Dev::Error, "1Password CLI executable #{argv.first.inspect} was not found"
212
+ end
213
+
128
214
  def required_config(key)
129
215
  value = string_config(key)
130
216
  raise Kettle::Dev::Error, "1Password release secrets require #{key}" if value.empty?
@@ -157,6 +243,10 @@ module Kettle
157
243
  provider_name.to_s
158
244
  end
159
245
  return Provider.new if name.empty? || name == "interactive"
246
+ if %w[family broker].include?(name.downcase)
247
+ endpoint = configured.fetch("endpoint", ENV.fetch("KETTLE_RELEASE_SECRETS_BROKER", ""))
248
+ return BrokerClient.new(endpoint)
249
+ end
160
250
  return OnePassword.new(env_config.merge(configured)) if OnePassword.configured?(name)
161
251
 
162
252
  raise Kettle::Dev::Error, "unsupported release secrets provider #{name.inspect}"
@@ -5,7 +5,7 @@ module Kettle
5
5
  # Version namespace for this gem.
6
6
  module Version
7
7
  # Current gem version.
8
- VERSION = "3.0.0"
8
+ VERSION = "3.0.2"
9
9
  end
10
10
  # Current gem version exposed at the traditional constant location.
11
11
  VERSION = Version::VERSION # Traditional Constant Location
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: 3.0.0
4
+ version: 3.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter H. Boling
@@ -60,7 +60,7 @@ dependencies:
60
60
  version: '0.3'
61
61
  - - ">="
62
62
  - !ruby/object:Gem::Version
63
- version: 0.3.10
63
+ version: 0.3.11
64
64
  type: :runtime
65
65
  prerelease: false
66
66
  version_requirements: !ruby/object:Gem::Requirement
@@ -70,7 +70,7 @@ dependencies:
70
70
  version: '0.3'
71
71
  - - ">="
72
72
  - !ruby/object:Gem::Version
73
- version: 0.3.10
73
+ version: 0.3.11
74
74
  - !ruby/object:Gem::Dependency
75
75
  name: kettle-ndjson
76
76
  requirement: !ruby/object:Gem::Requirement
@@ -400,10 +400,10 @@ licenses:
400
400
  - AGPL-3.0-only
401
401
  metadata:
402
402
  homepage_uri: https://kettle-dev.galtzo.com
403
- source_code_uri: https://github.com/kettle-dev/kettle-dev/tree/v3.0.0
404
- changelog_uri: https://github.com/kettle-dev/kettle-dev/blob/v3.0.0/CHANGELOG.md
403
+ source_code_uri: https://github.com/kettle-dev/kettle-dev/tree/v3.0.2
404
+ changelog_uri: https://github.com/kettle-dev/kettle-dev/blob/v3.0.2/CHANGELOG.md
405
405
  bug_tracker_uri: https://github.com/kettle-dev/kettle-dev/issues
406
- documentation_uri: https://www.rubydoc.info/gems/kettle-dev/3.0.0
406
+ documentation_uri: https://www.rubydoc.info/gems/kettle-dev/3.0.2
407
407
  funding_uri: https://github.com/sponsors/pboling
408
408
  wiki_uri: https://github.com/kettle-dev/kettle-dev/wiki
409
409
  news_uri: https://www.railsbling.com/tags/kettle-dev
metadata.gz.sig CHANGED
Binary file