chef 16.7.61-universal-mingw32 → 16.9.20-universal-mingw32

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.
Files changed (122) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -5
  3. data/README.md +2 -2
  4. data/chef.gemspec +12 -2
  5. data/distro/ruby_bin_folder/AMD64/Chef.PowerShell.Wrapper.dll +0 -0
  6. data/distro/ruby_bin_folder/AMD64/Chef.PowerShell.dll +0 -0
  7. data/distro/ruby_bin_folder/AMD64/shared/Microsoft.NETCore.App/5.0.0/Chef.PowerShell.Wrapper.Core.dll +0 -0
  8. data/distro/ruby_bin_folder/AMD64/shared/Microsoft.NETCore.App/5.0.0/Chef.Powershell.Core.dll +0 -0
  9. data/distro/ruby_bin_folder/AMD64/shared/Microsoft.NETCore.App/5.0.0/Chef.Powershell.Core.pdb +0 -0
  10. data/distro/ruby_bin_folder/x86/Chef.PowerShell.dll +0 -0
  11. data/distro/ruby_bin_folder/x86/Chef.Powershell.Wrapper.dll +0 -0
  12. data/distro/ruby_bin_folder/x86/shared/Microsoft.NETCore.App/5.0.0/Chef.PowerShell.Wrapper.Core.dll +0 -0
  13. data/distro/ruby_bin_folder/x86/shared/Microsoft.NETCore.App/5.0.0/Chef.Powershell.Core.dll +0 -0
  14. data/distro/ruby_bin_folder/x86/shared/Microsoft.NETCore.App/5.0.0/Chef.Powershell.Core.pdb +0 -0
  15. data/lib/chef/application/base.rb +1 -1
  16. data/lib/chef/client.rb +3 -0
  17. data/lib/chef/compliance/default_attributes.rb +93 -0
  18. data/lib/chef/compliance/fetcher/automate.rb +69 -0
  19. data/lib/chef/compliance/fetcher/chef_server.rb +134 -0
  20. data/lib/chef/compliance/reporter/automate.rb +201 -0
  21. data/lib/chef/compliance/reporter/chef_server_automate.rb +94 -0
  22. data/lib/chef/compliance/reporter/compliance_enforcer.rb +20 -0
  23. data/lib/chef/compliance/reporter/json_file.rb +19 -0
  24. data/lib/chef/compliance/runner.rb +262 -0
  25. data/lib/chef/cookbook_manifest.rb +1 -0
  26. data/lib/chef/encrypted_data_bag_item/assertions.rb +1 -1
  27. data/lib/chef/exceptions.rb +4 -0
  28. data/lib/chef/http/ssl_policies.rb +33 -14
  29. data/lib/chef/knife/bootstrap/train_connector.rb +1 -1
  30. data/lib/chef/knife/core/formatting_options.rb +49 -0
  31. data/lib/chef/knife/core/node_presenter.rb +0 -25
  32. data/lib/chef/knife/core/status_presenter.rb +1 -26
  33. data/lib/chef/knife/core/ui.rb +4 -1
  34. data/lib/chef/knife/core/windows_bootstrap_context.rb +1 -1
  35. data/lib/chef/knife/node_show.rb +2 -1
  36. data/lib/chef/knife/search.rb +2 -1
  37. data/lib/chef/knife/ssh.rb +3 -1
  38. data/lib/chef/knife/status.rb +8 -11
  39. data/lib/chef/mixin/powershell_exec.rb +3 -1
  40. data/lib/chef/platform/query_helpers.rb +4 -4
  41. data/lib/chef/policy_builder/policyfile.rb +1 -1
  42. data/lib/chef/powershell.rb +2 -0
  43. data/lib/chef/provider/dsc_resource.rb +12 -24
  44. data/lib/chef/provider/dsc_script.rb +16 -20
  45. data/lib/chef/provider/git.rb +5 -5
  46. data/lib/chef/provider/package.rb +53 -19
  47. data/lib/chef/provider/package/dnf.rb +39 -12
  48. data/lib/chef/provider/package/dnf/dnf_helper.py +18 -5
  49. data/lib/chef/provider/package/dnf/python_helper.rb +6 -6
  50. data/lib/chef/provider/package/freebsd/pkgng.rb +3 -1
  51. data/lib/chef/provider/yum_repository.rb +2 -2
  52. data/lib/chef/resource/chef_client_config.rb +1 -1
  53. data/lib/chef/resource/chef_gem.rb +2 -2
  54. data/lib/chef/resource/cron/cron_d.rb +1 -0
  55. data/lib/chef/resource/dsc_script.rb +8 -1
  56. data/lib/chef/resource/file.rb +1 -1
  57. data/lib/chef/resource/gem_package.rb +2 -2
  58. data/lib/chef/resource/homebrew_cask.rb +3 -3
  59. data/lib/chef/resource/hostname.rb +3 -3
  60. data/lib/chef/resource/http_request.rb +1 -1
  61. data/lib/chef/resource/locale.rb +1 -1
  62. data/lib/chef/resource/mdadm.rb +2 -2
  63. data/lib/chef/resource/osx_profile.rb +7 -7
  64. data/lib/chef/resource/remote_directory.rb +1 -1
  65. data/lib/chef/resource/ruby.rb +1 -5
  66. data/lib/chef/resource/ruby_block.rb +1 -1
  67. data/lib/chef/resource/template.rb +2 -2
  68. data/lib/chef/resource/user/windows_user.rb +5 -0
  69. data/lib/chef/resource/windows_certificate.rb +9 -13
  70. data/lib/chef/resource/yum_repository.rb +5 -0
  71. data/lib/chef/resource_collection/resource_set.rb +1 -1
  72. data/lib/chef/util/dsc/configuration_generator.rb +52 -11
  73. data/lib/chef/util/dsc/lcm_output_parser.rb +3 -4
  74. data/lib/chef/util/dsc/local_configuration_manager.rb +17 -14
  75. data/lib/chef/util/dsc/resource_store.rb +5 -11
  76. data/lib/chef/version.rb +1 -1
  77. data/lib/chef/win32/api/file.rb +4 -0
  78. data/spec/data/rubygems.org/latest_specs.4.8.gz +0 -0
  79. data/spec/data/rubygems.org/nonexistent_gem +0 -0
  80. data/spec/data/rubygems.org/sexp_processor +0 -0
  81. data/spec/data/rubygems.org/sexp_processor-4.15.1.gemspec.rz +0 -0
  82. data/spec/data/ssl/binary/chef-rspec-der.cert +0 -0
  83. data/spec/data/ssl/binary/chef-rspec-der.key +0 -0
  84. data/spec/functional/resource/dnf_package_spec.rb +319 -16
  85. data/spec/functional/resource/dsc_script_spec.rb +3 -6
  86. data/spec/functional/resource/windows_certificate_spec.rb +204 -384
  87. data/spec/integration/client/client_spec.rb +2 -1
  88. data/spec/integration/compliance/compliance_spec.rb +81 -0
  89. data/spec/integration/recipes/recipe_dsl_spec.rb +1 -0
  90. data/spec/spec_helper.rb +1 -1
  91. data/spec/unit/client_spec.rb +1 -0
  92. data/spec/unit/compliance/fetcher/automate_spec.rb +134 -0
  93. data/spec/unit/compliance/fetcher/chef_server_spec.rb +93 -0
  94. data/spec/unit/compliance/reporter/automate_spec.rb +427 -0
  95. data/spec/unit/compliance/reporter/chef_server_automate_spec.rb +177 -0
  96. data/spec/unit/compliance/reporter/compliance_enforcer_spec.rb +48 -0
  97. data/spec/unit/compliance/runner_spec.rb +167 -0
  98. data/spec/unit/http/ssl_policies_spec.rb +107 -68
  99. data/spec/unit/knife/bootstrap_spec.rb +5 -17
  100. data/spec/unit/knife/core/node_editor_spec.rb +1 -1
  101. data/spec/unit/knife/core/status_presenter_spec.rb +54 -0
  102. data/spec/unit/mixin/openssl_helper_spec.rb +0 -7
  103. data/spec/unit/mixin/powershell_exec_spec.rb +1 -1
  104. data/spec/unit/platform/query_helpers_spec.rb +11 -12
  105. data/spec/unit/provider/dsc_resource_spec.rb +10 -27
  106. data/spec/unit/provider/dsc_script_spec.rb +1 -1
  107. data/spec/unit/provider/mount/windows_spec.rb +1 -0
  108. data/spec/unit/provider/package/freebsd/pkgng_spec.rb +1 -1
  109. data/spec/unit/provider/package/rubygems_spec.rb +39 -7
  110. data/spec/unit/provider/systemd_unit_spec.rb +1 -1
  111. data/spec/unit/resource/user/windows_user_spec.rb +36 -0
  112. data/spec/unit/resource/windows_certificate_spec.rb +12 -0
  113. data/spec/unit/util/dsc/configuration_generator_spec.rb +79 -0
  114. data/spec/unit/util/dsc/local_configuration_manager_spec.rb +27 -35
  115. metadata +55 -18
  116. data/lib/chef/util/powershell/cmdlet.rb +0 -169
  117. data/lib/chef/util/powershell/cmdlet_result.rb +0 -61
  118. data/spec/data/trusted_certs_empty/.gitkeep +0 -0
  119. data/spec/data/trusted_certs_empty/README.md +0 -1
  120. data/spec/functional/util/powershell/cmdlet_spec.rb +0 -111
  121. data/spec/scripts/ssl-serve.rb +0 -47
  122. data/spec/unit/util/powershell/cmdlet_spec.rb +0 -106
