ruby-pwsh 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eb7a2c9a103865f74de54ae3a977a70382a2b18ff2e1f8f830b25ef50f4ba1d2
4
- data.tar.gz: 7ca9acbd7478367673a8f761a0b51ddf5f0359246b3ca72f7fe9b8e4c3da34a6
3
+ metadata.gz: e217873cdddb9b32ba467e0a9f5de6977c04b11a1c0788613dda6181e96a62bd
4
+ data.tar.gz: 8dc82dfad8869d7c632ba3d902b4e22c375aeb5988f84e359269163da885b604
5
5
  SHA512:
6
- metadata.gz: 830c6e92076e50675f1ce02445f9fd9952545987af24e152bb164b11223d35d47d3619c997bf51b9b09293b22d69d2c832e689f59cfbad1118663203af374046
7
- data.tar.gz: 5e107bcb95cc294f2c421d565c3376b21a7272b4bd4e4c32684f4481577398e2fa54c5005f8e6d990a7d9ffebf2db5eca5dbdb7eba2b2c7ddb2660ca65315f04
6
+ metadata.gz: a7e02f1cee48fa49316c133268a16f9bc3b8f195927834854c81eee134cdb7056710cd1be04eaf992ca036aa2b014175d06ebf8684eef6354ef8d10a07a62e31
7
+ data.tar.gz: da78f276002b67faf3716ce0b8157fe3cf0edbbeb5da3ae1145c3ed696e386838285138fdd0c75b8a592b677b7631c66ce07355a25788dee58354af0ecdd9eaa
data/README.md CHANGED
@@ -86,6 +86,10 @@ The following platforms are supported:
86
86
  - RedHat
87
87
  - Ubuntu
88
88
 
