radfish 0.3.0 → 0.3.1

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: ddba2c0632175f4f75abe456074d912b7d6644371ca78699b7979abb4e9dd3de
4
- data.tar.gz: 44eedf5868fbea6171d2714a922f1ab35dec320293208c5472e32d7d2104ece7
3
+ metadata.gz: 28b19abfcfc47b88d31ad43a17e67b9f0de71ac358c44bdb8e7e6f91b80a775f
4
+ data.tar.gz: d6e34c43743f79bfbfbb874545deedf1a487bfdfd6c7111683baebad257b5f45
5
5
  SHA512:
6
- metadata.gz: 127e46cc938fe890f04ae0ad6b68b2ea0d2643ab7ca27c0855586291f363853cfb3151b0d88860d1f02f364f1430c42bef6f2c35880b6a8cc9504b5c7962b23c
7
- data.tar.gz: c0e1fb812a023c8ecdfcf47a701dfc2fa4b959c9a63527109b4367a960f6261d5f3a35daa0415fe706ef0f3a66c4097a103bbd0a7d1ecc25b32872191013da46
6
+ metadata.gz: 0c62952bdd04c892f39f6fe44785bfd8f7b12800f27eaac6ef7ba2555380027401acfb2ed76fe5a0d4628917ababcde8fd4dba12dd61bc0ecfa88ea97c9d9b0c
7
+ data.tar.gz: 51a2cd9988e9b3e39e4af3c382308f48128aa52d3f5ab52857e4b11425e775f996a559fc1d77a1353d321e832c8e5266336bf597f55b897666be4e6c8981a962
data/README.md CHANGED
@@ -126,6 +126,20 @@ Regardless of vendor, all adapters provide:
126
126
  ### Vendor-Specific Features
127
127
  Adapters can expose vendor-specific functionality while maintaining the common interface.
128
128
 
129
+ ## Compatibility
130
+
131
+ `activesupport` below 8.1 and `json` 3 cannot be used together: activesupport's
132
+ JSON encoder calls `JSON.generate(..., quirks_mode: true)`, and json 3 removed
133
+ that keyword, so any `hash.to_json` raises `ArgumentError: unknown keyword:
134
+ quirks_mode`. This is not specific to this gem — it bites anything that loads
135
+ `active_support/core_ext` — but radfish depends on activesupport, so pick one
136
+ of:
137
+
138
+ - activesupport >= 8.1 with json 3, or
139
+ - activesupport 7.x with json 2.
140
+
141
+ CI covers both ends.
142
+
129
143
  ## Installation
130
144
 
131
145
  Add to your Gemfile:
@@ -14,9 +14,14 @@ module Radfish
14
14
  end
15
15
 
16
16
  def connection
17
- @connection ||= Faraday.new(url: client.base_url, ssl: { verify: client.verify_ssl }) do |faraday|
18
- faraday.request :url_encoded
19
- faraday.adapter Faraday.default_adapter
17
+ @connection ||= begin
18
+ url = URI(client.base_url)
19
+ HttpClient.new(host: url.host, port: url.port,
20
+ use_ssl: url.scheme == 'https', verify_ssl: client.verify_ssl,
21
+ host_header: client.host_header,
22
+ retry_count: client.retry_count,
23
+ retry_delay: client.retry_delay,
24
+ verbosity: verbosity)
20
25
  end
21
26
  end
22
27
 
@@ -32,10 +37,9 @@ module Radfish
32
37
  'Content-Type' => 'application/json',
33
38
  'Accept' => 'application/json'
34
39
  }
35
- headers['Host'] = client.host_header if client.host_header
36
-
40
+
37
41
  begin
38
- response = connection.post('/redfish/v1/SessionService/Sessions', payload, headers)
42
+ response = connection.post('/redfish/v1/SessionService/Sessions', body: payload, headers: headers)
39
43
 
40
44
  if response.status == 201
41
45
  @x_auth_token = response.headers['x-auth-token']
@@ -50,14 +54,14 @@ module Radfish
50
54
  rescue JSON::ParserError
51
55
  end
52
56
 
53
- debug "Session created successfully. Token: #{@x_auth_token ? @x_auth_token[0..10] + '...' : 'nil'}", 1, :green
57
+ debug "Session #{@session_id || '?'} created successfully (token #{@x_auth_token ? 'received' : 'missing'})", 1, :green
54
58
  return true
55
59
  else
56
60
  debug "Failed to create session. Status: #{response.status}", 1, :red
57
- debug "Response: #{response.body}", 2
61
+ debug "Response: #{HttpClient.scrub(response.body)}", 2
58
62
  return false
59
63
  end
60
- rescue Faraday::Error => e
64
+ rescue Radfish::Error => e
61
65
  debug "Connection error creating session: #{e.message}", 1, :red
62
66
  return false
63
67
  end
@@ -72,10 +76,9 @@ module Radfish
72
76
  'X-Auth-Token' => @x_auth_token,
73
77
  'Accept' => 'application/json'
74
78
  }
75
- headers['Host'] = client.host_header if client.host_header
76
-
79
+
77
80
  begin
78
- response = connection.delete("/redfish/v1/SessionService/Sessions/#{@session_id}", nil, headers)
81
+ response = connection.delete("/redfish/v1/SessionService/Sessions/#{@session_id}", headers: headers)
79
82
 
80
83
  if response.status == 204 || response.status == 200
81
84
  debug "Session deleted successfully", 1, :green
@@ -86,7 +89,7 @@ module Radfish
86
89
  debug "Failed to delete session. Status: #{response.status}", 1, :yellow
87
90
  return false
88
91
  end
89
- rescue Faraday::Error => e
92
+ rescue Radfish::Error => e
90
93
  debug "Error deleting session: #{e.message}", 1, :yellow
91
94
  return false
92
95
  end
@@ -99,10 +102,9 @@ module Radfish
99
102
  'X-Auth-Token' => @x_auth_token,
100
103
  'Accept' => 'application/json'
101
104
  }
102
- headers['Host'] = client.host_header if client.host_header
103
-
105
+
104
106
  begin
105
- response = connection.get("/redfish/v1/SessionService/Sessions/#{@session_id}", nil, headers)
107
+ response = connection.get("/redfish/v1/SessionService/Sessions/#{@session_id}", headers: headers)
106
108
  response.status == 200
107
109
  rescue
108
110
  false
@@ -114,4 +116,4 @@ module Radfish
114
116
  end
115
117
  end
116
118
  end
117
- end
119
+ end
@@ -24,14 +24,29 @@ module Radfish
24
24
  IDEMPOTENT_METHODS = [:get, :head, :put, :delete].freeze
25
25
  RETRY_STATUSES = [408, 429, 500, 502, 503, 504].freeze
26
26
 
27
+ # Secrets stripped from the debug log. Redfish session payloads use
28
+ # "Password" where other calls use "password", and the session token comes
29
+ # back as a header, so match either case and both header shapes.
30
+ LOG_FILTERS = [
31
+ # Faraday logs a header as `Authorization: "Basic dXNlcjpwdw=="` and a
32
+ # headers hash as `"Authorization"=>"Basic ..."`, so the quote sits
33
+ # between the colon and the scheme. Match both shapes, and any scheme,
34
+ # keeping the scheme itself visible because it is useful and not secret.
35
+ [/(Authorization"?\s*(?:=>|:)\s*"?)((?:Basic|Bearer|Digest)\s+)?[^"\n]+/i, '\1\2[FILTERED]'],
36
+ [/(Password"=>"?)([^,"]+)/i, '\1[FILTERED]'],
37
+ [/("password"\s*:\s*")([^"]+)/i, '\1[FILTERED]'],
38
+ [/((?:X-Auth-Token)"?\s*(?:=>|:)\s*"?)([^",\n]+)/i, '\1[FILTERED]']
39
+ ].freeze
40
+
27
41
  attr_reader :host, :port, :use_ssl, :verify_ssl
28
42
  attr_accessor :username, :password, :verbosity, :retry_count, :retry_delay,
29
- :retry_methods, :max_redirects
43
+ :retry_methods, :max_redirects, :log_device
30
44
 
31
45
  def initialize(host:, port: 443, use_ssl: true, verify_ssl: false,
32
46
  username: nil, password: nil, verbosity: 0,
33
47
  retry_count: 3, retry_delay: 1,
34
- retry_methods: IDEMPOTENT_METHODS, max_redirects: 3, **options)
48
+ retry_methods: IDEMPOTENT_METHODS, max_redirects: 3,
49
+ log_device: STDOUT, **options)
35
50
  @host = host
36
51
  @port = port
37
52
  @use_ssl = use_ssl
@@ -43,9 +58,16 @@ module Radfish
43
58
  @retry_delay = retry_delay
44
59
  @retry_methods = retry_methods
45
60
  @max_redirects = max_redirects
61
+ @log_device = log_device
46
62
  @options = options
47
63
  end
48
64
 
65
+ # The Faraday logger applies LOG_FILTERS, but our own debug lines bypass it,
66
+ # so anything we print that can carry a header or a body goes through here.
67
+ def self.scrub(text)
68
+ LOG_FILTERS.reduce(text.to_s) { |t, (pattern, replacement)| t.gsub(pattern, replacement) }
69
+ end
70
+
49
71
  def base_url
50
72
  protocol = use_ssl ? 'https' : 'http'
51
73
  "#{protocol}://#{host}:#{port}"
@@ -91,7 +113,7 @@ module Radfish
91
113
  response = conn.send(method) do |req|
92
114
  debug "Setting request URL: #{path}", 3, :cyan
93
115
  req.url path
94
- debug "Merging headers: #{headers}", 3, :cyan
116
+ debug "Merging headers: #{self.class.scrub(headers)}", 3, :cyan
95
117
  req.headers.merge!(headers)
96
118
  req.body = body if body
97
119
 
@@ -152,6 +174,10 @@ module Radfish
152
174
  end
153
175
 
154
176
  raise Radfish::ConnectionError, "SSL error connecting to #{host}: #{e.message}"
177
+ rescue Faraday::Error => e
178
+ # HttpClient is the seam: callers speak Radfish errors, not Faraday ones.
179
+ debug "HTTP request failed: #{e.class} - #{e.message}", 1, :red
180
+ raise Radfish::Error, "Request to #{host} failed: #{e.message}"
155
181
  rescue => e
156
182
  debug "HTTP request failed: #{e.class} - #{e.message}", 1, :red
157
183
  debug "Exception backtrace: #{e.backtrace.first(5).join("\n")}", 1, :red
@@ -260,10 +286,8 @@ module Radfish
260
286
 
261
287
  # Add logging if verbose
262
288
  if verbosity >= 2
263
- faraday.response :logger, Logger.new(STDOUT), { bodies: verbosity >= 3 } do |logger|
264
- logger.filter(/(Authorization: Basic )([^,\n]+)/, '\1[FILTERED]')
265
- logger.filter(/(Password"=>"?)([^,"]+)/, '\1[FILTERED]')
266
- logger.filter(/("password":\s*")([^"]+)/, '\1[FILTERED]')
289
+ faraday.response :logger, Logger.new(log_device), { bodies: verbosity >= 3 } do |logger|
290
+ LOG_FILTERS.each { |pattern, replacement| logger.filter(pattern, replacement) }
267
291
  end
268
292
  end
269
293
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Radfish
4
- VERSION = "0.3.0"
4
+ VERSION = "0.3.1"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: radfish
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonathan Siegel
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-09-10 00:00:00.000000000 Z
11
+ date: 2026-09-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor