winrm 2.3.9 → 2.4.0

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: c2ad7fa7e2a15820a43f37d4dc3f68074d4700a9c2fe4a69f2832f51f4ae71c9
4
- data.tar.gz: 5299213d602e9c74498de6e8b4e5d67a79138fceb2de76c1c26d8f41aacd8561
3
+ metadata.gz: b4edbd0e2fca0dd65b9b1ba172f525b9473c7b07ddd2b5fd25c422f00e32164f
4
+ data.tar.gz: dcba3b6b6c8bf4653a588a0d2d2d70d286f19f831c384c107d0b796cdc77e5dc
5
5
  SHA512:
6
- metadata.gz: 60378036a89315c7651dfb633686cd404119a148b1dd40c3f16dd3379990aeff7662e6b6233cb4c074515bcbd0a29c01f989769ba22f125fc798d82228ab4e04
7
- data.tar.gz: 676184a8973b611833fe8f3c826941b376e818fe2a4463ea54a4eef261bbd2067ee290ae072a94d4aa5c367500ad044de4a1c668cec55e45a73a072601f192ec
6
+ metadata.gz: 359c0beed452df2eb17cfc82230bac1f075ce86eedc0ffb2a516681856d097527b6e2ed6eb256d1f7652201882b5e83399312b51e035ba2281611cc3e2ac1b3a
7
+ data.tar.gz: 4195fb3f4c60238102b3cd79de8d0840e49ff4425a1590cf9c01ce0563d43b465bfde5e400543f7f2b15915b5d0e8e9f58a9e1321706e6d2ecd55e47f28c3398
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # Windows Remote Management (WinRM) for Ruby
2
- [![build](https://github.com/WinRb/WinRM/actions/workflows/build.yml/badge.svg)](https://github.com/WinRb/WinRM/actions/workflows/build.yml)
2
+ [![build](https://github.com/WinRb/WinRM/actions/workflows/ci.yml/badge.svg)](https://github.com/WinRb/WinRM/actions/workflows/ci.yml)
3
3
  [![Gem Version](https://badge.fury.io/rb/winrm.svg)](http://badge.fury.io/rb/winrm)
4
4
 
5
5
  This is a SOAP library that uses the functionality in Windows Remote
@@ -11,7 +11,7 @@ site](http://msdn.microsoft.com/en-us/library/aa384426.aspx).
11
11
  As of version 2.0, this gem retains the WinRM name but all powershell calls use the more modern [Powershell Remoting Protocol (PSRP)](https://msdn.microsoft.com/en-us/library/dd357801.aspx) for initializing runspace pools as well as creating and processing powershell pipelines.
12
12
 
13
13
  ## Supported Ruby Versions
14
- Ruby 3.0 or higher is required. If you need to use an older version of Ruby you'll need to use a previous version of this gem.
14
+ Ruby 3.2 or higher is required. If you need to use an older version of Ruby you'll need to use a previous version of this gem.
15
15
 
16
16
  ## Supported WinRM Versions
17
17
  WinRM 1.1 is supported, however 2.0 and higher is recommended. [See MSDN](http://technet.microsoft.com/en-us/library/ff520073.aspx) for information about WinRM versions and supported operating systems.
@@ -202,7 +202,7 @@ iex $cmd
202
202
  ## Setting up Certificate based authentication
203
203
  Perform the following steps to authenticate with a certificate instead of a username and password:
204
204
 
205
- 1. Generate a certificate with an Extended Key Usage of Client Authentication and a Subject Alternative Name with the UPN of the user. See this [powershell function](https://github.com/WinRb/WinRM/blob/master/WinrmAppveyor.psm1#L1) as an example of using `openssl` to create a self signed user certificate in `.pem` and `.pfx` formats along with the private key file.
205
+ 1. Generate a certificate with an Extended Key Usage of Client Authentication and a Subject Alternative Name with the UPN of the user. See this [powershell function](https://github.com/WinRb/WinRM/blob/main/WinrmAppveyor.psm1#L1) as an example of using `openssl` to create a self signed user certificate in `.pem` and `.pfx` formats along with the private key file.
206
206
 
207
207
  2. Import the pfx file into the `TrustedPeople` directory of the `LocalMachine` certificate store on the windows endpoint.
208
208
 
@@ -215,7 +215,7 @@ Perform the following steps to authenticate with a certificate instead of a user
215
215
  See [this post](http://www.hurryupandwait.io/blog/certificate-password-less-based-authentication-in-winrm) for more details on certificate authentication.
216
216
 
217
217
  ## Logging
218
- The `WinRM::Connection` exposes a `logger` attribute and uses the [logging](https://rubygems.org/gems/logging) gem to manage logging behavior. By default this appends to `STDOUT` and has a level of `:warn`, but one can adjust the level or add additional appenders.
218
+ The `WinRM::Connection` exposes a `logger` attribute and uses the Ruby standard library [Logger](https://docs.ruby-lang.org/en/master/Logger.html). By default this logs to `STDOUT` with a level of `:warn`, but one can adjust the level or replace the logger entirely.
219
219
  ```ruby
220
220
  conn = WinRM::Connection.new(opts)
221
221
 
@@ -223,14 +223,18 @@ conn = WinRM::Connection.new(opts)
223
223
  conn.logger.level = :error
224
224
 
225
225
  # Log to a file
226
- conn.logger.add_appenders(Logging.appenders.file('error.log'))
226
+ conn.logger = Logger.new('error.log')
227
227
  ```
228
228
 
229
- If a consuming application uses its own logger that complies to the logging API, you can simply swap it in:
229
+ The default log level can also be set with the `WINRM_LOG` environment variable (`debug`, `info`, `warn`, `error` or `fatal`).
230
+
231
+ If a consuming application uses its own logger that complies to the stdlib `Logger` API, you can simply swap it in:
230
232
  ```ruby
231
233
  conn.logger = my_logger
232
234
  ```
233
235
 
236
+ Upgrading from the `logging` gem: the one `logging`-specific call that used to work, `conn.logger.add_appenders(...)`, is still accepted but logs a deprecation warning and has no effect. Configure the stdlib logger directly (or inject your own) instead.
237
+
234
238
  ## Troubleshooting
235
239
  You may have some errors like ```WinRM::WinRMAuthorizationError```. See [this post](http://www.hurryupandwait.io/blog/understanding-and-troubleshooting-winrm-connection-and-authentication-a-thrill-seekers-guide-to-adventure) for tips and troubleshooting steps related to winrm connection and authentication issues.
236
240
 
@@ -241,7 +245,7 @@ You may have some errors like ```WinRM::WinRMAuthorizationError```. See [this po
241
245
  3. Run the unit and integration tests (bundle exec rake integration)
242
246
  4. Commit your changes (git commit -am "Added a sweet feature")
243
247
  5. Push to the branch (git push origin my_feature_branch)
244
- 6. Create a pull requst from your branch into master (Please be sure to provide enough detail for us to cipher what this change is doing)
248
+ 6. Create a pull request from your branch into main (Please be sure to provide enough detail for us to cipher what this change is doing)
245
249
 
246
250
  ### Running the tests
247
251
 
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'logger'
4
+
5
+ module WinRM
6
+ # Backwards-compatible default for `Connection#logger`.
7
+ #
8
+ # WinRM used to expose a `logging`-gem logger here; it now exposes a plain
9
+ # stdlib {Logger} instead. This subclass keeps the small `logging`-specific
10
+ # API callers actually used (`add_appenders`) working while emitting a
11
+ # deprecation warning, so existing code keeps running instead of breaking
12
+ # on upgrade. Everything else is exactly stdlib `Logger` behavior.
13
+ class CompatLogger < ::Logger
14
+ # Accepts `logging`-gem-style appenders for backwards compatibility.
15
+ # Stdlib loggers write to their log device, so appenders have no
16
+ # equivalent here and are ignored.
17
+ def add_appenders(*_appenders)
18
+ deprecate_appenders unless @appenders_deprecated
19
+ nil
20
+ end
21
+
22
+ private
23
+
24
+ def deprecate_appenders
25
+ @appenders_deprecated = true
26
+ Kernel.warn '[DEPRECATION] WinRM: `logger.add_appenders` is deprecated and has no effect. ' \
27
+ 'Configure the stdlib logger directly or inject your own via `Connection#logger=`.'
28
+ end
29
+ end
30
+ end
@@ -65,9 +65,7 @@ module WinRM
65
65
  end
66
66
 
67
67
  def configure_logger
68
- @logger = Logging.logger[self]
69
- logger.level = :warn
70
- logger.add_appenders(Logging.appenders.stdout)
68
+ @logger = WinRM::CompatLogger.new($stdout, progname: 'WinRM', level: WinRM.default_log_level)
71
69
  end
72
70
 
73
71
  def shell_factory
@@ -77,7 +75,7 @@ module WinRM
77
75
  def transport
78
76
  @transport ||= begin
79
77
  transport_factory = WinRM::HTTP::TransportFactory.new
80
- transport_factory.create_transport(@connection_opts)
78
+ transport_factory.create_transport(@connection_opts.merge(logger: logger))
81
79
  end
82
80
  end
83
81
  end
@@ -26,7 +26,8 @@ module WinRM
26
26
  def initialize(endpoint, options)
27
27
  @endpoint = endpoint.is_a?(String) ? URI.parse(endpoint) : endpoint
28
28
  @httpcli = HTTPClient.new
29
- @logger = Logging.logger[self]
29
+ @logger = options[:logger] ||
30
+ Logger.new($stdout, progname: 'WinRM', level: WinRM.default_log_level)
30
31
  @httpcli.receive_timeout = options[:receive_timeout]
31
32
  @httpcli.default_header = { 'User-Agent': options[:user_agent] }
32
33
  end
@@ -19,27 +19,27 @@ module WinRM
19
19
  # PowerShell Remoting Protocol message fragment.
20
20
  class Fragment
21
21
  # Creates a new PSRP message fragment
22
- # @param object_id [Integer] The id of the fragmented message.
22
+ # @param message_id [Integer] The id of the fragmented message.
23
23
  # @param blob [Array] Array of fragmented bytes.
24
24
  # @param fragment_id [Integer] The id of this fragment
25
25
  # @param start_fragment [Boolean] If the fragment is the first fragment
26
26
  # @param end_fragment [Boolean] If the fragment is the last fragment
27
- def initialize(object_id, blob, fragment_id = 0, start_fragment = true, end_fragment = true)
28
- @object_id = object_id
27
+ def initialize(message_id, blob, fragment_id = 0, start_fragment = true, end_fragment = true)
28
+ @message_id = message_id
29
29
  @blob = blob
30
30
  @fragment_id = fragment_id
31
31
  @start_fragment = start_fragment
32
32
  @end_fragment = end_fragment
33
33
  end
34
34
 
35
- attr_reader :object_id, :fragment_id, :end_fragment, :start_fragment, :blob
35
+ attr_reader :message_id, :fragment_id, :end_fragment, :start_fragment, :blob
36
36
 
37
37
  # Returns the raw PSRP message bytes ready for transfer to Windows inside a
38
38
  # WinRM message.
39
39
  # @return [Array<Byte>] Unencoded raw byte array of the PSRP message.
40
40
  def bytes
41
41
  [
42
- int64be(object_id),
42
+ int64be(message_id),
43
43
  int64be(fragment_id),
44
44
  end_start_fragment,
45
45
  int16be(blob.length),
@@ -26,13 +26,13 @@ module WinRM
26
26
  def defragment(base64_bytes)
27
27
  fragment = fragment_from(Base64.decode64(base64_bytes))
28
28
 
29
- @messages[fragment.object_id] ||= []
30
- @messages[fragment.object_id].push fragment
29
+ @messages[fragment.message_id] ||= []
30
+ @messages[fragment.message_id].push fragment
31
31
 
32
32
  # rubocop:disable Style/GuardClause
33
33
  if fragment.end_fragment
34
34
  blob = []
35
- @messages.delete(fragment.object_id).each { |frag| blob += frag.blob }
35
+ @messages.delete(fragment.message_id).each { |frag| blob += frag.blob }
36
36
  return message_from(blob.pack('C*'))
37
37
  end
38
38
  # rubocop:enable Style/GuardClause
@@ -22,15 +22,15 @@ module WinRM
22
22
  DEFAULT_BLOB_LENGTH = 32_768
23
23
 
24
24
  def initialize(max_blob_length = DEFAULT_BLOB_LENGTH)
25
- @object_id = 0
25
+ @message_id = 0
26
26
  @max_blob_length = max_blob_length || DEFAULT_BLOB_LENGTH
27
27
  end
28
28
 
29
- attr_reader :object_id
29
+ attr_reader :message_id
30
30
  attr_accessor :max_blob_length
31
31
 
32
32
  def fragment(message)
33
- @object_id += 1
33
+ @message_id += 1
34
34
  message_bytes = message.bytes
35
35
  bytes_fragmented = 0
36
36
  fragment_id = 0
@@ -40,7 +40,7 @@ module WinRM
40
40
  last_byte = bytes_fragmented + max_blob_length
41
41
  last_byte = message_bytes.length if last_byte > message_bytes.length
42
42
  fragment = Fragment.new(
43
- object_id,
43
+ message_id,
44
44
  message.bytes[bytes_fragmented..last_byte - 1],
45
45
  fragment_id,
46
46
  bytes_fragmented.zero?,
@@ -94,8 +94,36 @@ module WinRM
94
94
  @shell_id = nil
95
95
  end
96
96
 
97
+ # Ruby 3.1+ introduced a change where finalizers cannot allocate new threads.
98
+ # This can raise a ThreadError when the WinRM shell cleanup tries to run in a Thread
99
+ # during garbage collection. Previously, the gem used Thread.new in finalizers.
100
+ #
101
+ # Our solution preserves original behavior safely:
102
+ # 1. Attempt cleanup in a new thread (same as before) for normal execution.
103
+ # 2. If a ThreadError occurs specifically due to "can't alloc thread",
104
+ # defer cleanup to an at_exit block to ensure the shell is closed properly
105
+ # without crashing the program.
106
+ # 3. Any other ThreadError is re-raised to avoid hiding unexpected issues.
97
107
  def self.finalize(connection_opts, transport, shell_id)
98
- proc { Thread.new { close_shell(connection_opts, transport, shell_id) } }
108
+ proc do
109
+ begin
110
+ # Attempt normal cleanup in a new thread (preserves existing behavior)
111
+ Thread.new { close_shell(connection_opts, transport, shell_id) }
112
+ rescue ThreadError => e
113
+ # Only handle the specific Ruby 3.1+ GC thread allocation restriction
114
+ raise unless e.message.include?("can't alloc thread")
115
+
116
+ # Defer cleanup to at_exit when thread allocation is permitted
117
+ at_exit do
118
+ begin
119
+ close_shell(connection_opts, transport, shell_id)
120
+ rescue StandardError => cleanup_error
121
+ # Warn about cleanup failures in deferred context only
122
+ warn "[WinRM] Deferred shell cleanup failed: #{cleanup_error.class}: #{cleanup_error.message}"
123
+ end
124
+ end
125
+ end
126
+ end
99
127
  end
100
128
 
101
129
  protected
data/lib/winrm/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # WinRM module
2
2
  module WinRM
3
3
  # The version of the WinRM library
4
- VERSION = '2.3.9'.freeze
4
+ VERSION = '2.4.0'.freeze
5
5
  end
data/lib/winrm.rb CHANGED
@@ -1,37 +1,43 @@
1
- # Copyright 2010 Dan Wanek <dan.wanek@gmail.com>
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
- require 'logging'
16
- require_relative 'winrm/version'
17
- require_relative 'winrm/connection'
18
- require_relative 'winrm/exceptions'
19
-
20
- # Main WinRM module entry point
21
- module WinRM
22
- # Enable logging if it is requested. We do this before
23
- # anything else so that we can setup the output before
24
- # any logging occurs.
25
- if ENV['WINRM_LOG'] && ENV['WINRM_LOG'] != ''
26
- begin
27
- Logging.logger.root.level = ENV['WINRM_LOG']
28
- Logging.logger.root.appenders = Logging.appenders.stderr
29
- rescue ArgumentError
30
- # This means that the logging level wasn't valid
31
- warn "Invalid WINRM_LOG level is set: #{ENV['WINRM_LOG']}"
32
- warn ''
33
- warn 'Please use one of the standard log levels: ' \
34
- 'debug, info, warn, or error'
35
- end
36
- end
37
- end
1
+ # Copyright 2010 Dan Wanek <dan.wanek@gmail.com>
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'logger'
16
+ require_relative 'winrm/compat_logger'
17
+ require_relative 'winrm/version'
18
+ require_relative 'winrm/connection'
19
+ require_relative 'winrm/exceptions'
20
+
21
+ # Main WinRM module entry point
22
+ module WinRM
23
+ LOG_LEVELS = %w[debug info warn error fatal].freeze
24
+
25
+ # Default log level used by WinRM loggers, controlled by the
26
+ # WINRM_LOG environment variable. Falls back to :warn when unset
27
+ # or invalid.
28
+ # @return [Symbol] One of :debug, :info, :warn, :error or :fatal
29
+ def self.default_log_level
30
+ level = ENV.fetch('WINRM_LOG', '').downcase
31
+ return :warn if level.empty?
32
+
33
+ unless LOG_LEVELS.include?(level)
34
+ warn "Invalid WINRM_LOG level is set: #{ENV.fetch('WINRM_LOG', nil)}"
35
+ warn ''
36
+ warn 'Please use one of the standard log levels: ' \
37
+ 'debug, info, warn, or error'
38
+ return :warn
39
+ end
40
+
41
+ level.to_sym
42
+ end
43
+ end
metadata CHANGED
@@ -1,18 +1,31 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: winrm
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.9
4
+ version: 2.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Wanek
8
8
  - Paul Morton
9
9
  - Matt Wrock
10
10
  - Shawn Neal
11
- autorequire:
12
11
  bindir: bin
13
12
  cert_chain: []
14
- date: 2024-08-02 00:00:00.000000000 Z
13
+ date: 2026-09-10 00:00:00.000000000 Z
15
14
  dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: base64
17
+ requirement: !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - "~>"
20
+ - !ruby/object:Gem::Version
21
+ version: '0.2'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - "~>"
27
+ - !ruby/object:Gem::Version
28
+ version: '0.2'
16
29
  - !ruby/object:Gem::Dependency
17
30
  name: builder
18
31
  requirement: !ruby/object:Gem::Requirement
@@ -90,25 +103,19 @@ dependencies:
90
103
  - !ruby/object:Gem::Version
91
104
  version: 2.2.0.2
92
105
  - !ruby/object:Gem::Dependency
93
- name: logging
106
+ name: logger
94
107
  requirement: !ruby/object:Gem::Requirement
95
108
  requirements:
96
- - - ">="
97
- - !ruby/object:Gem::Version
98
- version: 1.6.1
99
- - - "<"
109
+ - - "~>"
100
110
  - !ruby/object:Gem::Version
101
- version: '3.0'
111
+ version: '1.6'
102
112
  type: :runtime
103
113
  prerelease: false
104
114
  version_requirements: !ruby/object:Gem::Requirement
105
115
  requirements:
106
- - - ">="
107
- - !ruby/object:Gem::Version
108
- version: 1.6.1
109
- - - "<"
116
+ - - "~>"
110
117
  - !ruby/object:Gem::Version
111
- version: '3.0'
118
+ version: '1.6'
112
119
  - !ruby/object:Gem::Dependency
113
120
  name: nori
114
121
  requirement: !ruby/object:Gem::Requirement
@@ -161,22 +168,16 @@ dependencies:
161
168
  name: rake
162
169
  requirement: !ruby/object:Gem::Requirement
163
170
  requirements:
164
- - - ">="
165
- - !ruby/object:Gem::Version
166
- version: '10.3'
167
- - - "<"
171
+ - - "~>"
168
172
  - !ruby/object:Gem::Version
169
- version: '13'
173
+ version: '13.0'
170
174
  type: :development
171
175
  prerelease: false
172
176
  version_requirements: !ruby/object:Gem::Requirement
173
177
  requirements:
174
- - - ">="
175
- - !ruby/object:Gem::Version
176
- version: '10.3'
177
- - - "<"
178
+ - - "~>"
178
179
  - !ruby/object:Gem::Version
179
- version: '13'
180
+ version: '13.0'
180
181
  - !ruby/object:Gem::Dependency
181
182
  name: rb-readline
182
183
  requirement: !ruby/object:Gem::Requirement
@@ -211,14 +212,14 @@ dependencies:
211
212
  requirements:
212
213
  - - "~>"
213
214
  - !ruby/object:Gem::Version
214
- version: 1.26.0
215
+ version: '1.87'
215
216
  type: :development
216
217
  prerelease: false
217
218
  version_requirements: !ruby/object:Gem::Requirement
218
219
  requirements:
219
220
  - - "~>"
220
221
  - !ruby/object:Gem::Version
221
- version: 1.26.0
222
+ version: '1.87'
222
223
  - !ruby/object:Gem::Dependency
223
224
  name: rubyntlm
224
225
  requirement: !ruby/object:Gem::Requirement
@@ -249,13 +250,14 @@ executables:
249
250
  - rwinrm
250
251
  extensions: []
251
252
  extra_rdoc_files:
252
- - README.md
253
253
  - LICENSE
254
+ - README.md
254
255
  files:
255
256
  - LICENSE
256
257
  - README.md
257
258
  - bin/rwinrm
258
259
  - lib/winrm.rb
260
+ - lib/winrm/compat_logger.rb
259
261
  - lib/winrm/connection.rb
260
262
  - lib/winrm/connection_opts.rb
261
263
  - lib/winrm/exceptions.rb
@@ -313,7 +315,6 @@ licenses:
313
315
  - Apache-2.0
314
316
  metadata:
315
317
  rubygems_mfa_required: 'true'
316
- post_install_message:
317
318
  rdoc_options:
318
319
  - "-x"
319
320
  - test/
@@ -325,15 +326,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
325
326
  requirements:
326
327
  - - ">="
327
328
  - !ruby/object:Gem::Version
328
- version: '3.0'
329
+ version: '3.2'
329
330
  required_rubygems_version: !ruby/object:Gem::Requirement
330
331
  requirements:
331
332
  - - ">="
332
333
  - !ruby/object:Gem::Version
333
334
  version: '0'
334
335
  requirements: []
335
- rubygems_version: 3.5.11
336
- signing_key:
336
+ rubygems_version: 3.6.9
337
337
  specification_version: 4
338
338
  summary: Ruby library for Windows Remote Management
339
339
  test_files: []