89
+ ## Limitations
90
+
91
+ - When PowerShell [Script Block Logging](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_logging_windows?view=powershell-7.4#enabling-script-block-logging) is enabled, data marked as sensitive in your manifest may appear in these logs as plain text. It is **highly recommended**, by both Puppet and Microsoft, that you also enable [Protected Event Logging](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_logging_windows?view=powershell-7.4#protected-event-logging) alongside this to encrypt the logs to protect this information.
92
+
89
93
  ## License
90
94
 
91
95
  This codebase is licensed under Apache 2.0. However, the open source dependencies included in this codebase might be subject to other software licenses such as AGPL, GPL2.0, and MIT.
@@ -15,6 +15,7 @@ class Puppet::Provider::DscBaseProvider # rubocop:disable Metrics/ClassLength
15
15
  @cached_query_results = []
16
16
  @cached_test_results = []
17
17
  @logon_failures = []
18
+ @timeout = nil # default timeout, ps_manager.execute is expecting nil by default..
18
19
  super
19
20
  end
20
21
 
@@ -44,6 +45,7 @@ class Puppet::Provider::DscBaseProvider # rubocop:disable Metrics/ClassLength
44
45
  # @param context [Object] the Puppet runtime context to operate in and send feedback to
45
46
  # @param resources [Hash] the hash of the resource to canonicalize from either manifest or invocation
46
47
  # @return [Hash] returns a hash representing the current state of the object, if it exists
48
+ # rubocop:disable Metrics/BlockLength, Metrics/MethodLength
47
49
  def canonicalize(context, resources)
48
50
  canonicalized_resources = []
49
51
  resources.collect do |r|
@@ -83,9 +85,18 @@ class Puppet::Provider::DscBaseProvider # rubocop:disable Metrics/ClassLength
83
85
  downcased_result.each do |key, value|
84
86
  # Canonicalize to the manifest value unless the downcased strings match and the attribute is not an enum:
85
87
  # - When the values don't match at all, the manifest value is desired;
86
- # - When the values match case insensitively but the attribute is an enum, prefer the casing of the manifest enum.
87
- # - When the values match case insensitively and the attribute is not an enum, prefer the casing from invoke_get_method
88
- canonicalized[key] = r[key] unless same?(value, downcased_resource[key]) && !enum_attributes(context).include?(key)
88
+ # - When the values match case insensitively but the attribute is an enum, and the casing from invoke_get_method
89
+ # is not int the enum, prefer the casing of the manifest enum.
90
+ # - When the values match case insensitively and the attribute is not an enum, or is an enum and invoke_get_method casing
91
+ # is in the enum, prefer the casing from invoke_get_method
92
+ is_enum = enum_attributes(context).include?(key)
93
+ canonicalized_value_in_enum = if is_enum
94
+ enum_values(context, key).include?(canonicalized[key])
95
+ else
96
+ false
97
+ end
98
+ match_insensitively = same?(value, downcased_resource[key])
99
+ canonicalized[key] = r[key] unless match_insensitively && (canonicalized_value_in_enum || !is_enum)
89
100
  canonicalized.delete(key) unless downcased_resource.key?(key)
90
101
  end
91
102
  # Cache the actually canonicalized resource separately
@@ -104,6 +115,7 @@ class Puppet::Provider::DscBaseProvider # rubocop:disable Metrics/ClassLength
104
115
  context.debug("Canonicalized Resources: #{canonicalized_resources}")
105
116
  canonicalized_resources
106
117
  end
118
+ # rubocop:enable Metrics/BlockLength, Metrics/MethodLength
107
119
 
108
120
  # Attempts to retrieve an instance of the DSC resource, invoking the `Get` method and passing any
109
121
  # namevars as the Properties to Invoke-DscResource. The result object, if any, is compared to the
@@ -240,18 +252,22 @@ class Puppet::Provider::DscBaseProvider # rubocop:disable Metrics/ClassLength
240
252
  context.err('Logon credentials are invalid')
241
253
  return nil
242
254
  end
255
+ specify_dsc_timeout(name_hash)
243
256
  resource = invocable_resource(props, context, method)
244
257
  script_content = ps_script_content(resource)
258
+ context.debug("Invoke-DSC Timeout: #{@timeout} milliseconds") if @timeout
245
259
  context.debug("Script:\n #{redact_secrets(script_content)}")
246
- output = ps_manager.execute(remove_secret_identifiers(script_content))[:stdout]
260
+ output = ps_manager.execute(remove_secret_identifiers(script_content), @timeout)
247
261
 
248
- if output.nil?
249
- context.err('Nothing returned')
262
+ if output[:stdout].nil?
263
+ message = 'Nothing returned.'
264
+ message += " #{output[:errormessage]}" if output[:errormessage]&.match?(/PowerShell module timeout \(\d+ ms\) exceeded while executing/)
265
+ context.err(message)
250
266
  return nil
251
267
  end
252
268
 
253
269
  begin
254
- data = JSON.parse(output)
270
+ data = JSON.parse(output[:stdout])
255
271
  rescue StandardError => e
256
272
  context.err(e)
257
273
  return nil
@@ -284,6 +300,18 @@ class Puppet::Provider::DscBaseProvider # rubocop:disable Metrics/ClassLength
284
300
  data
285
301
  end
286
302
 
303
+ # Sets the @timeout instance variable.
304
+ # @param name_hash [Hash] the hash of namevars to be passed as properties to `Invoke-DscResource`
305
+ # The @timeout variable is set to the value of name_hash[:dsc_timeout] in milliseconds
306
+ # If name_hash[:dsc_timeout] is nil, @timeout is not changed.
307
+ # If @timeout is already set to a value other than nil,
308
+ # it is changed only if it's different from name_hash[:dsc_timeout]..
309
+ def specify_dsc_timeout(name_hash)
310
+ return unless name_hash[:dsc_timeout] && (@timeout.nil? || @timeout != name_hash[:dsc_timeout])
311
+
312
+ @timeout = name_hash[:dsc_timeout] * 1000
313
+ end
314
+
287
315
  # Retries Invoke-DscResource when returned error matches error regex supplied as param.
288
316
  # @param context [Object] the Puppet runtime context to operate in and send feedback to
289
317
  # @param max_retry_count [Int] max number of times to retry Invoke-DscResource
@@ -299,24 +327,16 @@ class Puppet::Provider::DscBaseProvider # rubocop:disable Metrics/ClassLength
299
327
  # notify and retry
300
328
  context.notice("Retrying: attempt #{try} of #{max_retry_count}.")
301
329
  data = JSON.parse(yield)
302
- # if no error, break
303
- if data['errormessage'].nil?
304
- break
305
- # check if error matches error matcher supplied
306
- elsif data['errormessage'].match?(error_matcher)
307
- # if last attempt, return error
308
- if try == max_retry_count
309
- context.notice("Attempt #{try} of #{max_retry_count} failed. No more retries.")
310
- # all attempts failed, raise error
311
- return context.err(data['errormessage'])
312
- end
313
- # if not last attempt, notify, continue and retry
314
- context.notice("Attempt #{try} of #{max_retry_count} failed.")
315
- next
316
- else
317
- # if we get an unexpected error, return
318
- return context.err(data['errormessage'])
319
- end
330
+ # if no error, assume successful invocation and break
331
+ break if data['errormessage'].nil?
332
+
333
+ # notify of failed retry
334
+ context.notice("Attempt #{try} of #{max_retry_count} failed.")
335
+ # return if error does not match expceted error, or all retries exhausted
336
+ return context.err(data['errormessage']) unless data['errormessage'].match?(error_matcher) && try < max_retry_count
337
+
338
+ # else, retry
339
+ next
320
340
  end
321
341
  data
322
342
  end
@@ -348,7 +368,7 @@ class Puppet::Provider::DscBaseProvider # rubocop:disable Metrics/ClassLength
348
368
  # @param context [Object] the Puppet runtime context to operate in and send feedback to
349
369
  # @param name_hash [Hash] the hash of namevars to be passed as properties to `Invoke-DscResource`
350
370
  # @return [Hash] returns a hash representing the DSC resource munged to the representation the Puppet Type expects
351
- def invoke_get_method(context, name_hash)
371
+ def invoke_get_method(context, name_hash) # rubocop:disable Metrics/AbcSize
352
372
  context.debug("retrieving #{name_hash.inspect}")
353
373
 
354
374
  query_props = name_hash.select { |k, v| mandatory_get_attributes(context).include?(k) || (k == :dsc_psdscrunascredential && !v.nil?) }
@@ -391,6 +411,8 @@ class Puppet::Provider::DscBaseProvider # rubocop:disable Metrics/ClassLength
391
411
  # If a resource is found, it's present, so refill this Puppet-only key
392
412
  data[:name] = name_hash[:name]
393
413
 
414
+ data = stringify_nil_attributes(context, data)
415
+
394
416
  # Have to check for this to avoid a weird canonicalization warning
395
417
  # The Resource API calls canonicalize against the current state which
396
418
  # will lead to dsc_ensure being set to absent in the name_hash even if
@@ -660,6 +682,20 @@ class Puppet::Provider::DscBaseProvider # rubocop:disable Metrics/ClassLength
660
682
  context.type.attributes.select { |_attribute, properties| properties[:mandatory_for_set] }.keys
661
683
  end
662
684
 
685
+ # Parses the DSC resource type definition to retrieve the names of any attributes which are specified as required strings
686
+ # This is used to ensure that any nil values are converted to empty strings to match puppets expected value
687
+ # @param context [Object] the Puppet runtime context to operate in and send feedback to
688
+ # @param data [Hash] the hash of properties returned from the DSC resource
689
+ # @return [Hash] returns a data hash with any nil values converted to empty strings
690
+ def stringify_nil_attributes(context, data)
691
+ nil_attributes = data.select { |_name, value| value.nil? }.keys
692
+ nil_attributes.each do |nil_attr|
693
+ attribute_type = context.type.attributes[nil_attr][:type]
694
+ data[nil_attr] = '' if (attribute_type.include?('Enum[') && enum_values(context, nil_attr).include?('')) || attribute_type == 'String'
695
+ end
696
+ data
697
+ end
698
+
663
699
  # Parses the DSC resource type definition to retrieve the names of any attributes which are specified as namevars
664
700
  #
665
701
  # @param context [Object] the Puppet runtime context to operate in and send feedback to
@@ -686,6 +722,28 @@ class Puppet::Provider::DscBaseProvider # rubocop:disable Metrics/ClassLength
686
722
  context.type.attributes.select { |_name, properties| properties[:type].include?('Enum[') }.keys
687
723
  end
688
724
 
725
+ # Parses the DSC resource type definition to retrieve the values of any attributes which are specified as enums
726
+ #
727
+ # @param context [Object] the Puppet runtime context to operate in and send feedback to
728
+ # @param attribute [String] the enum attribute to retrieve the allowed values from
729
+ # @return [Array] returns an array of attribute names as symbols which are enums
730
+ def enum_values(context, attribute)
731
+ # Get the attribute's type string for the given key
732
+ type_string = context.type.attributes[attribute][:type]
733
+
734
+ # Return an empty array if the key doesn't have an Enum type or doesn't exist
735
+ return [] unless type_string&.include?('Enum[')
736
+
737
+ # Extract the enum values from the type string
738
+ enum_content = type_string.match(/Enum\[(.*?)\]/)&.[](1)
739
+
740
+ # Return an empty array if we couldn't find the enum values
741
+ return [] if enum_content.nil?
742
+
743
+ # Return an array of the enum values, stripped of extra whitespace and quote marks
744
+ enum_content.split(',').map { |val| val.strip.delete('\'') }
745
+ end
746
+
689
747
  # Look through a fully formatted string, replacing all instances where a value matches the formatted properties
690
748
  # of an instantiated variable with references to the variable instead. This allows us to pass complex and nested
691
749
  # CIM instances to the Invoke-DscResource parameter hash without constructing them *in* the hash.
@@ -1035,6 +1093,10 @@ class Puppet::Provider::DscBaseProvider # rubocop:disable Metrics/ClassLength
1035
1093
  def ps_manager
1036
1094
  debug_output = Puppet::Util::Log.level == :debug
1037
1095
  # TODO: Allow you to specify an alternate path, either to pwsh generally or a specific pwsh path.
1038
- Pwsh::Manager.instance(Pwsh::Manager.powershell_path, Pwsh::Manager.powershell_args, debug: debug_output)
1096
+ if Pwsh::Util.on_windows?
1097
+ Pwsh::Manager.instance(Pwsh::Manager.powershell_path, Pwsh::Manager.powershell_args, debug: debug_output)
1098
+ else
1099
+ Pwsh::Manager.instance(Pwsh::Manager.pwsh_path, Pwsh::Manager.pwsh_args, debug: debug_output)
1100
+ end
1039
1101
  end
1040
1102
  end
@@ -123,4 +123,4 @@ Function ConvertTo-CanonicalResult {
123
123
 
124
124
  # Output the final result
125
125
  $ResultObject
126
- }
126
+ }
data/lib/pwsh/util.rb CHANGED
@@ -7,12 +7,12 @@ module Pwsh
7
7
  module_function
