chef 17.4.38-universal-mingw32 → 17.5.22-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 (78) hide show
  1. checksums.yaml +4 -4
  2. data/chef.gemspec +2 -0
  3. data/lib/chef/application/base.rb +11 -1
  4. data/lib/chef/client.rb +1 -2
  5. data/lib/chef/compliance/input.rb +115 -0
  6. data/lib/chef/compliance/input_collection.rb +139 -0
  7. data/lib/chef/compliance/profile.rb +122 -0
  8. data/lib/chef/compliance/profile_collection.rb +109 -0
  9. data/lib/chef/compliance/runner.rb +47 -5
  10. data/lib/chef/compliance/waiver.rb +115 -0
  11. data/lib/chef/compliance/waiver_collection.rb +143 -0
  12. data/lib/chef/dsl/compliance.rb +38 -0
  13. data/lib/chef/dsl/reader_helpers.rb +51 -0
  14. data/lib/chef/dsl/recipe.rb +4 -2
  15. data/lib/chef/dsl/secret.rb +2 -4
  16. data/lib/chef/dsl/universal.rb +2 -0
  17. data/lib/chef/event_dispatch/base.rb +44 -2
  18. data/lib/chef/formatters/doc.rb +46 -0
  19. data/lib/chef/http/basic_client.rb +15 -7
  20. data/lib/chef/http.rb +7 -3
  21. data/lib/chef/provider/file.rb +2 -0
  22. data/lib/chef/provider/link.rb +2 -2
  23. data/lib/chef/provider/registry_key.rb +3 -2
  24. data/lib/chef/provider/remote_file/http.rb +1 -1
  25. data/lib/chef/provider/template.rb +1 -1
  26. data/lib/chef/resource/archive_file.rb +17 -14
  27. data/lib/chef/resource/chef_client_scheduled_task.rb +45 -2
  28. data/lib/chef/resource/chocolatey_config.rb +13 -13
  29. data/lib/chef/resource/file/verification/json.rb +50 -0
  30. data/lib/chef/resource/file/verification/yaml.rb +52 -0
  31. data/lib/chef/resource/inspec_input.rb +128 -0
  32. data/lib/chef/resource/inspec_waiver.rb +185 -0
  33. data/lib/chef/resource/mount.rb +1 -1
  34. data/lib/chef/resource/registry_key.rb +36 -48
  35. data/lib/chef/resource/remote_file.rb +98 -2
  36. data/lib/chef/resource/timezone.rb +2 -2
  37. data/lib/chef/resource/user_ulimit.rb +1 -0
  38. data/lib/chef/resource/windows_printer.rb +1 -1
  39. data/lib/chef/resource/windows_uac.rb +3 -1
  40. data/lib/chef/resource/windows_user_privilege.rb +1 -1
  41. data/lib/chef/resources.rb +2 -0
  42. data/lib/chef/run_context/cookbook_compiler.rb +112 -28
  43. data/lib/chef/run_context.rb +31 -1
  44. data/lib/chef/secret_fetcher/akeyless_vault.rb +57 -0
  45. data/lib/chef/secret_fetcher/aws_secrets_manager.rb +1 -1
  46. data/lib/chef/secret_fetcher/azure_key_vault.rb +1 -1
  47. data/lib/chef/secret_fetcher/base.rb +1 -1
  48. data/lib/chef/secret_fetcher/hashi_vault.rb +100 -0
  49. data/lib/chef/secret_fetcher.rb +8 -2
  50. data/lib/chef/version.rb +1 -1
  51. data/spec/data/archive_file/test_archive.tar.gz +0 -0
  52. data/spec/functional/resource/archive_file_spec.rb +87 -0
  53. data/spec/functional/resource/group_spec.rb +5 -1
  54. data/spec/functional/resource/link_spec.rb +8 -0
  55. data/spec/integration/compliance/compliance_spec.rb +60 -0
  56. data/spec/spec_helper.rb +3 -0
  57. data/spec/support/platform_helpers.rb +4 -0
  58. data/spec/support/ruby_installer.rb +51 -0
  59. data/spec/unit/compliance/input_spec.rb +104 -0
  60. data/spec/unit/compliance/profile_spec.rb +120 -0
  61. data/spec/unit/compliance/waiver_spec.rb +104 -0
  62. data/spec/unit/http/basic_client_spec.rb +30 -0
  63. data/spec/unit/http_spec.rb +8 -2
  64. data/spec/unit/provider/link_spec.rb +13 -7
  65. data/spec/unit/provider/remote_file/http_spec.rb +10 -0
  66. data/spec/unit/provider/template_spec.rb +2 -2
  67. data/spec/unit/resource/archive_file_spec.rb +414 -3
  68. data/spec/unit/resource/chef_client_scheduled_task_spec.rb +69 -0
  69. data/spec/unit/resource/file/verification/json_spec.rb +72 -0
  70. data/spec/unit/resource/file/verification/yaml_spec.rb +67 -0
  71. data/spec/unit/resource/inspec_input_spec.rb +300 -0
  72. data/spec/unit/resource/inspec_waiver_spec.rb +312 -0
  73. data/spec/unit/resource/mount_spec.rb +10 -0
  74. data/spec/unit/resource/user_ulimit_spec.rb +14 -1
  75. data/spec/unit/secret_fetcher/akeyless_vault_spec.rb +37 -0
  76. data/spec/unit/secret_fetcher/hashi_vault_spec.rb +80 -0
  77. data/tasks/rspec.rb +2 -1
  78. metadata +60 -6
