chef 17.2.29 → 17.5.22

Sign up to get free protection for your applications and to get access to all the features.
Files changed (173) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +6 -5
  3. data/chef.gemspec +3 -0
  4. data/lib/chef/application/base.rb +11 -1
  5. data/lib/chef/application.rb +3 -1
  6. data/lib/chef/client.rb +2 -3
  7. data/lib/chef/compliance/default_attributes.rb +5 -3
  8. data/lib/chef/compliance/input.rb +115 -0
  9. data/lib/chef/compliance/input_collection.rb +139 -0
  10. data/lib/chef/compliance/profile.rb +122 -0
  11. data/lib/chef/compliance/profile_collection.rb +109 -0
  12. data/lib/chef/compliance/reporter/automate.rb +1 -1
  13. data/lib/chef/compliance/runner.rb +62 -6
  14. data/lib/chef/compliance/waiver.rb +115 -0
  15. data/lib/chef/compliance/waiver_collection.rb +143 -0
  16. data/lib/chef/data_bag.rb +1 -2
  17. data/lib/chef/data_bag_item.rb +1 -2
  18. data/lib/chef/deprecated.rb +10 -4
  19. data/lib/chef/dsl/compliance.rb +38 -0
  20. data/lib/chef/dsl/reader_helpers.rb +51 -0
  21. data/lib/chef/dsl/recipe.rb +4 -2
  22. data/lib/chef/dsl/render_helpers.rb +44 -0
  23. data/lib/chef/dsl/secret.rb +62 -0
  24. data/lib/chef/dsl/toml.rb +116 -0
  25. data/lib/chef/dsl/universal.rb +7 -0
  26. data/lib/chef/dsl.rb +1 -0
  27. data/lib/chef/event_dispatch/base.rb +44 -2
  28. data/lib/chef/exceptions.rb +20 -0
  29. data/lib/chef/formatters/doc.rb +60 -13
  30. data/lib/chef/formatters/error_mapper.rb +2 -2
  31. data/lib/chef/formatters/minimal.rb +6 -5
  32. data/lib/chef/handler/slow_report.rb +1 -1
  33. data/lib/chef/http/basic_client.rb +15 -7
  34. data/lib/chef/http.rb +12 -8
  35. data/lib/chef/json_compat.rb +1 -1
  36. data/lib/chef/policy_builder/policyfile.rb +88 -45
  37. data/lib/chef/provider/execute.rb +1 -1
  38. data/lib/chef/provider/file.rb +4 -2
  39. data/lib/chef/provider/group/dscl.rb +1 -1
  40. data/lib/chef/provider/launchd.rb +6 -6
  41. data/lib/chef/provider/link.rb +2 -2
  42. data/lib/chef/provider/lwrp_base.rb +1 -1
  43. data/lib/chef/provider/package/habitat.rb +168 -0
  44. data/lib/chef/provider/package/powershell.rb +5 -0
  45. data/lib/chef/provider/registry_key.rb +3 -2
  46. data/lib/chef/provider/remote_file/http.rb +1 -1
  47. data/lib/chef/provider/subversion.rb +4 -4
  48. data/lib/chef/provider/support/yum_repo.erb +1 -1
  49. data/lib/chef/provider/systemd_unit.rb +17 -16
  50. data/lib/chef/provider/template.rb +1 -1
  51. data/lib/chef/provider/user/mac.rb +3 -3
  52. data/lib/chef/provider/yum_repository.rb +27 -43
  53. data/lib/chef/provider/zypper_repository.rb +3 -3
  54. data/lib/chef/provider.rb +26 -1
  55. data/lib/chef/provider_resolver.rb +8 -2
  56. data/lib/chef/providers.rb +1 -0
  57. data/lib/chef/resource/archive_file.rb +17 -14
  58. data/lib/chef/resource/chef_client_config.rb +7 -2
  59. data/lib/chef/resource/chef_client_cron.rb +1 -1
  60. data/lib/chef/resource/chef_client_launchd.rb +1 -1
  61. data/lib/chef/resource/chef_client_scheduled_task.rb +46 -3
  62. data/lib/chef/resource/chef_client_systemd_timer.rb +1 -1
  63. data/lib/chef/resource/chef_client_trusted_certificate.rb +2 -2
  64. data/lib/chef/resource/chef_vault_secret.rb +2 -2
  65. data/lib/chef/resource/chocolatey_config.rb +13 -13
  66. data/lib/chef/resource/dsc_resource.rb +1 -1
  67. data/lib/chef/resource/execute.rb +5 -5
  68. data/lib/chef/resource/file/verification/json.rb +50 -0
  69. data/lib/chef/resource/file/verification/yaml.rb +52 -0
  70. data/lib/chef/resource/gem_package.rb +2 -1
  71. data/lib/chef/resource/habitat/_habitat_shared.rb +28 -0
  72. data/lib/chef/resource/habitat/habitat_package.rb +129 -0
  73. data/lib/chef/resource/habitat/habitat_sup.rb +329 -0
  74. data/lib/chef/resource/habitat/habitat_sup_systemd.rb +67 -0
  75. data/lib/chef/resource/habitat/habitat_sup_windows.rb +90 -0
  76. data/lib/chef/resource/habitat_config.rb +107 -0
  77. data/lib/chef/resource/habitat_install.rb +247 -0
  78. data/lib/chef/resource/habitat_service.rb +451 -0
  79. data/lib/chef/resource/habitat_user_toml.rb +92 -0
  80. data/lib/chef/resource/homebrew_cask.rb +1 -1
  81. data/lib/chef/resource/inspec_input.rb +128 -0
  82. data/lib/chef/resource/inspec_waiver.rb +185 -0
  83. data/lib/chef/resource/inspec_waiver_file_entry.rb +2 -2
  84. data/lib/chef/resource/launchd.rb +3 -3
  85. data/lib/chef/resource/lwrp_base.rb +1 -1
  86. data/lib/chef/resource/mount.rb +1 -1
  87. data/lib/chef/resource/registry_key.rb +36 -48
  88. data/lib/chef/resource/remote_file.rb +99 -3
  89. data/lib/chef/resource/rhsm_subscription.rb +5 -5
  90. data/lib/chef/resource/ruby_block.rb +100 -0
  91. data/lib/chef/resource/scm/subversion.rb +1 -1
  92. data/lib/chef/resource/support/HabService.dll.config.erb +19 -0
  93. data/lib/chef/resource/support/client.erb +8 -1
  94. data/lib/chef/resource/support/sup.toml.erb +179 -0
  95. data/lib/chef/resource/sysctl.rb +2 -2
  96. data/lib/chef/resource/systemd_unit.rb +3 -3
  97. data/lib/chef/resource/timezone.rb +2 -2
  98. data/lib/chef/resource/user_ulimit.rb +1 -0
  99. data/lib/chef/resource/windows_defender.rb +163 -0
  100. data/lib/chef/resource/windows_defender_exclusion.rb +125 -0
  101. data/lib/chef/resource/windows_printer.rb +78 -44
  102. data/lib/chef/resource/windows_printer_port.rb +1 -1
  103. data/lib/chef/resource/windows_uac.rb +3 -1
  104. data/lib/chef/resource/windows_update_settings.rb +259 -0
  105. data/lib/chef/resource/windows_user_privilege.rb +1 -1
  106. data/lib/chef/resource/yum_package.rb +1 -5
  107. data/lib/chef/resource.rb +13 -17
  108. data/lib/chef/resource_inspector.rb +6 -2
  109. data/lib/chef/resources.rb +14 -1
  110. data/lib/chef/run_context/cookbook_compiler.rb +112 -28
  111. data/lib/chef/run_context.rb +31 -1
  112. data/lib/chef/secret_fetcher/akeyless_vault.rb +57 -0
  113. data/lib/chef/secret_fetcher/aws_secrets_manager.rb +65 -0
  114. data/lib/chef/secret_fetcher/azure_key_vault.rb +78 -0
  115. data/lib/chef/secret_fetcher/base.rb +76 -0
  116. data/lib/chef/secret_fetcher/example.rb +46 -0
  117. data/lib/chef/secret_fetcher/hashi_vault.rb +100 -0
  118. data/lib/chef/secret_fetcher.rb +61 -0
  119. data/lib/chef/version.rb +1 -1
  120. data/spec/data/archive_file/test_archive.tar.gz +0 -0
  121. data/spec/functional/mixin/from_file_spec.rb +1 -1
  122. data/spec/functional/resource/archive_file_spec.rb +87 -0
  123. data/spec/functional/resource/group_spec.rb +5 -1
  124. data/spec/functional/resource/link_spec.rb +8 -0
  125. data/spec/integration/compliance/compliance_spec.rb +61 -0
  126. data/spec/integration/recipes/recipe_dsl_spec.rb +1 -1
  127. data/spec/integration/recipes/resource_action_spec.rb +6 -6
  128. data/spec/spec_helper.rb +3 -0
  129. data/spec/support/platform_helpers.rb +4 -0
  130. data/spec/support/ruby_installer.rb +51 -0
  131. data/spec/support/shared/unit/provider/file.rb +2 -8
  132. data/spec/unit/compliance/input_spec.rb +104 -0
  133. data/spec/unit/compliance/profile_spec.rb +120 -0
  134. data/spec/unit/compliance/runner_spec.rb +46 -2
  135. data/spec/unit/compliance/waiver_spec.rb +104 -0
  136. data/spec/unit/data_bag_item_spec.rb +2 -2
  137. data/spec/unit/data_bag_spec.rb +1 -1
  138. data/spec/unit/dsl/render_helpers_spec.rb +102 -0
  139. data/spec/unit/dsl/secret_spec.rb +71 -0
  140. data/spec/unit/formatters/doc_spec.rb +1 -1
  141. data/spec/unit/http/basic_client_spec.rb +30 -0
  142. data/spec/unit/http_spec.rb +8 -2
  143. data/spec/unit/policy_builder/dynamic_spec.rb +0 -5
  144. data/spec/unit/policy_builder/policyfile_spec.rb +144 -56
  145. data/spec/unit/provider/apt_update_spec.rb +3 -1
  146. data/spec/unit/provider/link_spec.rb +13 -7
  147. data/spec/unit/provider/mount/aix_spec.rb +1 -1
  148. data/spec/unit/provider/package/powershell_spec.rb +74 -12
  149. data/spec/unit/provider/remote_file/http_spec.rb +10 -0
  150. data/spec/unit/provider/template_spec.rb +2 -2
  151. data/spec/unit/provider_spec.rb +23 -0
  152. data/spec/unit/resource/archive_file_spec.rb +414 -3
  153. data/spec/unit/resource/chef_client_scheduled_task_spec.rb +69 -0
  154. data/spec/unit/resource/file/verification/json_spec.rb +72 -0
  155. data/spec/unit/resource/file/verification/yaml_spec.rb +67 -0
  156. data/spec/unit/resource/homebrew_cask_spec.rb +29 -11
  157. data/spec/unit/resource/inspec_input_spec.rb +300 -0
  158. data/spec/unit/resource/inspec_waiver_spec.rb +312 -0
  159. data/spec/unit/resource/mount_spec.rb +10 -0
  160. data/spec/unit/resource/rhsm_subscription_spec.rb +50 -3
  161. data/spec/unit/resource/systemd_unit_spec.rb +1 -1
  162. data/spec/unit/resource/user_ulimit_spec.rb +14 -1
  163. data/spec/unit/resource/windows_defender_exclusion_spec.rb +62 -0
  164. data/spec/unit/resource/windows_defender_spec.rb +71 -0
  165. data/spec/unit/resource/windows_update_settings_spec.rb +64 -0
  166. data/spec/unit/resource_spec.rb +19 -8
  167. data/spec/unit/secret_fetcher/akeyless_vault_spec.rb +37 -0
  168. data/spec/unit/secret_fetcher/aws_secrets_manager_spec.rb +70 -0
  169. data/spec/unit/secret_fetcher/azure_key_vault_spec.rb +70 -0
  170. data/spec/unit/secret_fetcher/hashi_vault_spec.rb +80 -0
  171. data/spec/unit/secret_fetcher_spec.rb +82 -0
  172. data/tasks/rspec.rb +2 -1
  173. metadata +106 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3259221c96da998dc7da695df0488bcfbe781ce3764dcd98309c78c1a46cb56c