8
8
 
9
9
  # Verifies whether or not the current context is running on a Windows node.
10
+ # Implementation copied from `facets`: https://github.com/rubyworks/facets/blob/main/lib/standard/facets/rbconfig.rb
10
11
  #
11
12
  # @return [Bool] true if on windows
12
13
  def on_windows?
13
- # Ruby only sets File::ALT_SEPARATOR on Windows and the Ruby standard
14
- # library uses that to test what platform it's on.
15
- !!File::ALT_SEPARATOR
14
+ host_os = RbConfig::CONFIG['host_os']
15
+ !!(host_os =~ /mswin|mingw/)
16
16
  end
17
17
 
18
18
  # Verify paths specified are valid directories which exist.
data/lib/pwsh/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Pwsh
4
4
  # The version of the ruby-pwsh gem
5
- VERSION = '1.1.0'
5
+ VERSION = '1.2.0'
6
6
  end
data/lib/pwsh.rb CHANGED
@@ -380,7 +380,7 @@ module Pwsh
380
380
  pwsh_paths << File.join(path, 'pwsh.exe') if File.exist?(File.join(path, 'pwsh.exe'))
381
381
  end
382
382
  else
383
- search_paths.split(File::PATH_SEPARATOR).each do |path|
383
+ search_paths.split(':').each do |path|
384
384
  pwsh_paths << File.join(path, 'pwsh') if File.exist?(File.join(path, 'pwsh'))