@@ -0,0 +1,57 @@
1
+ #
2
+ # Author:: Marc Paradise (<marc@chef.io>)
3
+ # Copyright:: Copyright (c) Chef Software Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require_relative "base"
20
+ require_relative "hashi_vault"
21
+
22
+ class Chef
23
+ class SecretFetcher
24
+ # == Chef::SecretFetcher::AKeylessVault
25
+ # A fetcher that fetches a secret from AKeyless Vault. Initial implementation is
26
+ # based on HashiVault , because AKeyless provides a compatibility layer that makes this possible.
27
+ # Future revisions will use native akeyless authentication.
28
+ #
29
+ # Required config:
30
+ # :access_id - the access id of the API key
31
+ # :access_key - the access key of the API key
32
+ #
33
+ #
34
+ # @example
35
+ #
36
+ # fetcher = SecretFetcher.for_service(:akeyless_vault, { access_id: "my-access-id", access_key: "my-access-key" }, run_context )
37
+ # fetcher.fetch("/secret/data/secretkey1")
38
+ #
39
+ AKEYLESS_VAULT_PROXY_ADDR = "https://hvp.akeyless.io".freeze
40
+ class AKeylessVault < HashiVault
41
+ def validate!
42
+ if config[:access_key].nil?
43
+ raise Chef::Exceptions::Secret::ConfigurationInvalid.new("You must provide the secret access key in the configuration as :secret_access_key")
44
+ end
45
+ if config[:access_id].nil?
46
+ raise Chef::Exceptions::Secret::ConfigurationInvalid.new("You must provide the access key id in the configuration as :access_key_id")
47
+ end
48
+
49
+ config[:vault_addr] ||= AKEYLESS_VAULT_PROXY_ADDR
50
+ config[:auth_method] = :token
51
+ config[:token] = "#{config[:access_id]}..#{config[:access_key]}"
52
+ super
53
+ end
54
+ end
55
+ end
56
+ end
57
+
@@ -52,7 +52,7 @@ class Chef
52
52
  end
53
53
 
54
54
  # @param identifier [String] the secret_id
55
- # @param version [String] the secret version. Not usd at this time
55
+ # @param version [String] the secret version.
56
56
  # @return Aws::SecretsManager::Types::GetSecretValueResponse
