chef 16.7.61 → 16.8.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -2
  3. data/README.md +1 -1
  4. data/chef.gemspec +2 -1
  5. data/lib/chef/application/base.rb +1 -1
  6. data/lib/chef/client.rb +3 -0
  7. data/lib/chef/compliance/default_attributes.rb +89 -0
  8. data/lib/chef/compliance/fetcher/automate.rb +69 -0
  9. data/lib/chef/compliance/fetcher/chef_server.rb +134 -0
  10. data/lib/chef/compliance/reporter/automate.rb +202 -0
  11. data/lib/chef/compliance/reporter/chef_server_automate.rb +92 -0
  12. data/lib/chef/compliance/reporter/compliance_enforcer.rb +20 -0
  13. data/lib/chef/compliance/reporter/json_file.rb +19 -0
  14. data/lib/chef/compliance/runner.rb +250 -0
  15. data/lib/chef/cookbook_manifest.rb +1 -0
  16. data/lib/chef/encrypted_data_bag_item/assertions.rb +1 -1
  17. data/lib/chef/exceptions.rb +4 -0
  18. data/lib/chef/http/ssl_policies.rb +6 -0
  19. data/lib/chef/knife/bootstrap/train_connector.rb +1 -1
  20. data/lib/chef/knife/core/ui.rb +4 -1
  21. data/lib/chef/knife/ssh.rb +1 -1
  22. data/lib/chef/mixin/powershell_exec.rb +3 -1
  23. data/lib/chef/platform/query_helpers.rb +4 -4
  24. data/lib/chef/powershell.rb +2 -0
  25. data/lib/chef/provider/dsc_resource.rb +12 -24
  26. data/lib/chef/provider/dsc_script.rb +16 -20
  27. data/lib/chef/provider/git.rb +5 -5
  28. data/lib/chef/resource/chef_client_config.rb +1 -1
  29. data/lib/chef/resource/dsc_script.rb +8 -1
  30. data/lib/chef/resource/hostname.rb +3 -3
  31. data/lib/chef/resource/template.rb +2 -2
  32. data/lib/chef/resource/windows_certificate.rb +7 -1
  33. data/lib/chef/resource_collection/resource_set.rb +1 -1
  34. data/lib/chef/util/dsc/configuration_generator.rb +52 -11
  35. data/lib/chef/util/dsc/lcm_output_parser.rb +3 -4
  36. data/lib/chef/util/dsc/local_configuration_manager.rb +17 -14
  37. data/lib/chef/util/dsc/resource_store.rb +5 -11
  38. data/lib/chef/version.rb +1 -1
  39. data/lib/chef/win32/api/file.rb +4 -0
  40. data/spec/functional/resource/dsc_script_spec.rb +3 -6
  41. data/spec/integration/client/client_spec.rb +2 -1
  42. data/spec/integration/compliance/compliance_spec.rb +81 -0
  43. data/spec/integration/recipes/recipe_dsl_spec.rb +1 -0
  44. data/spec/spec_helper.rb +1 -1
  45. data/spec/unit/client_spec.rb +1 -0
  46. data/spec/unit/compliance/fetcher/automate_spec.rb +134 -0
  47. data/spec/unit/compliance/fetcher/chef_server_spec.rb +93 -0
  48. data/spec/unit/compliance/reporter/automate_spec.rb +427 -0
  49. data/spec/unit/compliance/reporter/chef_server_automate_spec.rb +177 -0
  50. data/spec/unit/compliance/reporter/compliance_enforcer_spec.rb +48 -0
  51. data/spec/unit/compliance/runner_spec.rb +113 -0
  52. data/spec/unit/http/ssl_policies_spec.rb +11 -0
  53. data/spec/unit/knife/core/node_editor_spec.rb +1 -1
  54. data/spec/unit/mixin/powershell_exec_spec.rb +1 -1
  55. data/spec/unit/platform/query_helpers_spec.rb +11 -12
  56. data/spec/unit/provider/dsc_resource_spec.rb +10 -27
  57. data/spec/unit/provider/dsc_script_spec.rb +1 -1
  58. data/spec/unit/provider/mount/windows_spec.rb +1 -0
  59. data/spec/unit/provider/systemd_unit_spec.rb +1 -1
  60. data/spec/unit/resource/windows_certificate_spec.rb +12 -0
  61. data/spec/unit/util/dsc/configuration_generator_spec.rb +79 -0
  62. data/spec/unit/util/dsc/local_configuration_manager_spec.rb +27 -35
  63. metadata +37 -12
  64. data/lib/chef/util/powershell/cmdlet.rb +0 -169
  65. data/lib/chef/util/powershell/cmdlet_result.rb +0 -61
  66. data/spec/functional/util/powershell/cmdlet_spec.rb +0 -111
  67. data/spec/unit/util/powershell/cmdlet_spec.rb +0 -106