@@ -0,0 +1,177 @@
1
+ require "spec_helper"
2
+
3
+ describe Chef::Compliance::Reporter::ChefServerAutomate do
4
+ before do
5
+ WebMock.disable_net_connect!
6
+
7
+ Chef::Config[:client_key] = File.expand_path("../../../data/ssl/private_key.pem", __dir__)
8
+ Chef::Config[:node_name] = "spec-node"
9
+ end
10
+
11
+ let(:reporter) { Chef::Compliance::Reporter::ChefServerAutomate.new(opts) }
12
+
13
+ let(:opts) do
14
+ {
15
+ entity_uuid: "aaaaaaaa-709a-475d-bef5-zzzzzzzzzzzz",
16
+ run_id: "3f0536f7-3361-4bca-ae53-b45118dceb5d",
17
+ node_info: {
18
+ node: "chef-client.solo",
19
+ environment: "My Prod Env",
20
+ roles: %w{base_linux apache_linux},
21
+ recipes: ["some_cookbook::some_recipe", "some_cookbook"],
22
+ policy_name: "test_policy_name",
23
+ policy_group: "test_policy_group",
24
+ chef_tags: ["mylinux", "my.tag", "some=tag"],
25
+ organization_name: "test_org",
26
+ source_fqdn: "api.chef.io",
27
+ ipaddress: "192.168.56.33",
28
+ fqdn: "lb1.prod.example.com",
29
+ },
30
+ url: "https://chef.server/data_collector",
31
+ control_results_limit: 2,
32
+ timestamp: Time.parse("2016-07-19T19:19:19+01:00"),
33
+ }
34
+ end
35
+
36
+ let(:inspec_report) do
37
+ {
38
+ "version": "1.2.1",
39
+ "profiles":
40
+ [{ "name": "tmp_compliance_profile",
41
+ "title": "/tmp Compliance Profile",
42
+ "summary": "An Example Compliance Profile",
43
+ "sha256": "7bd598e369970002fc6f2d16d5b988027d58b044ac3fa30ae5fc1b8492e215cd",
44
+ "version": "0.1.1",
45
+ "maintainer": "Nathen Harvey <nharvey@chef.io>",
46
+ "license": "Apache 2.0 License",
47
+ "copyright": "Nathen Harvey <nharvey@chef.io>",
48
+ "supports": [],
49
+ "controls":
50
+ [{ "title": "A /tmp directory must exist",
51
+ "desc": "A /tmp directory must exist",
52
+ "impact": 0.3,
53
+ "refs": [],
54
+ "tags": {},
55
+ "code": "control 'tmp-1.0' do\n impact 0.3\n title 'A /tmp directory must exist'\n desc 'A /tmp directory must exist'\n describe file '/tmp' do\n it { should be_directory }\n end\nend\n",
56
+ "source_location": { "ref": "/Users/vjeffrey/code/delivery/insights/data_generator/chef-client/cache/cookbooks/test-cookbook/recipes/../files/default/compliance_profiles/tmp_compliance_profile/controls/tmp.rb", "line": 3 },
57
+ "id": "tmp-1.0",
58
+ "results": [
59
+ { "status": "passed", "code_desc": "File /tmp should be directory", "run_time": 0.002312, "start_time": "2016-10-19 11:09:43 -0400" },
60
+ ],
61
+ },
62
+ { "title": "/tmp directory is owned by the root user",
63
+ "desc": "The /tmp directory must be owned by the root user",
64
+ "impact": 0.3,
65
+ "refs": [{ "url": "https://pages.chef.io/rs/255-VFB-268/images/compliance-at-velocity2015.pdf", "ref": "Compliance Whitepaper" }],
66
+ "tags": { "production": nil, "development": nil, "identifier": "value", "remediation": "https://github.com/chef-cookbooks/audit" },
67
+ "code": "control 'tmp-1.1' do\n impact 0.3\n title '/tmp directory is owned by the root user'\n desc 'The /tmp directory must be owned by the root user'\n tag 'production','development'\n tag identifier: 'value'\n tag remediation: 'https://github.com/chef-cookbooks/audit'\n ref 'Compliance Whitepaper', url: 'https://pages.chef.io/rs/255-VFB-268/images/compliance-at-velocity2015.pdf'\n describe file '/tmp' do\n it { should be_owned_by 'root' }\n end\nend\n",
68
+ "source_location": { "ref": "/Users/vjeffrey/code/delivery/insights/data_generator/chef-client/cache/cookbooks/test-cookbook/recipes/../files/default/compliance_profiles/tmp_compliance_profile/controls/tmp.rb", "line": 12 },
69
+ "id": "tmp-1.1",
70
+ "results": [
71
+ { "status": "passed", "code_desc": 'File /tmp should be owned by "root"', "run_time": 1.228845, "start_time": "2016-10-19 11:09:43 -0400" },
72
+ { "status": "skipped", "code_desc": 'File /tmp should be owned by "root"', "run_time": 1.228845, "start_time": "2016-10-19 11:09:43 -0400" },
73
+ { "status": "failed", "code_desc": "File /etc/hosts is expected to be directory", "run_time": 1.228845, "start_time": "2016-10-19 11:09:43 -0400", "message": "expected `File /etc/hosts.directory?` to return true, got false" },
74
+ ],
75
+ },
76
+ ],
77
+ "groups": [{ "title": "/tmp Compliance Profile", "controls": ["tmp-1.0", "tmp-1.1"], "id": "controls/tmp.rb" }],
78
+ "attributes": [{ "name": "syslog_pkg", "options": { "default": "rsyslog", "description": "syslog package..." } }] }],
79
+ "other_checks": [],
80
+ "statistics": { "duration": 0.032332 },
81
+ }
82
+ end
83
+
84
+ let(:enriched_report) do
85
+ {
86
+ "version": "1.2.1",
87
+ "profiles": [
88
+ {
89
+ "name": "tmp_compliance_profile",
90
+ "title": "/tmp Compliance Profile",
91
+ "summary": "An Example Compliance Profile",
92
+ "sha256": "7bd598e369970002fc6f2d16d5b988027d58b044ac3fa30ae5fc1b8492e215cd",
93
+ "version": "0.1.1",
94
+ "maintainer": "Nathen Harvey <nharvey@chef.io>",
95
+ "license": "Apache 2.0 License",
96
+ "copyright": "Nathen Harvey <nharvey@chef.io>",
97
+ "supports": [],
98
+ "controls": [
99
+ {
100
+ "title": "A /tmp directory must exist",
101
+ "desc": "A /tmp directory must exist",
102
+ "impact": 0.3,
103
+ "refs": [],
104
+ "tags": {},
105
+ "code":
106
+ "control 'tmp-1.0' do\n impact 0.3\n title 'A /tmp directory must exist'\n desc 'A /tmp directory must exist'\n describe file '/tmp' do\n it { should be_directory }\n end\nend\n",
107
+ "source_location": { "ref": "/Users/vjeffrey/code/delivery/insights/data_generator/chef-client/cache/cookbooks/test-cookbook/recipes/../files/default/compliance_profiles/tmp_compliance_profile/controls/tmp.rb", "line": 3 },
108
+ "id": "tmp-1.0",
109
+ "results": [{ "status": "passed", "code_desc": "File /tmp should be directory", "run_time": 0.002312, "start_time": "2016-10-19 11:09:43 -0400" }],
110
+ },
111
+ {
112
+ "title": "/tmp directory is owned by the root user",
113
+ "desc": "The /tmp directory must be owned by the root user",
114
+ "impact": 0.3,
115
+ "refs": [{ "url": "https://pages.chef.io/rs/255-VFB-268/images/compliance-at-velocity2015.pdf", "ref": "Compliance Whitepaper" }],
116
+ "tags": { "production": nil, "development": nil, "identifier": "value", "remediation": "https://github.com/chef-cookbooks/audit" },
117
+ "code": "control 'tmp-1.1' do\n impact 0.3\n title '/tmp directory is owned by the root user'\n desc 'The /tmp directory must be owned by the root user'\n tag 'production','development'\n tag identifier: 'value'\n tag remediation: 'https://github.com/chef-cookbooks/audit'\n ref 'Compliance Whitepaper', url: 'https://pages.chef.io/rs/255-VFB-268/images/compliance-at-velocity2015.pdf'\n describe file '/tmp' do\n it { should be_owned_by 'root' }\n end\nend\n",
118
+ "source_location": { "ref": "/Users/vjeffrey/code/delivery/insights/data_generator/chef-client/cache/cookbooks/test-cookbook/recipes/../files/default/compliance_profiles/tmp_compliance_profile/controls/tmp.rb", "line": 12 },
119
+ "id": "tmp-1.1",
120
+ "results": [
121
+ { "status": "failed", "code_desc": "File /etc/hosts is expected to be directory", "run_time": 1.228845, "start_time": "2016-10-19 11:09:43 -0400", "message": "expected `File /etc/hosts.directory?` to return true, got false" },
122
+ { "status": "skipped", "code_desc": 'File /tmp should be owned by "root"', "run_time": 1.228845, "start_time": "2016-10-19 11:09:43 -0400" },
123
+ ],
124
+ "removed_results_counts": { "failed": 0, "skipped": 0, "passed": 1 },
125
+ },
126
+ ],
127
+ "groups": [{ "title": "/tmp Compliance Profile", "controls": ["tmp-1.0", "tmp-1.1"], "id": "controls/tmp.rb" }],
128
+ "attributes": [{ "name": "syslog_pkg", "options": { "default": "rsyslog", "description": "syslog package..." } }],
129
+ },
130
+ ],
131
+ "other_checks": [],
132
+ "statistics": { "duration": 0.032332 },
133
+ "type": "inspec_report",
134
+ "node_name": "chef-client.solo",
135
+ "end_time": "2016-07-19T18:19:19Z",
136
+ "node_uuid": "aaaaaaaa-709a-475d-bef5-zzzzzzzzzzzz",
137
+ "environment": "My Prod Env",
138
+ "roles": %w{base_linux apache_linux},
139
+ "recipes": ["some_cookbook::some_recipe", "some_cookbook"],
140
+ "report_uuid": "3f0536f7-3361-4bca-ae53-b45118dceb5d",
141
+ "source_fqdn": "api.chef.io",
142
+ "organization_name": "test_org",
143
+ "policy_group": "test_policy_group",
144
+ "policy_name": "test_policy_name",
145
+ "chef_tags": ["mylinux", "my.tag", "some=tag"],
146
+ "ipaddress": "192.168.56.33",
147
+ "fqdn": "lb1.prod.example.com",
148
+ }
149
+ end
150
+
151
+ it "sends report successfully" do
152
+ # TODO: Had to change 'X-Ops-Server-Api-Version' from 1 to 2, is that correct?
153
+ report_stub = stub_request(:post, "https://chef.server/data_collector")
154
+ .with(
155
+ body: enriched_report,
156
+ headers: {
157
+ "X-Chef-Version" => Chef::VERSION,
158
+ "X-Ops-Authorization-1" => /.+/,
159
+ "X-Ops-Authorization-2" => /.+/,
160
+ "X-Ops-Authorization-3" => /.+/,
161
+ "X-Ops-Authorization-4" => /.+/,
162
+ "X-Ops-Authorization-5" => /.+/,
163
+ "X-Ops-Authorization-6" => /.+/,
164
+ "X-Ops-Content-Hash" => "yfck5nQDcRWta06u45Q+J463LYY=",
165
+ "X-Ops-Server-Api-Version" => "2",
166
+ "X-Ops-Sign" => "algorithm=sha1;version=1.1;",
167
+ "X-Ops-Timestamp" => /.+/,
168
+ "X-Ops-Userid" => "spec-node",
169
+ "X-Remote-Request-Id" => /.+/,
170
+ }
171
+ ).to_return(status: 200)
172
+
173
+ expect(reporter.send_report(inspec_report)).to eq(true)
174
+
175
+ expect(report_stub).to have_been_requested
176
+ end
177
+ end
@@ -0,0 +1,48 @@
1
+ require "spec_helper"
2
+
3
+ describe Chef::Compliance::Reporter::AuditEnforcer do
4
+ let(:reporter) { Chef::Compliance::Reporter::AuditEnforcer.new }
5
+
6
+ it "does not raise error for a successful InSpec report" do
7
+ report = {
8
+ "profiles": [
9
+ {
10
+ "controls": [
11
+ { "id": "c1", "results": [{ "status": "passed" }] },
12
+ { "id": "c2", "results": [{ "status": "passed" }] },
13
+ ],
14
+ },
15
+ ],
16
+ }
17
+
18
+ expect(reporter.send_report(report)).to eq(true)
19
+ end
20
+
21
+ it "does not raise error for an InSpec report with no controls" do
22
+ report = { "profiles": [{ "name": "empty" }] }
23
+
24
+ expect(reporter.send_report(report)).to eq(true)
25
+ end
26
+
27
+ it "does not raise error for an InSpec report with controls but no results" do
28
+ report = { "profiles": [{ "controls": [{ "id": "empty" }] }] }
29
+ expect(reporter.send_report(report)).to eq(true)
30
+ end
31
+
32
+ it "raises an error for a failed InSpec report" do
33
+ report = {
34
+ "profiles": [
35
+ {
36
+ "controls": [
37
+ { "id": "c1", "results": [{ "status": "passed" }] },
38
+ { "id": "c2", "results": [{ "status": "failed" }] },
39
+ ],
40
+ },
41
+ ],
42
+ }
43
+
44
+ expect {
45
+ reporter.send_report(report)
46
+ }.to raise_error(Chef::Compliance::Reporter::AuditEnforcer::ControlFailure, "Audit c2 has failed. Aborting chef-client run.")
47
+ end
48
+ end
@@ -0,0 +1,167 @@
1
+ require "spec_helper"
2
+
3
+ describe Chef::Compliance::Runner do
4
+ let(:logger) { double(:logger).as_null_object }
5
+ let(:node) { Chef::Node.new(logger: logger) }
6
+
7
+ let(:runner) do
8
+ described_class.new.tap do |r|
9
+ r.node = node
10
+ r.run_id = "my_run_id"
11
+ end
12
+ end
13
+
14
+ describe "#enabled?" do
15
+ it "is true if the node attributes have audit profiles and the audit cookbook is not present" do
16
+ node.normal["audit"]["profiles"]["ssh"] = { 'compliance': "base/ssh" }
17
+ node.automatic["recipes"] = %w{ fancy_cookbook::fanciness tacobell::nachos }
18
+
19
+ expect(runner).to be_enabled
20
+ end
21
+
22
+ it "is false if the node attributes have audit profiles and the audit cookbook is present" do
23
+ node.normal["audit"]["profiles"]["ssh"] = { 'compliance': "base/ssh" }
24
+ node.automatic["recipes"] = %w{ audit::default fancy_cookbook::fanciness tacobell::nachos }
25
+
26
+ expect(runner).not_to be_enabled
27
+ end
28
+
29
+ it "is false if the node attributes do not have audit profiles and the audit cookbook is not present" do
30
+ node.normal["audit"]["profiles"] = {}
31
+ node.automatic["recipes"] = %w{ fancy_cookbook::fanciness tacobell::nachos }
32
+
33
+ expect(runner).not_to be_enabled
34
+ end
35
+
36
+ it "is false if the node attributes do not have audit profiles and the audit cookbook is present" do
37
+ node.normal["audit"]["profiles"] = {}
38
+ node.automatic["recipes"] = %w{ audit::default fancy_cookbook::fanciness tacobell::nachos }
39
+
40
+ expect(runner).not_to be_enabled
41
+ end
42
+
43
+ it "is false if the node attributes do not have audit attributes and the audit cookbook is not present" do
44
+ node.automatic["recipes"] = %w{ fancy_cookbook::fanciness tacobell::nachos }
45
+ expect(runner).not_to be_enabled
46
+ end
47
+ end
48
+
49
+ describe "#inspec_profiles" do
50
+ it "returns an empty list with no profiles defined" do
51
+ expect(runner.inspec_profiles).to eq([])
52
+ end
53
+
54
+ it "converts from the attribute format to the format Inspec expects" do
55
+ node.normal["audit"]["profiles"]["linux-baseline"] = {
56
+ 'compliance': "user/linux-baseline",
57
+ 'version': "2.1.0",
58
+ }
59
+
60
+ node.normal["audit"]["profiles"]["ssh"] = {
61
+ 'supermarket': "hardening/ssh-hardening",
62
+ }
63
+
64
+ expected = [
65
+ {
66
+ compliance: "user/linux-baseline",
67
+ name: "linux-baseline",
68
+ version: "2.1.0",
69
+ },
70
+ {
71
+ name: "ssh",
72
+ supermarket: "hardening/ssh-hardening",
73
+ },
74
+ ]
75
+
76
+ expect(runner.inspec_profiles).to eq(expected)
77
+ end
78
+
79
+ it "raises an error when the profiles are in the old audit-cookbook format" do
80
+ node.normal["audit"]["profiles"] = [
81
+ {
82
+ name: "Windows 2019 Baseline",
83
+ compliance: "admin/windows-2019-baseline",
84
+ },
85
+ ]
86
+
87
+ expect { runner.inspec_profiles }.to raise_error(/profiles specified in an unrecognized format, expected a hash of hashes./)
88
+ end
89
+ end
90
+
91
+ describe "#warn_for_deprecated_config_values!" do
92
+ it "logs a warning when deprecated config values are present" do
93
+ node.normal["audit"]["owner"] = "my_org"
94
+ node.normal["audit"]["inspec_version"] = "90210"
95
+
96
+ expect(logger).to receive(:warn).with(/config values 'inspec_version', 'owner' are not supported/)
97
+
98
+ runner.warn_for_deprecated_config_values!
99
+ end
100
+
101
+ it "does not log a warning with no deprecated config values" do
102
+ node.normal["audit"]["profiles"]["linux-baseline"] = {
103
+ 'compliance': "user/linux-baseline",
104
+ 'version': "2.1.0",
105
+ }
106
+
107
+ expect(logger).not_to receive(:warn)
108
+
109
+ runner.warn_for_deprecated_config_values!
110
+ end
111
+ end
112
+
113
+ describe "#reporter" do
114
+ context "chef-server-automate reporter" do
115
+ it "uses the correct URL when 'server' attribute is set" do
116
+ Chef::Config[:chef_server_url] = "https://chef_config_url.example.com/my_org"
117
+ node.normal["audit"]["server"] = "https://server_attribute_url.example.com/application/sub_application"
118
+
119
+ reporter = runner.reporter("chef-server-automate")
120
+
121
+ expect(reporter).to be_kind_of(Chef::Compliance::Reporter::ChefServerAutomate)
122
+ expect(reporter.url).to eq(URI("https://server_attribute_url.example.com/application/sub_application/organizations/my_org/data-collector"))
123
+ end
124
+
125
+ it "falls back to chef_server_url for URL when 'server' attribute is not set" do
126
+ Chef::Config[:chef_server_url] = "https://chef_config_url.example.com/my_org"
127
+
128
+ reporter = runner.reporter("chef-server-automate")
129
+
130
+ expect(reporter).to be_kind_of(Chef::Compliance::Reporter::ChefServerAutomate)
131
+ expect(reporter.url).to eq(URI("https://chef_config_url.example.com/organizations/my_org/data-collector"))
132
+ end
133
+ end
134
+
135
+ it "fails with unexpected reporter value" do
136
+ expect { runner.reporter("tacos") }.to raise_error(/'tacos' is not a supported reporter for Compliance Phase/)
137
+ end
138
+ end
139
+
140
+ describe "#inspec_opts" do
141
+ it "does not include chef_node in inputs by default" do
142
+ node.normal["audit"]["attributes"] = {
143
+ "tacos" => "lunch",
144
+ "nachos" => "dinner",
145
+ }
146
+
147
+ inputs = runner.inspec_opts[:inputs]
148
+
149
+ expect(inputs["tacos"]).to eq("lunch")
150
+ expect(inputs.key?("chef_node")).to eq(false)
151
+ end
152
+
153
+ it "includes chef_node in inputs with chef_node_attribute_enabled set" do
154
+ node.normal["audit"]["chef_node_attribute_enabled"] = true
155
+ node.normal["audit"]["attributes"] = {
156
+ "tacos" => "lunch",
157
+ "nachos" => "dinner",
158
+ }
159
+
160
+ inputs = runner.inspec_opts[:inputs]
161
+
162
+ expect(inputs["tacos"]).to eq("lunch")
163
+ expect(inputs["chef_node"]["audit"]["reporter"]).to eq("json-file")
164
+ expect(inputs["chef_node"]["chef_environment"]).to eq("_default")
165
+ end
166
+ end
167
+ end
@@ -26,83 +26,86 @@ describe "HTTP SSL Policy" do
26
26
  Chef::Config[:ssl_client_key] = nil