57
57
  def do_fetch(identifier, version)
58
58
  client = Aws::SecretsManager::Client.new(config)
@@ -2,7 +2,7 @@ require_relative "base"
2
2
 
3
3
  class Chef
4
4
  class SecretFetcher
5
- # == Chef::SecretFetcher::AWSSecretsManager
5
+ # == Chef::SecretFetcher::AzureKeyVault
6
6
  # A fetcher that fetches a secret from Azure Key Vault. Supports fetching with version.
7
7
  #
8
8
  # In this initial iteration this authenticates via token obtained from the OAuth2 /token
@@ -56,7 +56,7 @@ class Chef
56
56
  # @raise [Chef::Exceptions::Secret::ConfigurationInvalid] if it is not.
57
57
  def validate!; end
58
58
 
59
- # Called to fetch the secret identified by 'identifer'. Implementations
59
+ # Called to fetch the secret identified by 'identifier'. Implementations
60
60
  # should expect that `validate!` has been invoked before `do_fetch`.
61
61
  #
62
62
  # @param identifier [Object] Unique identifier of the secret to be retrieved.
@@ -0,0 +1,100 @@
1
+ #
2
+ # Author:: Marc Paradise (<marc@chef.io>)
3
+ # Copyright:: Copyright (c) Chef Software Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require_relative "base"
20
+ require "aws-sdk-core" # Support for aws instance profile auth
21
+ require "vault"
22
+ class Chef
23
+ class SecretFetcher
24
+ # == Chef::SecretFetcher::HashiVault
25
+ # A fetcher that fetches a secret from Hashi Vault.
26
+ #
27
+ # Does not yet support fetching with version when a versioned key store is in use.
28
+ # In this initial iteration the only supported authentication is IAM role-based
29
+ #
30
+ # Required config:
31
+ # :auth_method - one of :iam_role, :token. default: :iam_role
32
+ # :vault_addr - the address of a running Vault instance, eg https://vault.example.com:8200
33
+ #
34
+ # For `:token` auth: `:token` - a Vault token valid for authentication.
35
+ #
36
+ # For `:iam_role`: `:role_name` - the name of the role in Vault that was created
37
+ # to support authentication via IAM. See the Vault documentation for details[1].
38
+ # A Terraform example is also available[2]
39
+ #
40
+ #
41
+ # [1] https://www.vaultproject.io/docs/auth/aws#recommended-vault-iam-policy
42
+ # [2] https://registry.terraform.io/modules/hashicorp/vault/aws/latest/examples/vault-iam-auth
43
+ # an IAM principal ARN bound to it.
44
+ #
45
+ # Optional config
46
+ # :namespace - the namespace under which secrets are kept. Only supported in with Vault Enterprise
47
+ #
48
+ # @example
49
+ #
50
+ # fetcher = SecretFetcher.for_service(:hashi_vault, { role_name: "testing-role", vault_addr: https://localhost:8200}, run_context )
51
+ # fetcher.fetch("secretkey1")
52
+ #
53
+ # @example
54
+ #
55
+ # fetcher = SecretFetcher.for_service(:hashi_vault, { auth_method: :token, token: "s.1234abcdef", vault_addr: https://localhost:8200}, run_context )
56
+ # fetcher.fetch("secretkey1")
57
+ SUPPORTED_AUTH_TYPES = %i{iam_role token}.freeze
58
+ class HashiVault < Base
59
+
60
+ # Validate and authenticate the current session using the configured auth strategy and parameters
61
+ def validate!
62
+ if config[:vault_addr].nil?
63
+ raise Chef::Exceptions::Secret::ConfigurationInvalid.new("You must provide the Vault address in the configuration as :vault_addr")
64
+ end
65
+
66
+ Vault.address = config[:vault_addr]
67
+ Vault.namespace = config[:namespace] unless config[:namespace].nil?
68
+
69
+ case config[:auth_method]
70
+ when :token
71
+ if config[:token].nil?
72
+ raise Chef::Exceptions::Secret::ConfigurationInvalid.new("You must provide the token in the configuration as :token")
73
+ end
74
+
75
+ Vault.auth.token(config[:token])
76
+ when :iam_role, nil
77
+ if config[:role_name].nil?
78
+ raise Chef::Exceptions::Secret::ConfigurationInvalid.new("You must provide the authenticating Vault role name in the configuration as :role_name")
79
+ end
80
+
81
+ Vault.auth.aws_iam(config[:role_name], Aws::InstanceProfileCredentials.new)
82
+ else
83
+ raise Chef::Exceptions::Secret::ConfigurationInvalid.new("Invalid :auth_method provided. You gave #{config[:auth_method]}, expected one of :#{SUPPORTED_AUTH_TYPES.join(", :")} ")
84
+ end
85
+ end
86
+
87
+ # @param identifier [String] Identifier of the secret to be fetched, which should
88
+ # be the full path of that secret, eg 'secret/example'
89
+ # @param _version [String] not used in this implementation
90
+ # @return [Hash] containing key/value pairs stored at the location given in 'identifier'
91
+ def do_fetch(identifier, _version)
92
+ result = Vault.logical.read(identifier)
93
+ raise Chef::Exceptions::Secret::FetchFailed.new("No secret found at #{identifier}. Check to ensure that there is a secrets engine configured for that path") if result.nil?
94
+
95
+ result.data
96
+ end
97
+ end
98
+ end
99
+ end
100
+
@@ -21,7 +21,7 @@ require_relative "exceptions"
21
21
  class Chef
