kettle-dev 3.0.1 → 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: 335bd9651ff7bbe5381c8e050a26f070c6accd8054ab581226ba3355c8a4aa6e
4
- data.tar.gz: 7f59238412adde48ba5f2b524b08e4ce77a5348c81d0984e44013e6ce905b2dc
3
+ metadata.gz: ac5e19991ef314add0cbb6f8c764a0389df6003ea291e5ea08bb76bf32c2786a
4
+ data.tar.gz: 894c0f1521ec987771056394037f3aa2108634bea11830c47f630b43b65727e7
5
5
  SHA512:
6
- metadata.gz: 94e3d356b963078c8dd46d50d0f2b7ed92f656327bd3f766618617b56172ae0051dc32f6469cfd5c9faf539e00a4bbdf123947dd8febbd10c34172f51a2efc2d
7
- data.tar.gz: d2eee5766a478c4846f05969ac4fcbf4614793740911c029219d85fb446fd308f9c376c5fa8d68edbdc71bd144dba09a1ad927c5915278c7933d0fc50ac74dca
6
+ metadata.gz: 2bbb2b78730584bfdddbf66664679393ec7c282ea8e24130b01019bc4e61c48da2d4be751d354679c0a76f6ac4ed23a28bfcf60efae081468ffa98cfbe66dfb5
7
+ data.tar.gz: cc6156801f9ef0b6cd6e39ee614b63729acff1862e83cd4390319a98a6978ef06e148d82c255beb38a0d68a09531e435a4d57c7f315a9e4f4cb1cd929b16edff
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -30,6 +30,23 @@ 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
+
33
50
  ## [3.0.1] - 2026-08-10
34
51
 
35
52
  - TAG: [v3.0.1][3.0.1t]
@@ -3414,7 +3431,9 @@ Please file a bug if you notice a violation of semantic versioning.
3414
3431
  - Selecting will run the selected workflow via `act`
3415
3432
  - This may move to its own gem in the future.
3416
3433
 
3417
- [Unreleased]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.1...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
3418
3437
  [3.0.1]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.0...v3.0.1
3419
3438
  [3.0.1t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v3.0.1
3420
3439
  [3.0.0]: https://github.com/kettle-dev/kettle-dev/compare/v2.5.28...v3.0.0
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.098-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
@@ -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)
@@ -1170,7 +1189,7 @@ module Kettle
1170
1189
  Kettle::Dev::CIMonitor.monitor_all!(
1171
1190
  restart_hint: restart_hint,
1172
1191
  workflows: @ci_workflows,
1173
- keepalive: release_secrets_configured? ? -> { keep_release_secrets_alive!("CI monitoring") } : nil,
1192
+ keepalive: release_secrets_keepalive_required? ? -> { keep_release_secrets_alive!("CI monitoring") } : nil,
1174
1193
  event_recorder: @event_recorder
1175
1194
  )
1176
1195
  emit_ci_monitor_event(action: "finish", status: "ok", workflows: @ci_workflows, restart_hint: restart_hint)
@@ -1368,7 +1387,7 @@ module Kettle
1368
1387
  end
1369
1388
 
1370
1389
  def keep_release_secrets_alive!(purpose)
1371
- return unless release_secrets_configured?
1390
+ return unless release_secrets_keepalive_required?
1372
1391
  return unless @secrets_provider.respond_to?(:keepalive!)
1373
1392
 
1374
1393
  emit_secret_event(action: "keepalive", status: "started", purpose: purpose, source: release_secrets_provider_label, elapsed: release_elapsed_label)
@@ -1379,6 +1398,16 @@ module Kettle
1379
1398
  abort("Release secrets provider keepalive failed before #{purpose}: #{error.message}")
1380
1399
  end
1381
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
+
1382
1411
  def release_elapsed_label
1383
1412
  return nil unless @started_at
1384
1413
 
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "open3"
4
+ require "json"
5
+ require "socket"
4
6
  require "kettle/dev/interactive_release_command"
5
7
  require "kettle/dev/release_notifier"
6
8
 
@@ -10,6 +12,10 @@ module Kettle
10
12
 
11
13
  module ReleaseSecrets
12
14
  class Provider
15
+ def keepalive_required?
16
+ true
17
+ end
18
+
13
19
  def gem_signing_passphrase
14
20
  nil
15
21
  end
@@ -23,6 +29,63 @@ module Kettle
23
29
  end
24
30
  end
25
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
+
26
89
  class OnePassword < Provider
27
90
  PROVIDER_NAMES = %w[1password onepassword op].freeze
28
91
  DEFAULTS = {
@@ -71,13 +134,16 @@ module Kettle
71
134
  end
72
135
 
73
136
  def keepalive!(elapsed: nil)
74
- argv = [op_cli, "account", "get"]
75
- account = string_config("account")
76
- argv.concat(["--account", account]) unless account.empty?
77
- run_op(argv, purpose: "authorization keepalive", elapsed: elapsed, interactive: true)
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.
78
140
  true
79
141
  end
80
142
 
143
+ def keepalive_required?
144
+ false
145
+ end
146
+
81
147
  private
82
148
 
83
149
  attr_reader :config
@@ -177,6 +243,10 @@ module Kettle
177
243
  provider_name.to_s
178
244
  end
179
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
180
250
  return OnePassword.new(env_config.merge(configured)) if OnePassword.configured?(name)
181
251
 
182
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.1"
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.1
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.1
404
- changelog_uri: https://github.com/kettle-dev/kettle-dev/blob/v3.0.1/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.1
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