4
- data.tar.gz: 120938b331b2e96306b91c5a192a73ebbfaeebce9b3febfccae32d7e7918e4a6
3
+ metadata.gz: bfe0cb34ad720e2647118256d4260f209cd36d73e6ccedf079a67489963901c1
4
+ data.tar.gz: bc5229775dbb96f3f61cf2d11dfa16de3c0e2de6567169ed11cea54502a18679
5
5
  SHA512:
6
- metadata.gz: f1191c217a427591d0cdd0b0223249ed83164f53da4edd463258dfe37d084b9e928627eb9020a20aeb87f141d160eb72b64d4c1d37e47b7206f50e120b7738fe
7
- data.tar.gz: '0148bdae1adf6ffa4539aab3c8dbc47fc225cb5d6f1e421967be4d53ce7504f9ff10af21cd0410412847b9e99d6308892b32a0ab673bd657ccb6922f191c91a1'
6
+ metadata.gz: afce77f4964d02364b91be0128053ac2f866a41225308dd68d857d468c660d774450d95926e86615818791a37c9c6930c1ed1fdae4145f483f35dd633413ae1d
7
+ data.tar.gz: 8db608f6151726772e05ac054fb31d37da4e21e16101f383d70eed9622d88b1362573e56d2eed50b38cd7fd5258631d3b99db7f9f6e26415d9a48a751a4a78a7
data/Gemfile CHANGED
@@ -2,7 +2,7 @@ source "https://rubygems.org"
2
2
 