27
27
  Chef::Config[:ssl_ca_path] = nil
28
28
  Chef::Config[:ssl_ca_file] = nil
29
+ ENV["SSL_CERT_FILE"] = nil
29
30
  end
30
31
 
31
- let(:unconfigured_http_client) { Net::HTTP.new("example.com", 443) }
32
32
  let(:http_client) do
33
- unconfigured_http_client.use_ssl = true
34
- ssl_policy.apply
35
- unconfigured_http_client
33
+ ssl_policy_class.apply_to(Net::HTTP.new("example.com"))
36
34
  end
37
35
 
38
36
  describe Chef::HTTP::DefaultSSLPolicy do
39
37
 
40
- let(:ssl_policy) { Chef::HTTP::DefaultSSLPolicy.new(unconfigured_http_client) }
38
+ let(:ssl_policy_class) { Chef::HTTP::DefaultSSLPolicy }
41
39
 
42
- describe "when configured with :ssl_verify_mode set to :verify peer" do
43
- before do
44
- Chef::Config[:ssl_verify_mode] = :verify_peer
45
- end
46
-
47
- it "configures the HTTP client to use SSL when given a URL with the https protocol" do
48
- expect(http_client.use_ssl?).to be_truthy
49
- end
40
+ it "raises a ConfigurationError if :ssl_ca_path is set to a path that doesn't exist" do
41
+ Chef::Config[:ssl_ca_path] = "/dev/null/nothing_here"
42
+ expect { http_client }.to raise_error(Chef::Exceptions::ConfigurationError)
43
+ end
50
44
 