22
22
  class SecretFetcher
23
23
 
24
- SECRET_FETCHERS = %i{example aws_secrets_manager azure_key_vault}.freeze
24
+ SECRET_FETCHERS = %i{example aws_secrets_manager azure_key_vault hashi_vault akeyless_vault}.freeze
25
25
 
26
26
  # Returns a configured and validated instance
27
27
  # of a [Chef::SecretFetcher::Base] for the given
@@ -42,10 +42,16 @@ class Chef
42
42
  when :azure_key_vault
43
43
  require_relative "secret_fetcher/azure_key_vault"
44
44
  Chef::SecretFetcher::AzureKeyVault.new(config, run_context)
45
+ when :hashi_vault
46
+ require_relative "secret_fetcher/hashi_vault"
47
+ Chef::SecretFetcher::HashiVault.new(config, run_context)
48
+ when :akeyless_vault
49
+ require_relative "secret_fetcher/akeyless_vault"
50
+ Chef::SecretFetcher::AKeylessVault.new(config, run_context)
45
51
  when nil, ""
46
52
  raise Chef::Exceptions::Secret::MissingFetcher.new(SECRET_FETCHERS)
47
53
  else
48
- raise Chef::Exceptions::Secret::InvalidFetcherService.new("Unsupported secret service: #{service}", SECRET_FETCHERS)
54
+ raise Chef::Exceptions::Secret::InvalidFetcherService.new("Unsupported secret service: '#{service}'", SECRET_FETCHERS)
49
55
  end
50
56
  fetcher.validate!
51
57
  fetcher
data/lib/chef/version.rb CHANGED
@@ -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("17.4.38")
26
+ VERSION = Chef::VersionString.new("17.5.22")
27
27
  end
28
28
 
29
29
  #