385
385
  end
386
386
  end
@@ -179,6 +179,8 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
179
179
  end
180
180
 
181
181
  it 'treats the manifest value as canonical' do
182
+ expect(context).to receive(:type).and_return(type)
183
+ expect(type).to receive(:attributes).and_return({ dsc_property: { type: "Enum['Dword']" } })
182
184
  expect(canonicalized_resource.first[:dsc_property]).to eq('Dword')
183
185
  end
184
186
  end
@@ -539,7 +541,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
539
541
 
540
542
  context 'when the invocation script returns data without errors' do
541
543
  before do
542
- allow(ps_manager).to receive(:execute).with(script).and_return({ stdout: 'DSC Data' })
544
+ allow(ps_manager).to receive(:execute).with(script, nil).and_return({ stdout: 'DSC Data' })
543
545
  allow(JSON).to receive(:parse).with('DSC Data').and_return(parsed_invocation_data)
544
546
  allow(Puppet::Pops::Time::Timestamp).to receive(:parse).with('2100-01-01').and_return('TimeStamp:2100-01-01')
545
547
  allow(provider).to receive(:fetch_cached_hashes).and_return([])
@@ -657,15 +659,15 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
657
659
  context 'when the DSC invocation errors' do
658
660
  it 'writes an error and returns nil' do