51
- it "sets the OpenSSL verify mode to verify_peer" do
52
- expect(http_client.verify_mode).to eq(OpenSSL::SSL::VERIFY_PEER)
53
- end
45
+ it "should set the CA path if that is set in the configuration" do
46
+ Chef::Config[:ssl_ca_path] = File.join(CHEF_SPEC_DATA, "ssl")
47
+ expect(http_client.ca_path).to eq(File.join(CHEF_SPEC_DATA, "ssl"))
48
+ end
54
49
 
55
- it "raises a ConfigurationError if :ssl_ca_path is set to a path that doesn't exist" do
56
- Chef::Config[:ssl_ca_path] = "/dev/null/nothing_here"
57
- expect { http_client }.to raise_error(Chef::Exceptions::ConfigurationError)
58
- end
50
+ it "raises a ConfigurationError if :ssl_ca_file is set to a file that does not exist" do
51
+ Chef::Config[:ssl_ca_file] = "/dev/null/nothing_here"
52
+ expect { http_client }.to raise_error(Chef::Exceptions::ConfigurationError)
53
+ end
59
54
 
60
- it "should set the CA path if that is set in the configuration" do
61
- Chef::Config[:ssl_ca_path] = File.join(CHEF_SPEC_DATA, "ssl")
62
- expect(http_client.ca_path).to eq(File.join(CHEF_SPEC_DATA, "ssl"))
63
- end
55
+ it "should set the CA file if that is set in the configuration" do
56
+ Chef::Config[:ssl_ca_file] = CHEF_SPEC_DATA + "/ssl/5e707473.0"
57
+ expect(http_client.ca_file).to eq(CHEF_SPEC_DATA + "/ssl/5e707473.0")
58
+ end
64
59
 