3
3
  gem "chef", path: "."
4
4
 
5
- gem "ohai", git: "https://github.com/chef/ohai.git", branch: "master"
5
+ gem "ohai", git: "https://github.com/chef/ohai.git", branch: "main"
6
6
 
7
7
  gem "chef-utils", path: File.expand_path("chef-utils", __dir__) if File.exist?(File.expand_path("chef-utils", __dir__))
8
8
  gem "chef-config", path: File.expand_path("chef-config", __dir__) if File.exist?(File.expand_path("chef-config", __dir__))
@@ -22,13 +22,14 @@ group(:omnibus_package) do
22
22
  gem "rb-readline"
23
23
  gem "inspec-core-bin", "~> 4.24" # need to provide the binaries for inspec
24
24
  gem "chef-vault"
25
- gem "ed25519", "~> 1.2" # to make it possible to install knife into chef. Remove this in Chef 18
26
25
  end
27
26
 
28
27
  group(:omnibus_package, :pry) do
29
- gem "pry"
28
+ # Locked because pry-byebug is broken with 13+.
29
+ # some work is ongoing? https://github.com/deivid-rodriguez/pry-byebug/issues/343
30
+ gem "pry", "= 0.13.0"
30
31
  # byebug does not install on freebsd on ruby 3.0