@@ -0,0 +1,87 @@
1
+ #
2
+ # Copyright:: Copyright (c) Chef Software Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require "spec_helper"
19
+ require "tmpdir"
20
+
21
+ # Exclude this test on platforms where ffi-libarchive loading is broken
22
+ describe Chef::Resource::ArchiveFile, :libarchive_loading_broken do
23
+ include RecipeDSLHelper
24
+
25
+ let(:tmp_path) { Dir.mktmpdir }
26
+ let(:extract_destination) { "#{tmp_path}/extract_here" }
27
+ let(:test_archive_path) { File.expand_path("archive_file/test_archive.tar.gz", CHEF_SPEC_DATA) }
28
+
29
+ after do
30
+ FileUtils.remove_entry_secure(extract_destination) if File.exist?(extract_destination)
31
+ end
32
+
33
+ context "when strip_components is 0" do
34
+ it "extracts archive to destination" do
35
+ af = archive_file test_archive_path do
36
+ destination extract_destination
37
+ end
38
+ af.should_be_updated
39
+
40
+ expect(af.strip_components).to eq(0) # Validate defaults haven't changed here
41
+ expect(Dir.glob("#{extract_destination}/**/*").length).to eq(4)
42
+ expect(Dir.exist?("#{extract_destination}/folder-1")).to eq(true)
43
+ expect(File.exist?("#{extract_destination}/folder-1/file-1.txt")).to eq(true)
44
+ expect(Dir.exist?("#{extract_destination}/folder-1/folder-2")).to eq(true)
45
+ expect(File.exist?("#{extract_destination}/folder-1/folder-2/file-2.txt")).to eq(true)
46
+ end
47
+ end
48
+
49
+ context "when strip_components is 1" do
50
+ it "extracts archive to destination, with 1 component stripped" do
51
+ archive_file test_archive_path do
52
+ destination extract_destination
53
+ strip_components 1
54
+ end.should_be_updated
55
+
56
+ expect(Dir.exist?("#{extract_destination}/folder-1")).to eq(false)
57
+ expect(File.exist?("#{extract_destination}/folder-1/file-1.txt")).to eq(false)
58
+ expect(Dir.exist?("#{extract_destination}/folder-1/folder-2")).to eq(false)
59
+ expect(File.exist?("#{extract_destination}/folder-1/folder-2/file-2.txt")).to eq(false)
60
+
61
+ expect(Dir.glob("#{extract_destination}/**/*").length).to eq(3)
62
+ expect(File.exist?("#{extract_destination}/file-1.txt")).to eq(true)
63
+ expect(Dir.exist?("#{extract_destination}/folder-2")).to eq(true)
64
+ expect(File.exist?("#{extract_destination}/folder-2/file-2.txt")).to eq(true)
65
+ end
66
+ end
67
+
68
+ context "when strip_components is 2" do
69
+ it "extracts archive to destination, with 2 components stripped" do
70
+ archive_file test_archive_path do
71
+ destination extract_destination
72
+ strip_components 2
73
+ end.should_be_updated
74
+
75
+ expect(Dir.exist?("#{extract_destination}/folder-1")).to eq(false)
76
+ expect(File.exist?("#{extract_destination}/folder-1/file-1.txt")).to eq(false)
77
+ expect(Dir.exist?("#{extract_destination}/folder-1/folder-2")).to eq(false)
78
+ expect(File.exist?("#{extract_destination}/folder-1/folder-2/file-2.txt")).to eq(false)
79
+ expect(File.exist?("#{extract_destination}/file-1.txt")).to eq(false)
80
+ expect(Dir.exist?("#{extract_destination}/folder-2")).to eq(false)
81
+ expect(File.exist?("#{extract_destination}/folder-2/file-2.txt")).to eq(false)
82
+
83
+ expect(Dir.glob("#{extract_destination}/**/*").length).to eq(1)
84
+ expect(File.exist?("#{extract_destination}/file-2.txt")).to eq(true)
85
+ end
86
+ end
87
+ end
@@ -44,6 +44,10 @@ describe Chef::Resource::Group, :requires_root_or_running_windows do
44
44
  members.shift # Get rid of GroupMembership: string
45
45
  members.include?(user)
46
46
  else