@@ -16,25 +16,27 @@
16
16
  # limitations under the License.
17
17
  #
18
18
 
19
- require_relative "../powershell/cmdlet"
19
+ require_relative "../../mixin/powershell_exec"
20
20
  require_relative "lcm_output_parser"
21
21
 
22
22
  class Chef::Util::DSC
23
23
  class LocalConfigurationManager
24
+ include Chef::Mixin::PowershellExec
25
+
24
26
  def initialize(node, configuration_path)
25
27
  @node = node
26
28
  @configuration_path = configuration_path
27
29
  clear_execution_time
28
30
  end
29
31
 
30
- def test_configuration(configuration_document, shellout_flags)
31
- status = run_configuration_cmdlet(configuration_document, false, shellout_flags)
32
- log_dsc_exception(status.stderr) unless status.succeeded?
33
- configuration_update_required?(status.return_value)
32
+ def test_configuration(configuration_document)
33
+ status = run_configuration_cmdlet(configuration_document, false)
34
+ log_dsc_exception(status.errors.join("\n")) if status.error?
35
+ configuration_update_required?(status.result)
34
36
  end
35
37
 
36
- def set_configuration(configuration_document, shellout_flags)
37
- run_configuration_cmdlet(configuration_document, true, shellout_flags)
38
+ def set_configuration(configuration_document)
39
+ run_configuration_cmdlet(configuration_document, true)
38
40
  end
39
41
 
40
42
  def last_operation_execution_time_seconds
@@ -45,7 +47,7 @@ class Chef::Util::DSC
45
47
 
46
48
  private
47
49
 
48
- def run_configuration_cmdlet(configuration_document, apply_configuration, shellout_flags)
50
+ def run_configuration_cmdlet(configuration_document, apply_configuration)
49
51
  Chef::Log.trace("DSC: Calling DSC Local Config Manager to #{apply_configuration ? "set" : "test"} configuration document.")
50
52
 
51
53
  start_operation_timing
@@ -53,11 +55,12 @@ class Chef::Util::DSC
53
55
 
54
56
  begin
55
57
  save_configuration_document(configuration_document)
56
- cmdlet = ::Chef::Util::Powershell::Cmdlet.new(@node, lcm_command(apply_configuration))
58
+ cmd = lcm_command(apply_configuration)
59
+ Chef::Log.trace("DSC: Calling DSC Local Config Manager with:\n#{cmd}")
60
+
61
+ status = powershell_exec(cmd)
57
62
  if apply_configuration
58
- status = cmdlet.run!({}, shellout_flags)
59
- else
60
- status = cmdlet.run({}, shellout_flags)
63
+ status.error!
61
64
  end
62
65
  ensure
63
66
  end_operation_timing
@@ -77,7 +80,7 @@ class Chef::Util::DSC
77
80
  ps4_base_command
78
81
  else
79
82
  if ps_version_gte_5?
80
- "#{common_command_prefix} Test-DscConfiguration -path #{@configuration_path} | format-list"
83
+ "#{common_command_prefix} Test-DscConfiguration -path #{@configuration_path} | format-list | Out-String"
81
84
  else
82
85
  ps4_base_command + " -whatif; if (! $?) { exit 1 }"
83
86
  end
@@ -100,7 +103,7 @@ class Chef::Util::DSC
100
103
  end