659
661
  expect(provider).not_to receive(:logon_failed_already?)
660
- expect(ps_manager).to receive(:execute).with(script).and_return({ stdout: nil })
661
- expect(context).to receive(:err).with('Nothing returned')
662
+ expect(ps_manager).to receive(:execute).with(script, nil).and_return({ stdout: nil })
663
+ expect(context).to receive(:err).with('Nothing returned.')
662
664
  expect(result).to be_nil
663
665
  end
664
666
  end
665
667
 
666
668
  context 'when handling DateTimes' do
667
669
  before do
668
- allow(ps_manager).to receive(:execute).with(script).and_return({ stdout: 'DSC Data' })
670
+ allow(ps_manager).to receive(:execute).with(script, nil).and_return({ stdout: 'DSC Data' })
669
671
  allow(JSON).to receive(:parse).with('DSC Data').and_return(parsed_invocation_data)
670
672
  allow(provider).to receive(:fetch_cached_hashes).and_return([])
671
673
  end
@@ -717,7 +719,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
717
719
  context 'when the credential is invalid' do
718
720
  before do
719
721
  allow(provider).to receive(:logon_failed_already?).and_return(false)
720
- allow(ps_manager).to receive(:execute).with(script).and_return({ stdout: 'DSC Data' })
722
+ allow(ps_manager).to receive(:execute).with(script, nil).and_return({ stdout: 'DSC Data' })
721
723
  allow(JSON).to receive(:parse).with('DSC Data').and_return({ 'errormessage' => dsc_logon_failure_error })
722
724
  allow(context).to receive(:err).with(name_hash[:name], puppet_logon_failure_error)
