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.
- checksums.yaml +4 -4
- data/chef.gemspec +2 -0
- data/lib/chef/application/base.rb +11 -1
- data/lib/chef/client.rb +1 -2
- data/lib/chef/compliance/input.rb +115 -0
- data/lib/chef/compliance/input_collection.rb +139 -0
- data/lib/chef/compliance/profile.rb +122 -0
- data/lib/chef/compliance/profile_collection.rb +109 -0
- data/lib/chef/compliance/runner.rb +47 -5
- data/lib/chef/compliance/waiver.rb +115 -0
- data/lib/chef/compliance/waiver_collection.rb +143 -0
- data/lib/chef/dsl/compliance.rb +38 -0
- data/lib/chef/dsl/reader_helpers.rb +51 -0
- data/lib/chef/dsl/recipe.rb +4 -2
- data/lib/chef/dsl/secret.rb +2 -4
- data/lib/chef/dsl/universal.rb +2 -0
- data/lib/chef/event_dispatch/base.rb +44 -2
- data/lib/chef/formatters/doc.rb +46 -0
- data/lib/chef/http/basic_client.rb +15 -7
- data/lib/chef/http.rb +7 -3
- data/lib/chef/provider/file.rb +2 -0
- data/lib/chef/provider/link.rb +2 -2
- data/lib/chef/provider/registry_key.rb +3 -2
- data/lib/chef/provider/remote_file/http.rb +1 -1
- data/lib/chef/provider/template.rb +1 -1
- data/lib/chef/resource/archive_file.rb +17 -14
- data/lib/chef/resource/chef_client_scheduled_task.rb +45 -2
- data/lib/chef/resource/chocolatey_config.rb +13 -13
- data/lib/chef/resource/file/verification/json.rb +50 -0
- data/lib/chef/resource/file/verification/yaml.rb +52 -0
- data/lib/chef/resource/inspec_input.rb +128 -0
- data/lib/chef/resource/inspec_waiver.rb +185 -0
- data/lib/chef/resource/mount.rb +1 -1
- data/lib/chef/resource/registry_key.rb +36 -48
- data/lib/chef/resource/remote_file.rb +98 -2
- data/lib/chef/resource/timezone.rb +2 -2
- data/lib/chef/resource/user_ulimit.rb +1 -0
- data/lib/chef/resource/windows_printer.rb +1 -1
- data/lib/chef/resource/windows_uac.rb +3 -1
- data/lib/chef/resource/windows_user_privilege.rb +1 -1
- data/lib/chef/resources.rb +2 -0
- data/lib/chef/run_context/cookbook_compiler.rb +112 -28
- data/lib/chef/run_context.rb +31 -1
- data/lib/chef/secret_fetcher/akeyless_vault.rb +57 -0
- data/lib/chef/secret_fetcher/aws_secrets_manager.rb +1 -1
- data/lib/chef/secret_fetcher/azure_key_vault.rb +1 -1
- data/lib/chef/secret_fetcher/base.rb +1 -1
- data/lib/chef/secret_fetcher/hashi_vault.rb +100 -0
- data/lib/chef/secret_fetcher.rb +8 -2
- data/lib/chef/version.rb +1 -1
- data/spec/data/archive_file/test_archive.tar.gz +0 -0
- data/spec/functional/resource/archive_file_spec.rb +87 -0
- data/spec/functional/resource/group_spec.rb +5 -1
- data/spec/functional/resource/link_spec.rb +8 -0
- data/spec/integration/compliance/compliance_spec.rb +60 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/support/platform_helpers.rb +4 -0
- data/spec/support/ruby_installer.rb +51 -0
- data/spec/unit/compliance/input_spec.rb +104 -0
- data/spec/unit/compliance/profile_spec.rb +120 -0
- data/spec/unit/compliance/waiver_spec.rb +104 -0
- data/spec/unit/http/basic_client_spec.rb +30 -0
- data/spec/unit/http_spec.rb +8 -2
- data/spec/unit/provider/link_spec.rb +13 -7
- data/spec/unit/provider/remote_file/http_spec.rb +10 -0
- data/spec/unit/provider/template_spec.rb +2 -2
- data/spec/unit/resource/archive_file_spec.rb +414 -3
- data/spec/unit/resource/chef_client_scheduled_task_spec.rb +69 -0
- data/spec/unit/resource/file/verification/json_spec.rb +72 -0
- data/spec/unit/resource/file/verification/yaml_spec.rb +67 -0
- data/spec/unit/resource/inspec_input_spec.rb +300 -0
- data/spec/unit/resource/inspec_waiver_spec.rb +312 -0
- data/spec/unit/resource/mount_spec.rb +10 -0
- data/spec/unit/resource/user_ulimit_spec.rb +14 -1
- data/spec/unit/secret_fetcher/akeyless_vault_spec.rb +37 -0
- data/spec/unit/secret_fetcher/hashi_vault_spec.rb +80 -0
- data/tasks/rspec.rb +2 -1
- 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.
|
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::
|
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 '
|
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
|
+
|
data/lib/chef/secret_fetcher.rb
CHANGED
@@ -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
Binary file
|
@@ -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 =
|
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)
|
@@ -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
|