65
- it "raises a ConfigurationError if :ssl_ca_file is set to a file that does not exist" do
66
- Chef::Config[:ssl_ca_file] = "/dev/null/nothing_here"
67
- expect { http_client }.to raise_error(Chef::Exceptions::ConfigurationError)
68
- end
60
+ it "should set the custom CA file if SSL_CERT_FILE environment variable is set" do
61
+ ENV["SSL_CERT_FILE"] = CHEF_SPEC_DATA + "/trusted_certs/intermediate.pem"
62
+ expect(http_client.ca_file).to eq(CHEF_SPEC_DATA + "/trusted_certs/intermediate.pem")
63
+ end
69
64
 
70
- it "should set the CA file if that is set in the configuration" do
71
- Chef::Config[:ssl_ca_file] = CHEF_SPEC_DATA + "/ssl/5e707473.0"
72
- expect(http_client.ca_file).to eq(CHEF_SPEC_DATA + "/ssl/5e707473.0")
73
- end
65
+ it "raises a ConfigurationError if SSL_CERT_FILE environment variable is set to a file that does not exist" do
66
+ ENV["SSL_CERT_FILE"] = "/dev/null/nothing_here"
67
+ expect { http_client }.to raise_error(Chef::Exceptions::ConfigurationError)
74
68
  end
75
69
 
76
- describe "when configured with :ssl_verify_mode set to :verify peer" do
77
- before do
78
- @url = URI.parse("https://chef.example.com:4443/")
79
- Chef::Config[:ssl_verify_mode] = :verify_none
80
- end
70
+ it "sets the OpenSSL verify mode to verify_peer when configured with :ssl_verify_mode set to :verify_peer" do
71
+ Chef::Config[:ssl_verify_mode] = :verify_peer
72
+ expect(http_client.verify_mode).to eq(OpenSSL::SSL::VERIFY_PEER)
73
+ end
81
74
 
82
- it "sets the OpenSSL verify mode to :verify_none" do
83
- expect(http_client.verify_mode).to eq(OpenSSL::SSL::VERIFY_NONE)
84
- end
75
+ it "sets the OpenSSL verify mode to :verify_none when configured with :ssl_verify_mode set to :verify_none" do
76
+ Chef::Config[:ssl_verify_mode] = :verify_none
77
+ expect(http_client.verify_mode).to eq(OpenSSL::SSL::VERIFY_NONE)
85
78
  end
86
79
 
87
80
  describe "when configured with a client certificate" do
88
- before { @url = URI.parse("https://chef.example.com:4443/") }
89
-
90
81
  it "raises ConfigurationError if the certificate file doesn't exist" do
91
82
  Chef::Config[:ssl_client_cert] = "/dev/null/nothing_here"
92
83
  Chef::Config[:ssl_client_key] = CHEF_SPEC_DATA + "/ssl/chef-rspec.key"
93
- expect { http_client }.to raise_error(Chef::Exceptions::ConfigurationError)
84
+ expect { http_client }.to raise_error(Chef::Exceptions::ConfigurationError, /ssl_client_cert .* does not exist/)
94
85
  end
95
86
 
96
- it "raises ConfigurationError if the certificate file doesn't exist" do
87
+ it "raises ConfigurationError if the private key file doesn't exist" do
97
88
  Chef::Config[:ssl_client_cert] = CHEF_SPEC_DATA + "/ssl/chef-rspec.cert"
98
89
  Chef::Config[:ssl_client_key] = "/dev/null/nothing_here"
99
- expect { http_client }.to raise_error(Chef::Exceptions::ConfigurationError)
90
+ expect { http_client }.to raise_error(Chef::Exceptions::ConfigurationError, /ssl_client_key .* does not exist/)
100
91
  end
101
92
 
102
93
  it "raises a ConfigurationError if one of :ssl_client_cert and :ssl_client_key is set but not both" do
103
94
  Chef::Config[:ssl_client_cert] = "/dev/null/nothing_here"
104
95
  Chef::Config[:ssl_client_key] = nil
105
- expect { http_client }.to raise_error(Chef::Exceptions::ConfigurationError)
96
+ expect { http_client }.to raise_error(Chef::Exceptions::ConfigurationError, /configure ssl_client_cert and ssl_client_key together/)
97
+ end
98
+
99
+ it "raises a ConfigurationError with a bad cert file" do
100
+ Chef::Config[:ssl_client_cert] = __FILE__
101
+ Chef::Config[:ssl_client_key] = CHEF_SPEC_DATA + "/ssl/chef-rspec.key"
102
+ expect { http_client }.to raise_error(Chef::Exceptions::ConfigurationError, /Error reading cert file '#{__FILE__}'/)
103
+ end
104
+
105
+ it "raises a ConfigurationError with a bad key file" do
106
+ Chef::Config[:ssl_client_cert] = CHEF_SPEC_DATA + "/ssl/chef-rspec.cert"
107
+ Chef::Config[:ssl_client_key] = __FILE__
108
+ expect { http_client }.to raise_error(Chef::Exceptions::ConfigurationError, /Error reading key file '#{__FILE__}'/)
106
109
  end
107
110
 
108
111
  it "configures the HTTP client's cert and private key" do
@@ -111,20 +114,31 @@ describe "HTTP SSL Policy" do
111
114
  expect(http_client.cert.to_s).to eq(OpenSSL::X509::Certificate.new(IO.read(CHEF_SPEC_DATA + "/ssl/chef-rspec.cert")).to_s)
112
115
  expect(http_client.key.to_s).to eq(OpenSSL::PKey::RSA.new(IO.read(CHEF_SPEC_DATA + "/ssl/chef-rspec.key")).to_s)
113
116
  end
114
- end
115
117
 
116
- context "when additional certs are located in the trusted_certs dir" do
117
- let(:self_signed_crt_path) { File.join(CHEF_SPEC_DATA, "trusted_certs", "example.crt") }
118
- let(:self_signed_crt) { OpenSSL::X509::Certificate.new(File.read(self_signed_crt_path)) }
118
+ it "configures the HTTP client's cert and private key with a DER encoded cert" do
119
+ Chef::Config[:ssl_client_cert] = CHEF_SPEC_DATA + "/ssl/binary/chef-rspec-der.cert"
120
+ Chef::Config[:ssl_client_key] = CHEF_SPEC_DATA + "/ssl/chef-rspec.key"
121
+ expect(http_client.cert.to_s).to eq(OpenSSL::X509::Certificate.new(IO.read(CHEF_SPEC_DATA + "/ssl/chef-rspec.cert")).to_s)
122
+ expect(http_client.key.to_s).to eq(OpenSSL::PKey::RSA.new(IO.read(CHEF_SPEC_DATA + "/ssl/chef-rspec.key")).to_s)
123
+ end
119
124
 
120
- let(:additional_pem_path) { File.join(CHEF_SPEC_DATA, "trusted_certs", "opscode.pem") }
121
- let(:additional_pem) { OpenSSL::X509::Certificate.new(File.read(additional_pem_path)) }
125
+ it "configures the HTTP client's cert and private key with a DER encoded key" do
126
+ Chef::Config[:ssl_client_cert] = CHEF_SPEC_DATA + "/ssl/chef-rspec.cert"
127
+ Chef::Config[:ssl_client_key] = CHEF_SPEC_DATA + "/ssl/binary/chef-rspec-der.key"
128
+ expect(http_client.cert.to_s).to eq(OpenSSL::X509::Certificate.new(IO.read(CHEF_SPEC_DATA + "/ssl/chef-rspec.cert")).to_s)
129
+ expect(http_client.key.to_s).to eq(OpenSSL::PKey::RSA.new(IO.read(CHEF_SPEC_DATA + "/ssl/chef-rspec.key")).to_s)
130
+ end
131
+ end
122
132
 
133
+ context "when additional certs are located in the trusted_certs dir" do
123
134
  before do
124
135
  Chef::Config.trusted_certs_dir = File.join(CHEF_SPEC_DATA, "trusted_certs")
125
136
  end
126
137
 
127
138
  it "enables verification of self-signed certificates" do
139
+ path = File.join(CHEF_SPEC_DATA, "trusted_certs", "example.crt")
140
+ self_signed_crt = OpenSSL::X509::Certificate.new(File.binread(path))
141
+
128
142
  expect(http_client.cert_store.verify(self_signed_crt)).to be_truthy
129
143
  end
130
144
 
@@ -137,39 +151,64 @@ describe "HTTP SSL Policy" do
137
151
  # If the machine running the test doesn't have ruby SSL configured correctly,
138
152
  # then the root cert also has to be loaded for the test to succeed.
139
153
  # The system under test **SHOULD** do both of these things.
154
+ path = File.join(CHEF_SPEC_DATA, "trusted_certs", "opscode.pem")
155
+ additional_pem = OpenSSL::X509::Certificate.new(File.binread(path))
156
+
140
157
  expect(http_client.cert_store.verify(additional_pem)).to be_truthy
141
158
  end
142
159
 
143
- context "and some certs are duplicates" do
144
- it "skips duplicate certs" do
145
- # For whatever reason, OpenSSL errors out when adding a
146
- # cert you already have to the certificate store.
147
- ssl_policy.set_custom_certs
148
- ssl_policy.set_custom_certs # should not raise an error
160
+ it "skips duplicate certs" do
161
+ # For whatever reason, OpenSSL errors out when adding a
162
+ # cert you already have to the certificate store.
163
+ ssl_policy = ssl_policy_class.new(Net::HTTP.new("example.com"))
164
+ ssl_policy.set_custom_certs
165
+ ssl_policy.set_custom_certs # should not raise an error
166
+ end
167
+
168
+ it "raises ConfigurationError with a bad cert file in the trusted_certs dir" do
169
+ ssl_policy = ssl_policy_class.new(Net::HTTP.new("example.com"))
170
+
171
+ Dir.mktmpdir do |dir|
172
+ bad_cert_file = File.join(dir, "bad_cert_file.crt")
173
+ File.write(bad_cert_file, File.read(__FILE__))
174
+
175
+ Chef::Config.trusted_certs_dir = dir
176
+ expect { ssl_policy.set_custom_certs }.to raise_error(Chef::Exceptions::ConfigurationError, /Error reading cert file/)
149
177
  end
150
178
  end
179
+
180
+ it "works with binary certs" do
181
+ Chef::Config.trusted_certs_dir = File.join(CHEF_SPEC_DATA, "ssl", "binary")
182
+
183
+ ssl_policy = ssl_policy_class.new(Net::HTTP.new("example.com"))
184
+ ssl_policy.set_custom_certs
185
+ end
151
186
  end
152
187
  end
153
188
 
154
189
  describe Chef::HTTP::APISSLPolicy do
155
190
 
156
- let(:ssl_policy) { Chef::HTTP::APISSLPolicy.new(unconfigured_http_client) }
191
+ let(:ssl_policy_class) { Chef::HTTP::APISSLPolicy }
157
192
 
158
- context "when verify_api_cert is set" do
159
- before do
160
- Chef::Config[:verify_api_cert] = true
161
- end
193
+ it "sets the OpenSSL verify mode to verify_peer when configured with :ssl_verify_mode set to :verify_peer" do
194
+ Chef::Config[:ssl_verify_mode] = :verify_peer
195
+ expect(http_client.verify_mode).to eq(OpenSSL::SSL::VERIFY_PEER)
196
+ end
162
197
 
163
- it "sets the OpenSSL verify mode to verify_peer" do
164
- expect(http_client.verify_mode).to eq(OpenSSL::SSL::VERIFY_PEER)
165
- end
198
+ it "sets the OpenSSL verify mode to :verify_none when configured with :ssl_verify_mode set to :verify_none" do
199
+ Chef::Config[:ssl_verify_mode] = :verify_none
200
+ expect(http_client.verify_mode).to eq(OpenSSL::SSL::VERIFY_NONE)
166
201
  end
167
202
 
203
+ it "sets the OpenSSL verify mode to verify_peer when verify_api_cert is set" do
204
+ Chef::Config[:verify_api_cert] = true
205
+ expect(http_client.verify_mode).to eq(OpenSSL::SSL::VERIFY_PEER)
206
+ end
168
207
  end
169
208
 
170
209
  describe Chef::HTTP::VerifyPeerSSLPolicy do
171
210
 
172
- let(:ssl_policy) { Chef::HTTP::VerifyPeerSSLPolicy.new(unconfigured_http_client) }
211
+ let(:ssl_policy_class) { Chef::HTTP::VerifyPeerSSLPolicy }
173
212
 
174
213
  it "sets the OpenSSL verify mode to verify_peer" do
175
214
  expect(http_client.verify_mode).to eq(OpenSSL::SSL::VERIFY_PEER)
@@ -179,7 +218,7 @@ describe "HTTP SSL Policy" do
179
218
 
180
219
  describe Chef::HTTP::VerifyNoneSSLPolicy do
181
220
 
182
- let(:ssl_policy) { Chef::HTTP::VerifyNoneSSLPolicy.new(unconfigured_http_client) }
221
+ let(:ssl_policy_class) { Chef::HTTP::VerifyNoneSSLPolicy }
183
222
 
184
223
  it "sets the OpenSSL verify mode to verify_peer" do
185
224
  expect(http_client.verify_mode).to eq(OpenSSL::SSL::VERIFY_NONE)