101
104
 
102
105
  def whatif_not_supported?(dsc_exception_output)
103
- !! (dsc_exception_output.gsub(/[\r\n]+/, "").gsub(/\s+/, " ") =~ /A parameter cannot be found that matches parameter name 'Whatif'/i)
106
+ !! (dsc_exception_output.gsub(/[\n]+/, "").gsub(/\s+/, " ") =~ /A parameter cannot be found that matches parameter name 'Whatif'/i)
104
107
  end
105
108
 
106
109
  def dsc_module_import_failure?(command_output)
@@ -16,14 +16,14 @@
16
16
  # limitations under the License.
17
17
  #
18
18
 
19
- require_relative "../powershell/cmdlet"
20
- require_relative "../powershell/cmdlet_result"
19
+ require_relative "../../mixin/powershell_exec"
21
20
  require_relative "../../exceptions"
22
21
 
23
22
  class Chef
24
23
  class Util
25
24
  class DSC
26
25
  class ResourceStore
26
+ include Chef::Mixin::PowershellExec
27
27
 
28
28
  def self.instance
29
29
  @@instance ||= ResourceStore.new.tap do |store|
@@ -83,19 +83,13 @@ class Chef
83
83
 
84
84
  # Returns a list of dsc resources
85
85
  def query_resources
86
- cmdlet = Chef::Util::Powershell::Cmdlet.new(nil, "get-dscresource",
87
- :object)
88
- result = cmdlet.run
89
- result.return_value
86
+ powershell_exec("get-dscresource").result
90
87
  end
91
88
 
92
89
  # Returns a list of dsc resources matching the provided name
93
90
  def query_resource(resource_name)
94
- cmdlet = Chef::Util::Powershell::Cmdlet.new(nil, "get-dscresource #{resource_name}",
95
- :object)
96
- result = cmdlet.run
97
- ret_val = result.return_value
98
- if ret_val.nil?
91
+ ret_val = powershell_exec("get-dscresource #{resource_name}").result
92
+ if ret_val.empty?
99
93
  []
100
94
  elsif ret_val.is_a? Array
101
95
  ret_val
@@ -23,7 +23,7 @@ require_relative "version_string"
23
23
 
24
24
  class Chef
25
25
  CHEF_ROOT = File.expand_path("..", __dir__)
26
- VERSION = Chef::VersionString.new("16.7.61")
26
+ VERSION = Chef::VersionString.new("16.8.9")
27
27
  end
28
28
 
29
29
  #
@@ -316,6 +316,7 @@ typedef struct _REPARSE_DATA_BUFFER {
316
316
  string_pointer.read_wstring(self[:PrintNameLength] / 2)
317
317
  end
318
318
  end
319
+
319
320
  class REPARSE_DATA_BUFFER_MOUNT_POINT < FFI::Struct
320
321
  layout :SubstituteNameOffset, :ushort,
321
322
  :SubstituteNameLength, :ushort,
@@ -333,14 +334,17 @@ typedef struct _REPARSE_DATA_BUFFER {
333
334
  string_pointer.read_wstring(self[:PrintNameLength] / 2)
334
335
  end
335
336
  end
337
+
336
338
  class REPARSE_DATA_BUFFER_GENERIC < FFI::Struct
337
339
  layout :DataBuffer, :uchar
338
340
  end
341
+
339
342
  class REPARSE_DATA_BUFFER_UNION < FFI::Union
340
343
  layout :SymbolicLinkReparseBuffer, REPARSE_DATA_BUFFER_SYMBOLIC_LINK,
341
344
  :MountPointReparseBuffer, REPARSE_DATA_BUFFER_MOUNT_POINT,
342
345
  :GenericReparseBuffer, REPARSE_DATA_BUFFER_GENERIC
343
346
  end
347
+
344
348
  class REPARSE_DATA_BUFFER < FFI::Struct
345
349
  layout :ReparseTag, :uint32,
346
350
  :ReparseDataLength, :ushort,
@@ -21,7 +21,7 @@ require "chef/mixin/powershell_exec"
21
21
  require "chef/mixin/windows_architecture_helper"
22
22
  require "support/shared/integration/integration_helper"
23
23
 
24
- describe Chef::Resource::DscScript, :windows_powershell_dsc_only do
24
+ describe Chef::Resource::DscScript, :windows_powershell_dsc_only, :ruby64_only do
25
25
  include Chef::Mixin::WindowsArchitectureHelper
26
26
  include Chef::Mixin::PowershellExec
27
27
  before(:all) do
@@ -261,12 +261,9 @@ describe Chef::Resource::DscScript, :windows_powershell_dsc_only do
261
261
 
262
262
  it "should raise an exception if the cwd is etc" do
263
263
  dsc_test_resource.cwd(dsc_environment_fail_etc_directory)
264
- expect { dsc_test_resource.run_action(:run) }.to raise_error(Chef::Exceptions::PowershellCmdletException)
265
- begin
264
+ expect {
266
265
  dsc_test_resource.run_action(:run)
267
- rescue Chef::Exceptions::PowershellCmdletException => e
268
- expect(e.message).to match(exception_message_signature)
269
- end
266
+ }.to raise_error(Chef::PowerShell::CommandFailed, /#{exception_message_signature}/)
270
267
  end
271
268
  end
272
269
  end
@@ -97,7 +97,8 @@ describe "chef-client" do
97
97
  before { file ".chef/knife.rb", "xxx.xxx" }
98
98
 
99
99
  it "should load .chef/knife.rb when -z is specified" do
100
- result = shell_out("#{chef_client} -z -o 'x::default'", cwd: path_to(""))
100
+ # On Solaris shell_out will invoke /bin/sh which doesn't understand how to correctly update ENV['PWD']
101
+ result = shell_out("#{chef_client} -z -o 'x::default'", cwd: path_to(""), env: { "PWD" => nil })
101
102
  # FATAL: Configuration error NoMethodError: undefined method `xxx' for nil:NilClass
102
103
  expect(result.stdout).to include("xxx")
103
104
  end
@@ -0,0 +1,81 @@
1
+ require "spec_helper"
2
+
3
+ require "support/shared/integration/integration_helper"
4
+ require "chef/mixin/shell_out"
5
+ require "chef-utils/dist"
6
+
7
+ describe "chef-client with audit mode" do
8
+
9
+ include IntegrationSupport
10
+ include Chef::Mixin::ShellOut
11
+
12
+ let(:chef_dir) { File.join(__dir__, "..", "..", "..", "bin") }
13
+
14
+ # Invoke `chef-client` as `ruby PATH/TO/chef-client`. This ensures the
15
+ # following constraints are satisfied:
16
+ # * Windows: windows can only run batch scripts as bare executables. Rubygems
17
+ # creates batch wrappers for installed gems, but we don't have batch wrappers
18
+ # in the source tree.
19
+ # * Other `chef-client` in PATH: A common case is running the tests on a
20
+ # machine that has omnibus chef installed. In that case we need to ensure
21
+ # we're running `chef-client` from the source tree and not the external one.
22
+ # cf. CHEF-4914
23
+ let(:chef_client) { "bundle exec #{ChefUtils::Dist::Infra::CLIENT} --minimal-ohai" }
24
+
25
+ when_the_repository "has a custom profile" do
26
+ let(:report_file) { path_to("report_file.json") }
27
+
28
+ before do
29
+ directory "profiles/my-profile" do
30
+ file "inspec.yml", <<~FILE
31
+ ---
32
+ name: my-profile
33
+ FILE
34
+
35
+ directory "controls" do
36
+ file "my_control.rb", <<~FILE
37
+ control "my control" do
38
+ describe Dir.home do
39
+ it { should be_kind_of String }
40
+ end
41
+ end
42
+ FILE
43
+ end
44
+ end
45
+
46
+ file "attributes.json", <<~FILE
47
+ {
48
+ "audit": {
49
+ "json_file": {
50
+ "location": "#{report_file}"
51
+ },
52
+ "profiles": {
53
+ "my-profile": {
54
+ "path": "#{path_to("profiles/my-profile")}"
55
+ }
56
+ }
57
+ }
58
+ }
59
+ FILE
60
+ end
61
+
62
+ it "should complete with success" do
63
+ result = shell_out!("#{chef_client} --local-mode --json-attributes #{path_to("attributes.json")}", cwd: chef_dir)
64
+ result.error!
65
+
66
+ inspec_report = JSON.parse(File.read(report_file))
67
+ expect(inspec_report["profiles"].length).to eq(1)
68
+
69
+ profile = inspec_report["profiles"].first
70
+ expect(profile["name"]).to eq("my-profile")
71
+ expect(profile["controls"].length).to eq(1)
72
+
73
+ control = profile["controls"].first
74
+ expect(control["id"]).to eq("my control")
75
+ expect(control["results"].length).to eq(1)
76
+
77
+ result = control["results"].first
78
+ expect(result["status"]).to eq("passed")
79
+ end
80
+ end
81
+ end
@@ -28,6 +28,7 @@ describe "Recipe DSL methods" do
28
28
  def provider
29
29
  Provider
30
30
  end
31
+
31
32
  class Provider < Chef::Provider
32
33
  def load_current_resource; end
33
34
 
@@ -31,7 +31,7 @@ $LOAD_PATH.unshift File.expand_path("../chef-utils/lib", __dir__)
31
31
 
32
32
  require "rubygems"
33
33
  require "rspec/mocks"
34
-
34
+ require "rexml/document"
35
35
  require "webmock/rspec"
36
36
 
37
37
  require "chef"
@@ -129,6 +129,7 @@ shared_context "a client run" do
129
129
  expect(client.events).to receive(:register).with(instance_of(Chef::DataCollector::Reporter))
130
130
  expect(client.events).to receive(:register).with(instance_of(Chef::ResourceReporter))
131
131
  expect(client.events).to receive(:register).with(instance_of(Chef::ActionCollection))
132
+ expect(client.events).to receive(:register).with(instance_of(Chef::Compliance::Runner))
132
133
  end
133
134
 
134
135
  def stub_for_node_load
@@ -0,0 +1,134 @@
1
+ require "spec_helper"
2
+ require "chef/compliance/fetcher/automate"
3
+
4
+ describe Chef::Compliance::Fetcher::Automate do
5
+ describe ".resolve" do
6
+ before do
7
+ Chef::Config[:data_collector] = {
8
+ server_url: "https://automate.test/data_collector",
9
+ token: token,
10
+ }
11
+ end
12
+
13
+ let(:token) { "fake_token" }
14
+
15
+ context "when target is a string" do
16
+ it "should resolve a compliance URL" do
17
+ res = Chef::Compliance::Fetcher::Automate.resolve("compliance://namespace/profile_name")
18
+
19
+ expect(res).to be_kind_of(Chef::Compliance::Fetcher::Automate)
20
+ expected = "https://automate.test/compliance/profiles/namespace/profile_name/tar"
21
+ expect(res.target).to eq(expected)
22
+ end
23
+
24
+ it "raises an exception with no data collector token" do
25
+ Chef::Config[:data_collector].delete(:token)
26
+
27
+ expect {
28
+ Chef::Compliance::Fetcher::Automate.resolve("compliance://namespace/profile_name")
29
+ }.to raise_error(/No data-collector token set/)
30
+ end
31
+
32
+ it "includes the data collector token" do
33
+ expect(Chef::Compliance::Fetcher::Automate).to receive(:new).with(
34
+ "https://automate.test/compliance/profiles/namespace/profile_name/tar",
35
+ hash_including("token" => token)
36
+ ).and_call_original
37
+
38
+ res = Chef::Compliance::Fetcher::Automate.resolve("compliance://namespace/profile_name")
39
+
40
+ expect(res).to be_kind_of(Chef::Compliance::Fetcher::Automate)
41
+ expected = "https://automate.test/compliance/profiles/namespace/profile_name/tar"
42
+ expect(res.target).to eq(expected)
43
+ end
44
+
45
+ it "returns nil with a non-compliance URL" do
46
+ res = Chef::Compliance::Fetcher::Automate.resolve("http://github.com/chef-cookbooks/audit")
47
+
48
+ expect(res).to eq(nil)
49
+ end
50
+ end
51
+
52
+ context "when target is a hash" do
53
+ it "should resolve a target with a version" do
54
+ res = Chef::Compliance::Fetcher::Automate.resolve(
55
+ compliance: "namespace/profile_name",
56
+ version: "1.2.3"
57
+ )
58
+
59
+ expect(res).to be_kind_of(Chef::Compliance::Fetcher::Automate)
60
+ expected = "https://automate.test/compliance/profiles/namespace/profile_name/version/1.2.3/tar"
61
+ expect(res.target).to eq(expected)
62
+ end
63
+
64
+ it "should resolve a target without a version" do
65
+ res = Chef::Compliance::Fetcher::Automate.resolve(
66
+ compliance: "namespace/profile_name"
67
+ )
68
+
69
+ expect(res).to be_kind_of(Chef::Compliance::Fetcher::Automate)
70
+ expected = "https://automate.test/compliance/profiles/namespace/profile_name/tar"
71
+ expect(res.target).to eq(expected)
72
+ end
73
+
74
+ it "uses url key when present" do
75
+ res = Chef::Compliance::Fetcher::Automate.resolve(
76
+ compliance: "namespace/profile_name",
77
+ version: "1.2.3",
78
+ url: "https://profile.server.test/profiles/profile_name/1.2.3"
79
+ )
80
+
81
+ expect(res).to be_kind_of(Chef::Compliance::Fetcher::Automate)
82
+ expected = "https://profile.server.test/profiles/profile_name/1.2.3"
83
+ expect(res.target).to eq(expected)
84
+ end
85
+
86
+ it "does not include token in the config when url key is present" do
87
+ expect(Chef::Compliance::Fetcher::Automate).to receive(:new).with(
88
+ "https://profile.server.test/profiles/profile_name/1.2.3",
89
+ hash_including("token" => nil)
90
+ ).and_call_original
91
+
92
+ res = Chef::Compliance::Fetcher::Automate.resolve(
93
+ compliance: "namespace/profile_name",
94
+ version: "1.2.3",
95
+ url: "https://profile.server.test/profiles/profile_name/1.2.3"
96
+ )
97
+
98
+ expect(res).to be_kind_of(Chef::Compliance::Fetcher::Automate)
99
+ expected = "https://profile.server.test/profiles/profile_name/1.2.3"
100
+ expect(res.target).to eq(expected)
101
+ end
102
+
103
+ it "raises an exception with no data collector token" do
104
+ Chef::Config[:data_collector].delete(:token)
105
+
106
+ expect {
107
+ Chef::Compliance::Fetcher::Automate.resolve(compliance: "namespace/profile_name")
108
+ }.to raise_error(Inspec::FetcherFailure, /No data-collector token set/)
109
+ end
110
+
111
+ it "includes the data collector token" do
112
+ expect(Chef::Compliance::Fetcher::Automate).to receive(:new).with(
113
+ "https://automate.test/compliance/profiles/namespace/profile_name/tar",
114
+ hash_including("token" => token)
115
+ ).and_call_original
116
+
117
+ res = Chef::Compliance::Fetcher::Automate.resolve(compliance: "namespace/profile_name")
118
+
119
+ expect(res).to be_kind_of(Chef::Compliance::Fetcher::Automate)
120
+ expected = "https://automate.test/compliance/profiles/namespace/profile_name/tar"
121
+ expect(res.target).to eq(expected)
122
+ end
123
+
124
+ it "returns nil with a non-profile Hash" do
125
+ res = Chef::Compliance::Fetcher::Automate.resolve(
126
+ profile: "namespace/profile_name",
127
+ version: "1.2.3"
128
+ )
129
+
130
+ expect(res).to eq(nil)
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,93 @@
1
+ require "spec_helper"
2
+ require "chef/compliance/fetcher/chef_server"
3
+
4
+ describe Chef::Compliance::Fetcher::ChefServer do
5
+ let(:node) do
6
+ Chef::Node.new.tap do |n|
7
+ n.default["audit"] = {}
8
+ end
9
+ end
10
+
11
+ before :each do
12
+ allow(Chef).to receive(:node).and_return(node)
13
+
14
+ Chef::Config[:chef_server_url] = "http://127.0.0.1:8889/organizations/my_org"
15
+ end
16
+
17
+ describe ".resolve" do
18
+ context "when target is a string" do
19
+ it "should resolve a compliance URL" do
20
+ res = Chef::Compliance::Fetcher::ChefServer.resolve("compliance://namespace/profile_name")
21
+
22
+ expect(res).to be_kind_of(Chef::Compliance::Fetcher::ChefServer)
23
+ expected = "http://127.0.0.1:8889/organizations/my_org/owners/namespace/compliance/profile_name/tar"
24
+ expect(res.target).to eq(expected)
25
+ end
26
+
27
+ it "should add /compliance URL prefix if needed" do
28
+ node.default["audit"]["fetcher"] = "chef-server"
29
+ res = Chef::Compliance::Fetcher::ChefServer.resolve("compliance://namespace/profile_name")
30
+
31
+ expect(res).to be_kind_of(Chef::Compliance::Fetcher::ChefServer)
32
+ expected = "http://127.0.0.1:8889/compliance/organizations/my_org/owners/namespace/compliance/profile_name/tar"
33
+ expect(res.target).to eq(expected)
34
+ end
35
+
36
+ it "includes user in the URL if present" do
37
+ res = Chef::Compliance::Fetcher::ChefServer.resolve("compliance://username@namespace/profile_name")
38
+
39
+ expect(res).to be_kind_of(Chef::Compliance::Fetcher::ChefServer)
40
+ expected = "http://127.0.0.1:8889/organizations/my_org/owners/username@namespace/compliance/profile_name/tar"
41
+ expect(res.target).to eq(expected)
42
+ end
43
+
44
+ it "returns nil with a non-compliance URL" do
45
+ res = Chef::Compliance::Fetcher::ChefServer.resolve("http://github.com/chef-cookbooks/audit")
46
+
47
+ expect(res).to eq(nil)
48
+ end
49
+ end
50
+
51
+ context "when target is a hash" do
52
+ it "should resolve a target with a version" do
53
+ res = Chef::Compliance::Fetcher::ChefServer.resolve(
54
+ compliance: "namespace/profile_name",
55
+ version: "1.2.3"
56
+ )
57
+
58
+ expect(res).to be_kind_of(Chef::Compliance::Fetcher::ChefServer)
59
+ expected = "http://127.0.0.1:8889/organizations/my_org/owners/namespace/compliance/profile_name/version/1.2.3/tar"
60
+ expect(res.target).to eq(expected)
61
+ end
62
+
63
+ it "should resolve a target without a version" do
64
+ res = Chef::Compliance::Fetcher::ChefServer.resolve(
65
+ compliance: "namespace/profile_name"
66
+ )
67
+
68
+ expect(res).to be_kind_of(Chef::Compliance::Fetcher::ChefServer)
69
+ expected = "http://127.0.0.1:8889/organizations/my_org/owners/namespace/compliance/profile_name/tar"
70
+ expect(res.target).to eq(expected)
71
+ end
72
+
73
+ it "includes user in the URL if present" do
74
+ res = Chef::Compliance::Fetcher::ChefServer.resolve(
75
+ compliance: "username@namespace/profile_name"
76
+ )
77
+
78
+ expect(res).to be_kind_of(Chef::Compliance::Fetcher::ChefServer)
79
+ expected = "http://127.0.0.1:8889/organizations/my_org/owners/username@namespace/compliance/profile_name/tar"
80
+ expect(res.target).to eq(expected)
81
+ end
82
+
83
+ it "returns nil with a non-profile Hash" do
84
+ res = Chef::Compliance::Fetcher::ChefServer.resolve(
85
+ profile: "namespace/profile_name",
86
+ version: "1.2.3"
87
+ )
88
+
89
+ expect(res).to eq(nil)
90
+ end
91
+ end
92
+ end
93
+ end