723
725
  end
@@ -781,7 +783,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
781
783
  context 'when the invocation script returns nil' do
782
784
  it 'errors via context but does not raise' do
783
785
  expect(ps_manager).to receive(:execute).and_return({ stdout: nil })
784
- expect(context).to receive(:err).with('Nothing returned')
786
+ expect(context).to receive(:err).with('Nothing returned.')
785
787
  expect { result }.not_to raise_error
786
788
  end
787
789
  end
@@ -812,9 +814,9 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
812
814
  .exactly(5).times
813
815
  expect(context).to receive(:notice).with(/Invoke-DscResource collision detected: Please stagger the timing of your Puppet runs as this can lead to unexpected behaviour./).once
814
816
  expect(context).to receive(:notice).with('Sleeping for 60 seconds.').exactly(5).times
815
- expect(context).to receive(:notice).with(/Retrying: attempt [1-6] of 5/).exactly(5).times
817
+ expect(context).to receive(:notice).with(/Retrying: attempt [1-5] of 5/).exactly(5).times
816
818
  expect(ps_manager).to receive(:execute).and_return({ stdout: '{"errormessage": "The Invoke-DscResource cmdlet is in progress and must return before Invoke-DscResource can be invoked"}' })
817
- expect(context).to receive(:notice).with(/Attempt [1-6] of 5 failed/).exactly(5).times
819
+ expect(context).to receive(:notice).with(/Attempt [1-5] of 5 failed/).exactly(5).times
818
820
  expect(context).to receive(:err).with(/The Invoke-DscResource cmdlet is in progress and must return before Invoke-DscResource can be invoked/)
819
821
  allow(provider).to receive(:sleep)
820
822
  expect(result).to be_nil
@@ -827,14 +829,35 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
827
829
  expect(context).to receive(:notice).with(/Retrying: attempt 1 of 5/).once
828
830
  allow(provider).to receive(:sleep)
829
831
  expect(ps_manager).to receive(:execute).and_return({ stdout: '{"errormessage": "Some unexpected error"}' }).once
832
+ expect(context).to receive(:notice).with(/Attempt 1 of 5 failed/).once
830
833
  expect(context).to receive(:err).with(/Some unexpected error/)
831
834
  expect(result).to be_nil
832
835
  end
833
836
  end
834
837
 
838
+ context 'when a dsc_timeout is specified' do
839
+ let(:should_hash) { name.merge(dsc_timeout: 5) }
840
+ let(:apply_props_with_timeout) { { dsc_name: 'foo', dsc_timeout: 5 } }
841
+ let(:resource_with_timeout) { "Resource: #{apply_props_with_timeout}" }
842
+ let(:script_with_timeout) { "Script: #{apply_props_with_timeout}" }
843
+
844
+ before do
845
+ allow(provider).to receive(:invocable_resource).with(apply_props_with_timeout, context, 'set').and_return(resource_with_timeout)
846
+ allow(provider).to receive(:ps_script_content).with(resource_with_timeout).and_return(script_with_timeout)
847
+ allow(provider).to receive(:remove_secret_identifiers).with(script_with_timeout).and_return(script_with_timeout)
848
+ end
849
+
850
+ it 'sets @timeout and passes it to ps_manager.execute' do
851
+ provider.instance_variable_set(:@timeout, nil)
852
+ expect(ps_manager).to receive(:execute).with(script_with_timeout, 5000).and_return({ stdout: '{"in_desired_state": true, "errormessage": null}' })
853
+ provider.invoke_set_method(context, name, should_hash)
854
+ expect(provider.instance_variable_get(:@timeout)).to eq(5000)
855
+ end
856
+ end
857
+
835
858
  context 'when the invocation script returns data without errors' do
836
859
  it 'filters for the correct properties to invoke and returns the results' do