31
- # gem "pry-byebug"
32
+ gem "pry-byebug" unless RUBY_PLATFORM =~ /freebsd/i
32
33
  gem "pry-stack_explorer"
33
34
  end
34
35
 
@@ -47,7 +48,7 @@ end
47
48
 
48
49
  group(:chefstyle) do
49
50
  # for testing new chefstyle rules
50
- gem "chefstyle", git: "https://github.com/chef/chefstyle.git", branch: "master"
51
+ gem "chefstyle", git: "https://github.com/chef/chefstyle.git", branch: "main"
51
52
  end
52
53
 
53
54
  instance_eval(ENV["GEMFILE_MOD"]) if ENV["GEMFILE_MOD"]
data/chef.gemspec CHANGED
@@ -55,6 +55,9 @@ Gem::Specification.new do |s|
55
55
 
56
56
  s.add_dependency "proxifier", "~> 1.0"
57
57
 
58
+ s.add_dependency "aws-sdk-s3", "~> 1.91" # s3 recipe-url support
59
+ s.add_dependency "aws-sdk-secretsmanager", "~> 1.46"
60
+ s.add_dependency "vault", "~> 0.16" # hashi vault official client gem
58
61
  s.bindir = "bin"
59
62
  s.executables = %w{ }
60
63
 
@@ -378,9 +378,19 @@ class Chef::Application::Base < Chef::Application
378
378
 
379
379
  def fetch_recipe_tarball(url, path)
380
380
  require "open-uri" unless defined?(OpenURI)
381
+ uri = URI.parse(url)
382
+
381
383
  Chef::Log.trace("Download recipes tarball from #{url} to #{path}")
382
384
  if File.exist?(url)
383
385
  FileUtils.cp(url, path)
386
+ elsif uri.scheme == "s3"
387
+ require "aws-sdk-s3" unless defined?(Aws::S3)
388
+
389
+ s3 = Aws::S3::Client.new
390
+ object = s3.get_object(bucket: uri.hostname, key: uri.path[1..-1])
391
+ File.open(path, "wb") do |f|
392
+ f.write(object.body.read)
393
+ end
384
394
  elsif URI::DEFAULT_PARSER.make_regexp.match?(url)
385
395
  File.open(path, "wb") do |f|
386
396
  URI.open(url) do |r|
@@ -388,7 +398,7 @@ class Chef::Application::Base < Chef::Application
388
398
  end
389
399
  end
390
400
  else
391
- Chef::Application.fatal! "You specified --recipe-url but the value is neither a valid URL nor a path to a file that exists on disk." +
401
+ Chef::Application.fatal! "You specified --recipe-url but the value is neither a valid URL, an S3 bucket nor a path to a file that exists on disk." +
392
402
  "Please confirm the location of the tarball and try again."
393
403
  end
394
404
  end
@@ -377,7 +377,9 @@ class Chef
377
377
 
378
378
  Chef::FileCache.store("#{ChefUtils::Dist::Infra::SHORT}-stacktrace.out", chef_stacktrace_out)
379
379
  logger.fatal("Stacktrace dumped to #{Chef::FileCache.load("#{ChefUtils::Dist::Infra::SHORT}-stacktrace.out", false)}")
380
- logger.fatal("Please provide the contents of the stacktrace.out file if you file a bug report")
380
+ logger.fatal("---------------------------------------------------------------------------------------")
381
+ logger.fatal("PLEASE PROVIDE THE CONTENTS OF THE stacktrace.out FILE (above) IF YOU FILE A BUG REPORT")
382
+ logger.fatal("---------------------------------------------------------------------------------------")
381
383
  if Chef::Config[:always_dump_stacktrace]
382
384
  logger.fatal(message)
383
385
  else
data/lib/chef/client.rb CHANGED
@@ -241,8 +241,7 @@ class Chef
241
241
 
242
242
  run_status.run_id = request_id = Chef::RequestID.instance.request_id
243
243
 
244
- @run_context = Chef::RunContext.new
245
- run_context.events = events
244
+ @run_context = Chef::RunContext.new(nil, nil, events)
246
245
  run_status.run_context = run_context
247
246
 
248
247
  events.run_start(Chef::VERSION, run_status)
@@ -751,7 +750,7 @@ class Chef
751
750
  end
752
751
 
753
752
  # Notification registration
754
- class<<self
753
+ class << self
755
754
  #
756
755
  # Add a listener for the 'client run started' event.
757
756
  #
@@ -28,7 +28,7 @@ class Chef
28
28
  # Controls what is done with the resulting report after the Chef InSpec run.
29
29
  # Accepts a single string value or an array of multiple values.
30
30
  # Accepted values: 'chef-server-automate', 'chef-automate', 'json-file', 'audit-enforcer', 'cli'
31
- "reporter" => %w{json-file cli},
31
+ "reporter" => "cli",
32
32
 
33
33
  # Controls if Chef InSpec profiles should be fetched from Chef Automate or Chef Infra Server
34
34
  # in addition to the default fetch locations provided by Chef Inspec.
@@ -47,8 +47,10 @@ class Chef
47
47
  "profiles" => {},
48
48
 
49
49
  # Extra inputs passed to Chef InSpec to allow finer-grained control over behavior.
50
- # These are mapped to Chef InSpec's inputs, but are named attributes here for legacy reasons.
51
50
  # See Chef Inspec's documentation for more information: https://docs.chef.io/inspec/inputs/
51
+ "inputs" => {},
52
+
53
+ # Legacy alias for inputs
52
54
  "attributes" => {},
53
55
 
54
56
  # A string path or an array of paths to Chef InSpec waiver files.
@@ -88,7 +90,7 @@ class Chef
88
90
 
89
91
  # If enabled, a hash representation of the Chef Infra node object will be sent to Chef InSpec in an input
90
92
  # named `chef_node`.
91
- "chef_node_attribute_enabled" => false,
93
+ "chef_node_attribute_enabled" => true,
92
94
 
93
95
  # Should the built-in compliance phase run. True and false force the behavior. Nil does magic based on if you have
94
96
  # profiles defined but do not have the audit cookbook enabled.
@@ -0,0 +1,115 @@
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 "yaml"
19
+
20
+ class Chef
21
+ module Compliance
22
+ #
23
+ # Chef object that represents a single input file in the compliance segment
24
+ # of a cookbook.
25
+ #
26
+ class Input
27
+ # @return [Boolean] if the input has been enabled
28
+ attr_reader :enabled
29
+
30
+ # @return [String] The name of the cookbook that the input is in
31
+ attr_reader :cookbook_name
32
+
33
+ # @return [String] The full path on the host to the input yml file
34
+ attr_reader :path
35
+
36
+ # @return [String] the pathname in the cookbook
37
+ attr_reader :pathname
38
+
39
+ # Event dispatcher for this run.
40
+ #
41
+ # @return [Chef::EventDispatch::Dispatcher]
42
+ #
43
+ attr_reader :events
44
+
45
+ # @api private
46
+ attr_reader :data
47
+
48
+ def initialize(events, data, path, cookbook_name)
49
+ @events = events
50
+ @data = data
51
+ @cookbook_name = cookbook_name
52
+ @path = path
53
+ @pathname = File.basename(path, File.extname(path)) unless path.nil?
54
+ disable!
55
+ end
56
+
57
+ # @return [Boolean] if the input has been enabled
58
+ #
59
+ def enabled?
60
+ !!@enabled
61
+ end
62
+
63
+ # Set the input to being enabled
64
+ #
65
+ def enable!
66
+ events.compliance_input_enabled(self)
67
+ @enabled = true
68
+ end
69
+
70
+ # Set the input as being disabled
71
+ #
72
+ def disable!
73
+ @enabled = false
74
+ end
75
+
76
+ # Render the input in a way that it can be consumed by inspec
77
+ #
78
+ def inspec_data
79
+ data
80
+ end
81
+
82
+ HIDDEN_IVARS = [ :@events ].freeze
83
+
84
+ # Omit the event object from error output
85
+ #
86
+ def inspect
87
+ ivar_string = (instance_variables.map(&:to_sym) - HIDDEN_IVARS).map do |ivar|
88
+ "#{ivar}=#{instance_variable_get(ivar).inspect}"
89
+ end.join(", ")
90
+ "#<#{self.class}:#{object_id} #{ivar_string}>"
91
+ end
92
+
93
+ # Helper to construct a input object from a hash. Since the path and
94
+ # cookbook_name are required this is probably not externally useful.
95
+ #
96
+ def self.from_hash(events, hash, path = nil, cookbook_name = nil)
97
+ new(events, hash, path, cookbook_name)
98
+ end
99
+
100
+ # Helper to construct a input object from a yaml string. Since the path
101
+ # and cookbook_name are required this is probably not externally useful.
102
+ #
103
+ def self.from_yaml(events, string, path = nil, cookbook_name = nil)
104
+ from_hash(events, YAML.load(string), path, cookbook_name)
105
+ end
106
+
107
+ # @param filename [String] full path to the yml file in the cookbook
108
+ # @param cookbook_name [String] cookbook that the input is in
109
+ #
110
+ def self.from_file(events, filename, cookbook_name = nil)
111
+ from_yaml(events, IO.read(filename), filename, cookbook_name)
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,139 @@
1
+ # Copyright:: Copyright (c) Chef Software Inc.
2
+ # License:: Apache License, Version 2.0
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ require_relative "input"
18
+
19
+ class Chef
20
+ module Compliance
21
+ class InputCollection < Array
22
+
23
+ # Event dispatcher for this run.
24
+ #
25
+ # @return [Chef::EventDispatch::Dispatcher]
26
+ #
27
+ attr_reader :events
28
+
29
+ def initialize(events)
30
+ @events = events
31
+ end
32
+
33
+ # Add a input to the input collection. The cookbook_name needs to be determined by the
34
+ # caller and is used in the `include_input` API to match on. The path should be the complete
35
+ # path on the host of the yml file, including the filename.
36
+ #
37
+ # @param path [String]
38
+ # @param cookbook_name [String]
39
+ #
40
+ def from_file(filename, cookbook_name)
41
+ new_input = Input.from_file(events, filename, cookbook_name)
42
+ self << new_input
43
+ events.compliance_input_loaded(new_input)
44
+ end
45
+
46
+ # Add a input from a raw hash. This input will be enabled by default.
47
+ #
48
+ # @param path [String]
49
+ # @param cookbook_name [String]
50
+ #
51
+ def from_hash(hash)
52
+ new_input = Input.from_hash(events, hash)
53
+ new_input.enable!
54
+ self << new_input
55
+ end
56
+
57
+ # @return [Array<Input>] inspec inputs which are enabled in a form suitable to pass to inspec
58
+ #
59
+ def inspec_data
60
+ select(&:enabled?).each_with_object({}) { |input, hash| hash.merge(input.inspec_data) }
61
+ end
62
+
63
+ # DSL method to enable input files. This matches on the filename of the input file.
64
+ # If the specific input is omitted then it uses the default input. The string
65
+ # supports regular expression matching.
66
+ #
67
+ # @example Specific input file in a cookbook
68
+ #
69
+ # include_input "acme_cookbook::ssh-001"
70
+ #
71
+ # @example The compliance/inputs/default.yml input in a cookbook
72
+ #
73
+ # include_input "acme_cookbook"
74
+ #
75
+ # @example Every input file in a cookbook
76
+ #
77
+ # include_input "acme_cookbook::.*"
78
+ #
79
+ # @example Matching inputs by regexp in a cookbook
80
+ #
81
+ # include_input "acme_cookbook::ssh.*"
82
+ #
83
+ # @example Matching inputs by regexp in any cookbook in the cookbook collection
84
+ #
85
+ # include_input ".*::ssh.*"
86
+ #
87
+ # @example Adding an arbitrary hash of data (not from any file in a cookbook)
88
+ #
89
+ # include_input({ "ssh_custom_path": "/usr/local/bin" })
90
+ #
91
+ def include_input(arg)
92
+ raise "include_input was given a nil value" if arg.nil?
93
+
94
+ # if we're given a hash argument just shove it in the raw_hash
95
+ if arg.is_a?(Hash)
96
+ from_hash(arg)
97
+ return
98
+ end
99
+
100
+ matching_inputs(arg).each(&:enable!)
101
+ end
102
+
103
+ def valid?(arg)
104
+ !matching_inputs(arg).empty?
105
+ end
106
+
107
+ HIDDEN_IVARS = [ :@events ].freeze
108
+
109
+ # Omit the event object from error output
110
+ #
111
+ def inspect
112
+ ivar_string = (instance_variables.map(&:to_sym) - HIDDEN_IVARS).map do |ivar|
113
+ "#{ivar}=#{instance_variable_get(ivar).inspect}"
114
+ end.join(", ")
115
+ "#<#{self.class}:#{object_id} #{ivar_string}>"
116
+ end
117
+
118
+ private
119
+
120
+ def matching_inputs(arg, should_raise: false)
121
+ (cookbook_name, input_name) = arg.split("::")
122
+
123
+ input_name = "default" if input_name.nil?
124
+
125
+ inputs = select { |input| /^#{cookbook_name}$/.match?(input.cookbook_name) && /^#{input_name}$/.match?(input.pathname) }
126
+
127
+ if inputs.empty? && should_raise
128
+ raise "No inspec inputs matching '#{input_name}' found in cookbooks matching '#{cookbook_name}'"
129
+ end
130
+
131
+ inputs
132
+ end
133
+
134
+ def matching_inputs!(arg)
135
+ matching_inputs(arg, should_raise: true)
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,122 @@
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
+ class Chef
19
+ module Compliance
20
+ class Profile
21
+ # @return [Boolean] if the profile has been enabled
22
+ attr_accessor :enabled
23
+
24
+ # @return [String] The full path on the host to the profile inspec.yml
25
+ attr_reader :path
26
+
27
+ # @return [String] The name of the cookbook that the profile is in
28
+ attr_reader :cookbook_name
29
+
30
+ # @return [String] the pathname in the cookbook
31
+ attr_accessor :pathname
32
+
33
+ # @return [Chef::EventDispatch::Dispatcher] Event dispatcher for this run.
34
+ attr_reader :events
35
+
36
+ # @api private
37
+ attr_reader :data
38
+
39
+ def initialize(events, data, path, cookbook_name)
40
+ @events = events
41
+ @data = data
42
+ @path = path
43
+ @cookbook_name = cookbook_name
44
+ @pathname = File.basename(File.dirname(path))
45
+ disable!
46
+ validate!
47
+ end
48
+
49
+ # @return [String] name of the inspec profile from parsing the inspec.yml
50
+ def name
51
+ @data["name"]
52
+ end
53
+
54
+ # @return [String] version of the inspec profile from parsing the inspec.yml
55
+ def version
56
+ @data["version"]
57
+ end
58
+
59
+ # Raises if the inspec profile is not valid.
60
+ #
61
+ def validate!
62
+ raise "Inspec profile at #{path} has no name" unless name
63
+ end
64
+
65
+ # @return [Boolean] if the profile has been enabled
66
+ def enabled?
67
+ !!@enabled
68
+ end
69
+
70
+ # Set the profile to being enabled
71
+ #
72
+ def enable!
73
+ events.compliance_profile_enabled(self)
74
+ @enabled = true
75
+ end
76
+
77
+ # Set the profile as being disabled
78
+ #
79
+ def disable!
80
+ @enabled = false
81
+ end
82
+
83
+ # Render the profile in a way that it can be consumed by inspec
84
+ #
85
+ def inspec_data
86
+ { name: name, path: File.dirname(path) }
87
+ end
88
+
89
+ HIDDEN_IVARS = [ :@events ].freeze
90
+
91
+ # Omit the event object from error output
92
+ #
93
+ def inspect
94
+ ivar_string = (instance_variables.map(&:to_sym) - HIDDEN_IVARS).map do |ivar|
95
+ "#{ivar}=#{instance_variable_get(ivar).inspect}"
96
+ end.join(", ")
97
+ "#<#{self.class}:#{object_id} #{ivar_string}>"
98
+ end
99
+
100
+ # Helper to construct a profile object from a hash. Since the path and
101
+ # cookbook_name are required this is probably not externally useful.
102
+ #
103
+ def self.from_hash(events, hash, path, cookbook_name)
104
+ new(events, hash, path, cookbook_name)
105
+ end
106
+
107
+ # Helper to construct a profile object from a yaml string. Since the path
108
+ # and cookbook_name are required this is probably not externally useful.
109
+ #
110
+ def self.from_yaml(events, string, path, cookbook_name)
111
+ from_hash(events, YAML.load(string), path, cookbook_name)
112
+ end
113
+
114
+ # @param filename [String] full path to the inspec.yml file in the cookbook
115
+ # @param cookbook_name [String] cookbook that the profile is in
116
+ #
117
+ def self.from_file(events, filename, cookbook_name)
118
+ from_yaml(events, IO.read(filename), filename, cookbook_name)
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,109 @@
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_relative "profile"
19
+
20
+ class Chef
21
+ module Compliance
22
+ class ProfileCollection < Array
23
+
24
+ # Event dispatcher for this run.
25
+ #
26
+ # @return [Chef::EventDispatch::Dispatcher]
27
+ #
28
+ attr_reader :events
29
+
30
+ def initialize(events)
31
+ @events = events
32
+ end
33
+
34
+ # Add a profile to the profile collection. The cookbook_name needs to be determined by the
35
+ # caller and is used in the `include_profile` API to match on. The path should be the complete
36
+ # path on the host of the inspec.yml file, including the filename.
37
+ #
38
+ # @param path [String]
39
+ # @param cookbook_name [String]
40
+ #
41
+ def from_file(path, cookbook_name)
42
+ new_profile = Profile.from_file(events, path, cookbook_name)
43
+ self << new_profile
44
+ events.compliance_profile_loaded(new_profile)
45
+ end
46
+
47
+ # @return [Boolean] if any of the profiles are enabled
48
+ #
49
+ def using_profiles?
50
+ any?(&:enabled?)
51
+ end
52
+
53
+ # @return [Array<Profile>] inspec profiles which are enabled in a form suitable to pass to inspec
54
+ #
55
+ def inspec_data
56
+ select(&:enabled?).each_with_object([]) { |profile, arry| arry << profile.inspec_data }
57
+ end
58
+
59
+ # DSL method to enable profile files. This matches on the name of the profile being included it
60
+ # does not match on the filename of the input file. If the specific profile is omitted then
61
+ # it uses the default profile. The string supports regular expression matching.
62
+ #
63
+ # @example Specific profile in a cookbook
64
+ #
65
+ # include_profile "acme_cookbook::ssh-001"
66
+ #
67
+ # @example The profile named "default" in a cookbook
68
+ #
69
+ # include_profile "acme_cookbook"
70
+ #
71
+ # @example Every profile in a cookbook
72
+ #
73
+ # include_profile "acme_cookbook::.*"
74
+ #
75
+ # @example Matching profiles by regexp in a cookbook
76
+ #
77
+ # include_profile "acme_cookbook::ssh.*"
78
+ #
79
+ # @example Matching profiles by regexp in any cookbook in the cookbook collection
80
+ #
81
+ # include_profile ".*::ssh.*"
82
+ #
83
+ def include_profile(arg)
84
+ (cookbook_name, profile_name) = arg.split("::")
85
+
86
+ profile_name = "default" if profile_name.nil?
87
+
88
+ profiles = select { |profile| /^#{cookbook_name}$/.match?(profile.cookbook_name) && /^#{profile_name}$/.match?(profile.pathname) }
89
+
90
+ if profiles.empty?
91
+ raise "No inspec profiles matching '#{profile_name}' found in cookbooks matching '#{cookbook_name}'"
92
+ end
93
+
94
+ profiles.each(&:enable!)
95
+ end
96
+
97
+ HIDDEN_IVARS = [ :@events ].freeze
98
+
99
+ # Omit the event object from error output
100
+ #
101
+ def inspect
102
+ ivar_string = (instance_variables.map(&:to_sym) - HIDDEN_IVARS).map do |ivar|
103
+ "#{ivar}=#{instance_variable_get(ivar).inspect}"
104
+ end.join(", ")
105
+ "#<#{self.class}:#{object_id} #{ivar_string}>"
106
+ end
107
+ end
108
+ end
109
+ end
@@ -76,7 +76,7 @@ class Chef
76
76
 
77
77
  begin
78
78
  Chef::Log.info "Report to #{ChefUtils::Dist::Automate::PRODUCT}: #{@url}"
79
- Chef::Log.debug "Compliance Report: #{json_report}"
79
+ Chef::Log.debug "Compliance Phase report: #{json_report}"
80
80
  http_client.post(nil, json_report, headers)
81
81
  true
82
82
  rescue => e