47
+ # TODO For some reason our temporary AIX 7.2 system does not correctly report group membership immediately after changes have been made.
48
+ # Adding a 2 second delay for this platform is enough to get correct results.
49
+ # We hope to remove this delay after we get more permanent AIX 7.2 systems in our CI pipeline. reference: https://github.com/chef/release-engineering/issues/1617
50
+ sleep 2 if aix? && (ohai[:platform_version] == "7.2")
47
51
  Etc.getgrnam(group_name).mem.include?(user)
48
52
  end
49
53
  end
@@ -181,7 +185,7 @@ describe Chef::Resource::Group, :requires_root_or_running_windows do
181
185
 
182
186
  describe "when the users exist" do
183
187
  before do
184
- high_uid = 30000
188
+ high_uid = 40000
185
189
  (spec_members).each do |member|
186
190
  remove_user(member)
187
191
  create_user(member, high_uid)
@@ -345,9 +345,17 @@ describe Chef::Resource::Link do
345
345
  let(:test_user) { "test-link-user" }
346
346
  before do
347
347
  user(test_user).run_action(:create)
348
+ # TODO For some reason our temporary AIX 7.2 system does not correctly report user existence immediately after changes have been made.
349
+ # Adding a 2 second delay for this platform is enough to get correct results.
350
+ # We hope to remove this delay after we get more permanent AIX 7.2 systems in our CI pipeline. reference: https://github.com/chef/release-engineering/issues/1617
351
+ sleep 2 if aix? && (ohai[:platform_version] == "7.2")
348
352
  end
349
353
  after do
350
354
  user(test_user).run_action(:remove)
355
+ # TODO For some reason our temporary AIX 7.2 system does not correctly report user existence immediately after changes have been made.
356
+ # Adding a 2 second delay for this platform is enough to get correct results.
357
+ # We hope to remove this delay after we get more permanent AIX 7.2 systems in our CI pipeline. reference: https://github.com/chef/release-engineering/issues/1617
358
+ sleep 2 if aix? && (ohai[:platform_version] == "7.2")
351
359
  end
352
360
  before(:each) do
353
361
  resource.owner(test_user)
@@ -80,4 +80,64 @@ describe "chef-client with compliance phase" do
80
80
  expect(result["status"]).to eq("passed")
81
81
  end
82
82
  end
83
+
84
+ when_the_repository "has a compliance segment" do
85
+ let(:report_file) { path_to("report_file.json") }
86
+
87
+ before do
88
+ directory "cookbooks/x" do
89
+ directory "compliance" do
90
+ directory "profiles/my_profile" do
91
+ file "inspec.yml", <<~FILE
92
+ ---
93
+ name: my-profile
94
+ FILE
95
+
96
+ directory "controls" do
97
+ file "my_control.rb", <<~FILE
98
+ control "my control" do
99
+ describe Dir.home do
100
+ it { should be_kind_of String }
101
+ end
102
+ end
103
+ FILE
104
+ end
105
+ end
106
+ end
107
+ file "attributes/default.rb", <<~FILE
108
+ default['audit']['reporter'] = "json-file"
109
+ default['audit']['json_file'] = {
110
+ "location" => "#{report_file}"
111
+ }
112
+ FILE
113
+ file "recipes/default.rb", <<~FILE
114
+ include_profile ".*::.*"
115
+ FILE
116
+ end
117
+ file "config/client.rb", <<~EOM
118
+ local_mode true
119
+ cookbook_path "#{path_to("cookbooks")}"
120
+ log_level :warn
121
+ EOM
122
+ end
123
+
124
+ it "should complete with success" do
125
+ result = shell_out!("#{chef_client} -c \"#{path_to("config/client.rb")}\" -r 'recipe[x]'", cwd: chef_dir)
126
+ result.error!
127
+
128
+ inspec_report = JSON.parse(File.read(report_file))
129
+ expect(inspec_report["profiles"].length).to eq(1)
130
+
131
+ profile = inspec_report["profiles"].first
132
+ expect(profile["name"]).to eq("my-profile")
133
+ expect(profile["controls"].length).to eq(1)
134
+
135
+ control = profile["controls"].first
136
+ expect(control["id"]).to eq("my control")
137
+ expect(control["results"].length).to eq(1)
138
+
139
+ result = control["results"].first
140
+ expect(result["status"]).to eq("passed")
141
+ end
142
+ end
83
143
  end