837
- expect(ps_manager).to receive(:execute).with("Script: #{apply_props}").and_return({ stdout: '{"in_desired_state": true, "errormessage": null}' })
860
+ expect(ps_manager).to receive(:execute).with("Script: #{apply_props}", nil).and_return({ stdout: '{"in_desired_state": true, "errormessage": null}' })
838
861
  expect(context).not_to receive(:err)
839
862
  expect(result).to eq({ 'in_desired_state' => true, 'errormessage' => nil })
840
863
  end
@@ -2107,21 +2130,44 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
2107
2130
  end
2108
2131
 
2109
2132
  describe '.ps_manager' do
2110
- before do
2111
- allow(Pwsh::Manager).to receive(:powershell_path).and_return('pwsh')
2112
- allow(Pwsh::Manager).to receive(:powershell_args).and_return('args')
2113
- end
2133
+ describe '.ps_manager on non-Windows' do
2134
+ before do
2135
+ allow(Pwsh::Util).to receive(:on_windows?).and_return(false)
2136
+ allow(Pwsh::Manager).to receive(:pwsh_path).and_return('pwsh')
2137
+ allow(Pwsh::Manager).to receive(:pwsh_args).and_return('args')
2138
+ end
2139
+
2140
+ it 'Initializes an instance of the Pwsh::Manager' do
2141
+ expect(Puppet::Util::Log).to receive(:level).and_return(:normal)
2142
+ expect(Pwsh::Manager).to receive(:instance).with('pwsh', 'args', debug: false)
2143
+ expect { provider.ps_manager }.not_to raise_error
2144
+ end
2114
2145
 
2115
- it 'Initializes an instance of the Pwsh::Manager' do
2116
- expect(Puppet::Util::Log).to receive(:level).and_return(:normal)
2117
- expect(Pwsh::Manager).to receive(:instance).with('pwsh', 'args', debug: false)
2118
- expect { provider.ps_manager }.not_to raise_error
2146
+ it 'passes debug as true if Puppet::Util::Log.level is debug' do
2147
+ expect(Puppet::Util::Log).to receive(:level).and_return(:debug)
2148
+ expect(Pwsh::Manager).to receive(:instance).with('pwsh', 'args', debug: true)
2149
+ expect { provider.ps_manager }.not_to raise_error
2150
+ end
2119
2151
  end
2120
2152
 
2121
- it 'passes debug as true if Puppet::Util::Log.level is debug' do
2122
- expect(Puppet::Util::Log).to receive(:level).and_return(:debug)
2123
- expect(Pwsh::Manager).to receive(:instance).with('pwsh', 'args', debug: true)
2124
- expect { provider.ps_manager }.not_to raise_error
2153
+ describe '.ps_manager on Windows' do
2154
+ before do
2155
+ allow(Pwsh::Util).to receive(:on_windows?).and_return(true)
2156
+ allow(Pwsh::Manager).to receive(:powershell_path).and_return('pwsh')
2157
+ allow(Pwsh::Manager).to receive(:powershell_args).and_return('args')
2158
+ end
2159
+
2160
+ it 'Initializes an instance of the Pwsh::Manager' do
2161
+ expect(Puppet::Util::Log).to receive(:level).and_return(:normal)
2162
+ expect(Pwsh::Manager).to receive(:instance).with('pwsh', 'args', debug: false)
2163
+ expect { provider.ps_manager }.not_to raise_error
2164
+ end
2165
+
2166
+ it 'passes debug as true if Puppet::Util::Log.level is debug' do
2167
+ expect(Puppet::Util::Log).to receive(:level).and_return(:debug)
2168
+ expect(Pwsh::Manager).to receive(:instance).with('pwsh', 'args', debug: true)
2169
+ expect { provider.ps_manager }.not_to raise_error
2170
+ end
2125
2171
  end
2126
2172
  end
2127
2173
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-pwsh
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Puppet, Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-01-31 00:00:00.000000000 Z
11
+ date: 2024-08-15 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: PowerShell code manager for ruby.
14
14
  email: