kettle-family 1.2.14 → 1.2.15
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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +16 -1
- data/README.md +1 -1
- data/lib/kettle/family/command_runner.rb +80 -12
- data/lib/kettle/family/secrets.rb +1 -1
- data/lib/kettle/family/version.rb +1 -1
- data/lib/kettle/family/workflow.rb +24 -1
- data.tar.gz.sig +0 -0
- metadata +4 -4
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9ccc9063ef81ee8d6b8bee27424903371b47863d9fb2903b4461c2e132b757d9
|
|
4
|
+
data.tar.gz: ec46a0708e899590fb95d67d1f8e9dbe002195b21cf9a635c2c8b4a726a693c9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 883955e631cd8b19ee2219a98267465307dec049d35c7f209f61ce23465eeb05665a88954b0dcac39e70f980aa39a02bdc6f2539c4897ef6418412a7d5ad1054
|
|
7
|
+
data.tar.gz: 8c584b648f8fe2914ac5077b8b181f398b2fe1507eb30278927c13408f5b3b7e6c4a7b1beba417f1dcc1a0ae80a0e7a460d433bb1336615a6ccb3759e2abee34
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/CHANGELOG.md
CHANGED
|
@@ -30,6 +30,19 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
30
30
|
|
|
31
31
|
### Security
|
|
32
32
|
|
|
33
|
+
## [1.2.15] - 2026-07-31
|
|
34
|
+
|
|
35
|
+
- TAG: [v1.2.15][1.2.15t]
|
|
36
|
+
- COVERAGE: 94.03% -- 4192/4458 lines in 28 files
|
|
37
|
+
- BRANCH COVERAGE: 76.46% -- 1634/2137 branches in 28 files
|
|
38
|
+
- 28.88% documented
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
- Family-owned release OTP lookups now render as structured secret-provider
|
|
43
|
+
progress events, including a visible `👀 🔒` authorization prompt cue, instead
|
|
44
|
+
of printing loose MFA status lines through the release tape.
|
|
45
|
+
|
|
33
46
|
## [1.2.14] - 2026-07-31
|
|
34
47
|
|
|
35
48
|
- TAG: [v1.2.14][1.2.14t]
|
|
@@ -1499,7 +1512,9 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
1499
1512
|
- Fixed CI load failures on engines without compatible `pty` support by falling back to Open3 for interactive release commands.
|
|
1500
1513
|
- Fixed Ruby 3.2 version-bump support by loading Prism lazily and wiring the Prism gem only for MRI versions that need it.
|
|
1501
1514
|
|
|
1502
|
-
[Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v1.2.
|
|
1515
|
+
[Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v1.2.15...HEAD
|
|
1516
|
+
[1.2.15]: https://github.com/kettle-dev/kettle-family/compare/v1.2.14...v1.2.15
|
|
1517
|
+
[1.2.15t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.2.15
|
|
1503
1518
|
[1.2.14]: https://github.com/kettle-dev/kettle-family/compare/v1.2.13...v1.2.14
|
|
1504
1519
|
[1.2.14t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.2.14
|
|
1505
1520
|
[1.2.13]: https://github.com/kettle-dev/kettle-family/compare/v1.2.12...v1.2.13
|
data/README.md
CHANGED
|
@@ -819,7 +819,7 @@ Thanks for RTFM. ☺️
|
|
|
819
819
|
[📌gitmoji]: https://gitmoji.dev
|
|
820
820
|
[📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
|
821
821
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
822
|
-
[🧮kloc-img]: https://img.shields.io/badge/KLOC-4.
|
|
822
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-4.458-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
|
823
823
|
[🔐security]: https://github.com/kettle-dev/kettle-family/blob/main/SECURITY.md
|
|
824
824
|
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
|
825
825
|
[📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
|
|
@@ -12,10 +12,11 @@ module Kettle
|
|
|
12
12
|
].freeze
|
|
13
13
|
|
|
14
14
|
class OtpCoordinator
|
|
15
|
-
def initialize(input: $stdin, output: $stdout, queue_total: nil, secrets_provider: nil)
|
|
15
|
+
def initialize(input: $stdin, output: $stdout, queue_total: nil, secrets_provider: nil, event_handler: nil)
|
|
16
16
|
@input = input
|
|
17
17
|
@output = output
|
|
18
18
|
@secrets_provider = secrets_provider
|
|
19
|
+
@event_handler = event_handler
|
|
19
20
|
@mutex = Mutex.new
|
|
20
21
|
@condition = ConditionVariable.new
|
|
21
22
|
@prompting = false
|
|
@@ -41,7 +42,7 @@ module Kettle
|
|
|
41
42
|
if @prompting
|
|
42
43
|
generation = @generation
|
|
43
44
|
@queued_count += 1
|
|
44
|
-
render_queue_status_locked
|
|
45
|
+
render_queue_status_locked(member_name: member_name)
|
|
45
46
|
return wait_for_response(generation)
|
|
46
47
|
end
|
|
47
48
|
|
|
@@ -53,7 +54,7 @@ module Kettle
|
|
|
53
54
|
start_prompt_locked(member_name: member_name)
|
|
54
55
|
end
|
|
55
56
|
|
|
56
|
-
response = read_response(chunk: chunk)
|
|
57
|
+
response = read_response(chunk: chunk, member_name: member_name)
|
|
57
58
|
close_queue
|
|
58
59
|
@mutex.synchronize do
|
|
59
60
|
@response = response
|
|
@@ -67,7 +68,7 @@ module Kettle
|
|
|
67
68
|
|
|
68
69
|
private
|
|
69
70
|
|
|
70
|
-
attr_reader :secrets_provider
|
|
71
|
+
attr_reader :secrets_provider, :event_handler
|
|
71
72
|
|
|
72
73
|
def wait_for_response(generation)
|
|
73
74
|
@condition.wait(@mutex) while @prompting
|
|
@@ -83,22 +84,49 @@ module Kettle
|
|
|
83
84
|
end
|
|
84
85
|
|
|
85
86
|
def start_prompt_locked(member_name:)
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
unless emit_event(
|
|
88
|
+
member_name: member_name,
|
|
89
|
+
action: "mfa_requested",
|
|
90
|
+
label: "RubyGems MFA",
|
|
91
|
+
status: "requested",
|
|
92
|
+
mark: ">"
|
|
93
|
+
)
|
|
94
|
+
@output.puts
|
|
95
|
+
@output.puts("[#{member_name}] RubyGems MFA requested.")
|
|
96
|
+
end
|
|
97
|
+
render_queue_status_locked(member_name: member_name)
|
|
98
|
+
return if event_handler
|
|
99
|
+
|
|
89
100
|
@output.puts("Queued prompts at entry will share this code; later prompts will ask again.")
|
|
90
101
|
end
|
|
91
102
|
|
|
92
|
-
def render_queue_status_locked
|
|
103
|
+
def render_queue_status_locked(member_name:)
|
|
93
104
|
suffix = @queue_total ? " / #{@queue_total}" : ""
|
|
105
|
+
return if emit_event(
|
|
106
|
+
member_name: member_name,
|
|
107
|
+
action: "otp_queue",
|
|
108
|
+
label: "RubyGems MFA prompts",
|
|
109
|
+
status: "queued",
|
|
110
|
+
mark: ">",
|
|
111
|
+
queued: @queued_count,
|
|
112
|
+
total: @queue_total
|
|
113
|
+
)
|
|
114
|
+
|
|
94
115
|
@output.puts("RubyGems MFA prompts queued: #{@queued_count}#{suffix}")
|
|
95
116
|
@output.flush if @output.respond_to?(:flush)
|
|
96
117
|
end
|
|
97
118
|
|
|
98
|
-
def read_response(chunk:)
|
|
99
|
-
provided = read_provider_response
|
|
119
|
+
def read_response(chunk:, member_name:)
|
|
120
|
+
provided = read_provider_response(member_name: member_name)
|
|
100
121
|
unless provided.empty?
|
|
101
|
-
|
|
122
|
+
emit_event(
|
|
123
|
+
member_name: member_name,
|
|
124
|
+
action: "prompt_response",
|
|
125
|
+
label: "RubyGems MFA code",
|
|
126
|
+
source: secret_provider_source,
|
|
127
|
+
status: "ok",
|
|
128
|
+
mark: "."
|
|
129
|
+
) || @output.puts("RubyGems MFA code loaded from configured secrets provider.")
|
|
102
130
|
return provided
|
|
103
131
|
end
|
|
104
132
|
|
|
@@ -117,17 +145,57 @@ module Kettle
|
|
|
117
145
|
chunk.to_s.lines.last&.strip.to_s.empty? ? "Code:" : chunk.to_s.lines.last.strip
|
|
118
146
|
end
|
|
119
147
|
|
|
120
|
-
def read_provider_response
|
|
148
|
+
def read_provider_response(member_name:)
|
|
121
149
|
return "" unless secrets_provider
|
|
122
150
|
|
|
123
151
|
@output.print("\a") if @output.respond_to?(:print)
|
|
152
|
+
emit_event(
|
|
153
|
+
member_name: member_name,
|
|
154
|
+
action: "prompt_request",
|
|
155
|
+
label: "👀 🔒 watch for authorization prompt",
|
|
156
|
+
source: secret_provider_source,
|
|
157
|
+
status: "started",
|
|
158
|
+
mark: ">"
|
|
159
|
+
)
|
|
124
160
|
secrets_provider.rubygems_otp.to_s
|
|
125
161
|
rescue Error => error
|
|
126
162
|
raise unless @input.respond_to?(:tty?) && @input.tty?
|
|
127
163
|
|
|
164
|
+
emit_event(
|
|
165
|
+
member_name: member_name,
|
|
166
|
+
action: "prompt_response",
|
|
167
|
+
label: "RubyGems MFA code",
|
|
168
|
+
source: secret_provider_source,
|
|
169
|
+
status: "failed",
|
|
170
|
+
mark: "F"
|
|
171
|
+
)
|
|
128
172
|
@output.puts("#{error.message}; falling back to manual OTP entry.")
|
|
129
173
|
""
|
|
130
174
|
end
|
|
175
|
+
|
|
176
|
+
def emit_event(member_name:, action:, label:, status:, mark:, **payload)
|
|
177
|
+
return false unless event_handler
|
|
178
|
+
|
|
179
|
+
event_handler.call(
|
|
180
|
+
member_name,
|
|
181
|
+
{
|
|
182
|
+
"event_version" => 1,
|
|
183
|
+
"type" => "secret_provider",
|
|
184
|
+
"action" => action,
|
|
185
|
+
"label" => label,
|
|
186
|
+
"status" => status,
|
|
187
|
+
"mark" => mark
|
|
188
|
+
}.merge(payload.transform_keys(&:to_s))
|
|
189
|
+
)
|
|
190
|
+
true
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def secret_provider_source
|
|
194
|
+
return "" unless secrets_provider
|
|
195
|
+
return "1Password" if secrets_provider.is_a?(Secrets::OnePassword)
|
|
196
|
+
|
|
197
|
+
secrets_provider.class.name.to_s.split("::").last.to_s
|
|
198
|
+
end
|
|
131
199
|
end
|
|
132
200
|
|
|
133
201
|
FailureStatus = Struct.new(:exitstatus) do
|
|
@@ -5,7 +5,7 @@ module Kettle
|
|
|
5
5
|
# Version namespace for this gem.
|
|
6
6
|
module Version
|
|
7
7
|
# Current gem version.
|
|
8
|
-
VERSION = "1.2.
|
|
8
|
+
VERSION = "1.2.15"
|
|
9
9
|
end
|
|
10
10
|
# Current gem version exposed at the traditional constant location.
|
|
11
11
|
VERSION = Version::VERSION # Traditional Constant Location
|
|
@@ -806,7 +806,29 @@ module Kettle
|
|
|
806
806
|
def release_otp_coordinator
|
|
807
807
|
return nil unless execute && release_command_interactive?
|
|
808
808
|
|
|
809
|
-
@release_otp_coordinator ||= CommandRunner::OtpCoordinator.new(
|
|
809
|
+
@release_otp_coordinator ||= CommandRunner::OtpCoordinator.new(
|
|
810
|
+
secrets_provider: @secrets_provider,
|
|
811
|
+
event_handler: method(:handle_release_otp_event)
|
|
812
|
+
)
|
|
813
|
+
end
|
|
814
|
+
|
|
815
|
+
def handle_release_otp_event(member_name, event)
|
|
816
|
+
progress = @release_progress
|
|
817
|
+
return unless progress
|
|
818
|
+
|
|
819
|
+
member = release_progress_member_for(member_name)
|
|
820
|
+
if progress_io
|
|
821
|
+
if verbose || debug
|
|
822
|
+
emit_release_event_progress(member, event)
|
|
823
|
+
elsif progress.tty?
|
|
824
|
+
emit_release_event_status(member, event, progress: progress)
|
|
825
|
+
end
|
|
826
|
+
end
|
|
827
|
+
end
|
|
828
|
+
|
|
829
|
+
def release_progress_member_for(member_name)
|
|
830
|
+
@release_progress_members_by_name ||= members.to_h { |member| [member.name, member] }
|
|
831
|
+
@release_progress_members_by_name.fetch(member_name.to_s) { PreflightProgressMember.new(member_name.to_s) }
|
|
810
832
|
end
|
|
811
833
|
|
|
812
834
|
def parallel_release_members?(release_members)
|
|
@@ -2214,6 +2236,7 @@ module Kettle
|
|
|
2214
2236
|
parts << purpose unless purpose.empty?
|
|
2215
2237
|
parts << label unless label.empty?
|
|
2216
2238
|
parts << source if purpose.empty? && label.empty? && !source.empty?
|
|
2239
|
+
parts << "#{event["queued"]}/#{event["total"]}" if event["queued"] && event["total"]
|
|
2217
2240
|
parts.join(":")
|
|
2218
2241
|
end
|
|
2219
2242
|
|
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kettle-family
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.2.
|
|
4
|
+
version: 1.2.15
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter H. Boling
|
|
@@ -342,10 +342,10 @@ licenses:
|
|
|
342
342
|
- AGPL-3.0-only
|
|
343
343
|
metadata:
|
|
344
344
|
homepage_uri: https://kettle-family.galtzo.com
|
|
345
|
-
source_code_uri: https://github.com/kettle-dev/kettle-family/tree/v1.2.
|
|
346
|
-
changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v1.2.
|
|
345
|
+
source_code_uri: https://github.com/kettle-dev/kettle-family/tree/v1.2.15
|
|
346
|
+
changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v1.2.15/CHANGELOG.md
|
|
347
347
|
bug_tracker_uri: https://github.com/kettle-dev/kettle-family/issues
|
|
348
|
-
documentation_uri: https://www.rubydoc.info/gems/kettle-family/1.2.
|
|
348
|
+
documentation_uri: https://www.rubydoc.info/gems/kettle-family/1.2.15
|
|
349
349
|
funding_uri: https://github.com/sponsors/pboling
|
|
350
350
|
wiki_uri: https://github.com/kettle-dev/kettle-family/wiki
|
|
351
351
|
news_uri: https://www.railsbling.com/tags/kettle-family
|
metadata.gz.sig
CHANGED
|
Binary file
|