data/spec/spec_helper.rb CHANGED
@@ -68,6 +68,7 @@ end
68
68
  require "spec/support/local_gems" if File.exist?(File.join(File.dirname(__FILE__), "support", "local_gems.rb"))
69
69
 
70
70
  # Explicitly require spec helpers that need to load first
71
+ require "spec/support/ruby_installer"
71
72
  require "spec/support/platform_helpers"
72
73
  require "spec/support/shared/unit/mock_shellout"
73
74
 
@@ -186,6 +187,8 @@ RSpec.configure do |config|
186
187
  config.filter_run_excluding not_rhel7: true if rhel7?
187
188
  config.filter_run_excluding not_intel_64bit: true if intel_64bit?
188
189
 
190
+ config.filter_run_excluding libarchive_loading_broken: true if aix? || amazon_linux? || rhel7?
191
+
189
192
  # these let us use chef: ">= 13" or ruby: "~> 2.0.0" or any other Gem::Dependency-style constraint
190
193
  config.filter_run_excluding chef: DependencyProc.with(Chef::VERSION)
191
194
  config.filter_run_excluding ruby: DependencyProc.with(RUBY_VERSION)
@@ -163,6 +163,10 @@ def aix?
163
163
  RUBY_PLATFORM.include?("aix")
164
164
  end
165
165
 
166
+ def amazon_linux?
167
+ ohai[:platform_family] == "amazon"
168
+ end
169
+
166
170
  def wpar?
167
171
  !((ohai[:virtualization] || {})[:wpar_no].nil?)
168
172
  end
@@ -0,0 +1,51 @@
1
+ #
2
+ # Copyright:: Copyright (c) Chef Software Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ def add_libarchive_dll_directory
18
+ require "ruby_installer"
19
+ libarchive_paths = Dir.glob("{#{Gem.dir},C:/hab}/**/libarchive.dll").map { |f| File.expand_path(f) }
20
+ if libarchive_paths.empty?
21
+ $stderr.puts <<~EOL
22
+ !!!!
23
+ We couldn't find a libarchive.dll in #{Gem.dir} or C:/hab
24
+
25
+ If this is running in a CI/CD environment, this may end up causing failures
26
+ in the tests for archive_file. If this is not running in a CI/CD
27
+ environment then it may be safe to ignore this. That is especially true if
28
+ you're not using the Ruby Installer as your Ruby runtime.
29
+ !!!!
30
+ EOL
31
+ return
32
+ end
33
+
34
+ $stderr.puts "\nFound the following libarchive paths:\n\n#{libarchive_paths.map { |f| "- #{f}\n" }.join}\n\n"
35
+ libarchive_path = libarchive_paths.first
36
+ libarchive_dir = File.dirname(libarchive_path)
37
+
38
+ if defined?(RubyInstaller::Build) && RubyInstaller::Build.methods.include?(:add_dll_directory)
39
+ $stderr.puts "Adding #{libarchive_dir} as a DLL load path using RubyInstaller::Build#add_dll_directory"
40
+ RubyInstaller::Build.add_dll_directory(libarchive_dir)
41
+ elsif defined?(RubyInstaller::Runtime) && RubyInstaller::Runtime.methods.include?(:add_dll_directory)
42
+ $stderr.puts "Adding #{libarchive_dir} as a DLL load path using RubyInstaller::Runtime#add_dll_directory"
43
+ RubyInstaller::Runtime.add_dll_directory(libarchive_dir)
44
+ else
45
+ $stderr.puts "Unable to find the right namespace to call #add_dll_directory! Please raise an issue on [GitHub](https://github.com/chef/chef/issues/new/choose)."
46
+ end
47
+ rescue LoadError
48
+ $stderr.puts "Failed to load ruby_installer. Assuming Ruby Installer is not being used."
49
+ end
50
+
51
+ add_libarchive_dll_directory if RUBY_PLATFORM =~ /mswin|mingw32|windows/
@@ -0,0 +1,104 @@
1
+ #
2
+ # Copyright:: Copyright (c) Chef Software Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require "spec_helper"
19
+ require "tempfile"
20
+
21
+ describe Chef::Compliance::Input do
22
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
23
+ let(:data) { { "ssh-01" => { "expiration_date" => Date.jd(2463810), "justification" => "waived, yo", "run" => false } } }
24
+ let(:path) { "/var/chef/cache/cookbooks/acme_compliance/compliance/inputs/default.yml" }
25
+ let(:cookbook_name) { "acme_compliance" }
26
+ let(:input) { Chef::Compliance::Input.new(events, data, path, cookbook_name) }
27
+
28
+ it "has a cookbook_name" do
29
+ expect(input.cookbook_name).to eql(cookbook_name)
30
+ end
31
+
32
+ it "has a path" do
33
+ expect(input.path).to eql(path)
34
+ end
35
+
36
+ it "has a pathname based on the path" do
37
+ expect(input.pathname).to eql("default")
38
+ end
39
+
40
+ it "is disabled" do
41
+ expect(input.enabled).to eql(false)
42
+ expect(input.enabled?).to eql(false)
43
+ end
44
+
45
+ it "has an event handler" do
46
+ expect(input.events).to eql(events)
47
+ end
48
+
49
+ it "can be enabled by enable!" do
50
+ input.enable!
51
+ expect(input.enabled).to eql(true)
52
+ expect(input.enabled?).to eql(true)
53
+ end
54
+
55
+ it "enabling sends an event" do
56
+ expect(events).to receive(:compliance_input_enabled).with(input)
57
+ input.enable!
58
+ end
59
+
60
+ it "can be disabled by disable!" do
61
+ input.enable!
62
+ input.disable!
63
+ expect(input.enabled).to eql(false)
64
+ expect(input.enabled?).to eql(false)
65
+ end
66
+
67
+ it "has a #inspec_data method that renders the data" do
68
+ expect(input.inspec_data).to eql(data)
69
+ end
70
+
71
+ it "doesn't render the events in the inspect output" do
72
+ expect(input.inspect).not_to include("events")
73
+ end
74
+
75
+ it "inflates objects from YAML" do
76
+ string = <<~EOH
77
+ ssh-01:
78
+ expiration_date: 2033-07-31
79
+ run: false
80
+ justification: "waived, yo"
81
+ EOH
82
+ newinput = Chef::Compliance::Input.from_yaml(events, string, path, cookbook_name)
83
+ expect(newinput.data).to eql(data)
84
+ end
85
+
86
+ it "inflates objects from files" do
87
+ string = <<~EOH
88
+ ssh-01:
89
+ expiration_date: 2033-07-31
90
+ run: false
91
+ justification: "waived, yo"
92
+ EOH
93
+ tempfile = Tempfile.new("chef-compliance-test")
94
+ tempfile.write string
95
+ tempfile.close
96
+ newinput = Chef::Compliance::Input.from_file(events, tempfile.path, cookbook_name)
97
+ expect(newinput.data).to eql(data)
98
+ end
99
+
100
+ it "inflates objects from hashes" do
101
+ newinput = Chef::Compliance::Input.from_hash(events, data, path, cookbook_name)
102
+ expect(newinput.data).to eql(data)
103
+ end
104
+ end