inspec 0.9.11 → 0.10.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (178) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -0
  3. data/CHANGELOG.md +45 -2
  4. data/bin/inspec +53 -86
  5. data/examples/kitchen-ansible/.kitchen/default-ubuntu-1404.yml +2 -2
  6. data/examples/kitchen-ansible/.kitchen/kitchen-vagrant/kitchen-kitchen-ansible-default-ubuntu-1404/.vagrant/machines/default/virtualbox/action_set_name +1 -1
  7. data/examples/kitchen-ansible/.kitchen/kitchen-vagrant/kitchen-kitchen-ansible-default-ubuntu-1404/.vagrant/machines/default/virtualbox/id +1 -1
  8. data/examples/kitchen-ansible/.kitchen/kitchen-vagrant/kitchen-kitchen-ansible-default-ubuntu-1404/.vagrant/machines/default/virtualbox/index_uuid +1 -1
  9. data/examples/kitchen-ansible/.kitchen/kitchen-vagrant/kitchen-kitchen-ansible-default-ubuntu-1404/.vagrant/machines/default/virtualbox/private_key +25 -25
  10. data/examples/kitchen-ansible/.kitchen/logs/default-centos-71.log +0 -4
  11. data/examples/kitchen-ansible/.kitchen/logs/default-ubuntu-1204.log +0 -4
  12. data/examples/kitchen-ansible/.kitchen/logs/default-ubuntu-1404.log +395 -4
  13. data/examples/kitchen-ansible/.kitchen/logs/kitchen.log +3 -8
  14. data/examples/kitchen-ansible/Gemfile.lock +29 -25
  15. data/examples/kitchen-ansible/test/.DS_Store +0 -0
  16. data/examples/kitchen-ansible/test/integration/.DS_Store +0 -0
  17. data/examples/kitchen-azure/.kitchen.yml +30 -0
  18. data/examples/kitchen-azure/.kitchen/default-debian-80-20151022-x86-64.yml +1 -0
  19. data/examples/kitchen-azure/.kitchen/default-ubuntu-1204.yml +9 -0
  20. data/examples/kitchen-azure/.kitchen/logs/default-debian-80-20151022-x86-64.log +59 -0
  21. data/examples/kitchen-azure/.kitchen/logs/default-ubuntu-1204.log +27 -0
  22. data/{lib/resources/certificate.rb → examples/kitchen-azure/.kitchen/logs/default-windows2012-r2.log} +0 -0
  23. data/examples/kitchen-azure/.kitchen/logs/kitchen.log +29 -0
  24. data/examples/kitchen-azure/Berksfile +3 -0
  25. data/examples/kitchen-azure/Gemfile +20 -0
  26. data/examples/kitchen-azure/Gemfile.lock +273 -0
  27. data/examples/kitchen-azure/README.md +14 -0
  28. data/{lib/resources/private_key.rb → examples/kitchen-azure/credentials.sh} +0 -0
  29. data/examples/kitchen-azure/metadata.rb +7 -0
  30. data/examples/kitchen-azure/recipes/default.rb +6 -0
  31. data/examples/kitchen-azure/recipes/nginx.rb +30 -0
  32. data/examples/kitchen-azure/test/integration/default/web_spec.rb +28 -0
  33. data/examples/kitchen-chef/.kitchen/default-ubuntu-1404.yml +1 -1
  34. data/examples/kitchen-chef/.kitchen/kitchen-vagrant/kitchen-kitchen-chef-default-ubuntu-1404/.vagrant/machines/default/virtualbox/action_set_name +1 -1
  35. data/examples/kitchen-chef/.kitchen/kitchen-vagrant/kitchen-kitchen-chef-default-ubuntu-1404/.vagrant/machines/default/virtualbox/id +1 -1
  36. data/examples/kitchen-chef/.kitchen/kitchen-vagrant/kitchen-kitchen-chef-default-ubuntu-1404/.vagrant/machines/default/virtualbox/index_uuid +1 -1
  37. data/examples/kitchen-chef/.kitchen/kitchen-vagrant/kitchen-kitchen-chef-default-ubuntu-1404/.vagrant/machines/default/virtualbox/private_key +25 -25
  38. data/examples/kitchen-chef/.kitchen/logs/default-centos-71.log +0 -4
  39. data/examples/kitchen-chef/.kitchen/logs/default-ubuntu-1204.log +0 -4
  40. data/examples/kitchen-chef/.kitchen/logs/default-ubuntu-1404.log +3 -4
  41. data/examples/kitchen-chef/.kitchen/logs/kitchen.log +3 -8
  42. data/examples/kitchen-chef/Gemfile.lock +27 -24
  43. data/examples/kitchen-chef/test/integration/.DS_Store +0 -0
  44. data/examples/{kitchen-chef/.kitchen/default-ubuntu-1204.yml → kitchen-puppet/.kitchen/default-ubuntu-1404.yml} +1 -1
  45. data/examples/kitchen-puppet/.kitchen/kitchen-vagrant/kitchen-kitchen-puppet-default-ubuntu-1404/.vagrant/machines/default/virtualbox/action_set_name +1 -0
  46. data/examples/{kitchen-ansible/.kitchen/kitchen-vagrant/kitchen-kitchen-ansible-default-centos-71 → kitchen-puppet/.kitchen/kitchen-vagrant/kitchen-kitchen-puppet-default-ubuntu-1404}/.vagrant/machines/default/virtualbox/creator_uid +0 -0
  47. data/examples/kitchen-puppet/.kitchen/kitchen-vagrant/kitchen-kitchen-puppet-default-ubuntu-1404/.vagrant/machines/default/virtualbox/id +1 -0
  48. data/examples/kitchen-puppet/.kitchen/kitchen-vagrant/kitchen-kitchen-puppet-default-ubuntu-1404/.vagrant/machines/default/virtualbox/index_uuid +1 -0
  49. data/examples/kitchen-puppet/.kitchen/kitchen-vagrant/kitchen-kitchen-puppet-default-ubuntu-1404/.vagrant/machines/default/virtualbox/private_key +27 -0
  50. data/examples/{kitchen-ansible/.kitchen/kitchen-vagrant/kitchen-kitchen-ansible-default-centos-71 → kitchen-puppet/.kitchen/kitchen-vagrant/kitchen-kitchen-puppet-default-ubuntu-1404}/.vagrant/machines/default/virtualbox/synced_folders +0 -0
  51. data/examples/{kitchen-ansible/.kitchen/kitchen-vagrant/kitchen-kitchen-ansible-default-centos-71 → kitchen-puppet/.kitchen/kitchen-vagrant/kitchen-kitchen-puppet-default-ubuntu-1404}/Vagrantfile +3 -3
  52. data/examples/kitchen-puppet/.kitchen/logs/default-centos-71.log +0 -5
  53. data/examples/kitchen-puppet/.kitchen/logs/default-ubuntu-1204.log +0 -5
  54. data/examples/kitchen-puppet/.kitchen/logs/default-ubuntu-1404.log +305 -5
  55. data/examples/kitchen-puppet/.kitchen/logs/kitchen.log +6 -5
  56. data/examples/kitchen-puppet/.librarian/puppet/config +1 -1
  57. data/examples/kitchen-puppet/Gemfile.lock +22 -21
  58. data/examples/kitchen-puppet/test/integration/.DS_Store +0 -0
  59. data/examples/kitchen-puppet/test/integration/default/.DS_Store +0 -0
  60. data/examples/profile/controls/example.rb +7 -1
  61. data/lib/bundles/README.md +3 -0
  62. data/lib/bundles/inspec-compliance.rb +14 -0
  63. data/lib/bundles/inspec-compliance/README.md +20 -0
  64. data/lib/bundles/inspec-compliance/TODO.md +4 -0
  65. data/lib/bundles/inspec-compliance/api.rb +134 -0
  66. data/lib/bundles/inspec-compliance/cli.rb +146 -0
  67. data/lib/bundles/inspec-compliance/configuration.rb +52 -0
  68. data/lib/bundles/inspec-compliance/target.rb +61 -0
  69. data/lib/bundles/inspec-supermarket.rb +14 -0
  70. data/lib/bundles/inspec-supermarket/README.md +31 -0
  71. data/lib/bundles/inspec-supermarket/TODO.md +5 -0
  72. data/lib/bundles/inspec-supermarket/api.rb +58 -0
  73. data/lib/bundles/inspec-supermarket/cache.rb +30 -0
  74. data/lib/bundles/inspec-supermarket/cli.rb +54 -0
  75. data/lib/bundles/inspec-supermarket/target.rb +49 -0
  76. data/lib/inspec.rb +9 -2
  77. data/lib/inspec/metadata.rb +21 -7
  78. data/lib/inspec/plugins.rb +41 -0
  79. data/lib/inspec/plugins/cli.rb +24 -0
  80. data/lib/inspec/profile.rb +90 -61
  81. data/lib/inspec/rule.rb +9 -0
  82. data/lib/inspec/runner.rb +7 -3
  83. data/lib/inspec/runner_rspec.rb +19 -0
  84. data/lib/inspec/targets/archive.rb +14 -10
  85. data/lib/inspec/targets/tar.rb +3 -2
  86. data/lib/inspec/targets/url.rb +5 -4
  87. data/lib/inspec/targets/zip.rb +3 -2
  88. data/lib/inspec/version.rb +1 -1
  89. data/lib/resources/file.rb +7 -21
  90. data/lib/resources/os.rb +1 -1
  91. data/lib/resources/service.rb +15 -3
  92. data/lib/utils/base_cli.rb +131 -0
  93. data/lib/utils/find_files.rb +1 -1
  94. data/lib/utils/json_log.rb +17 -0
  95. data/test/helper.rb +39 -25
  96. data/test/integration/.kitchen.chef.yml +1 -1
  97. data/test/integration/.kitchen.ec2.yml +2 -0
  98. data/test/integration/.kitchen/default-aws-linux.yml +4 -0
  99. data/test/integration/.kitchen/default-centos-7.yml +4 -0
  100. data/test/integration/.kitchen/default-chef-solaris-113.yml +6 -0
  101. data/test/integration/.kitchen/default-chef-windows-server-2008r2-standard.yml +1 -1
  102. data/test/integration/.kitchen/default-debian-8.yml +4 -0
  103. data/test/integration/.kitchen/default-fedora-22.yml +4 -0
  104. data/test/integration/.kitchen/default-redhat-65.yml +4 -0
  105. data/test/integration/.kitchen/default-redhat-71.yml +4 -0
  106. data/test/integration/.kitchen/default-suse-11sp3.yml +4 -0
  107. data/test/integration/.kitchen/default-suse-12.yml +4 -0
  108. data/test/integration/.kitchen/default-suse-hi11sp3.yml +4 -0
  109. data/test/integration/.kitchen/default-ubuntu-1204.yml +4 -0
  110. data/test/integration/.kitchen/default-ubuntu-1404.yml +4 -0
  111. data/test/integration/.kitchen/default-ubuntu-1510.yml +4 -0
  112. data/test/integration/.kitchen/default-windows-2012r2.yml +6 -0
  113. data/test/integration/.kitchen/kitchen-vagrant/kitchen-integration-default-chef-solaris-113/.vagrant/machines/default/virtualbox/action_set_name +1 -0
  114. data/{examples/kitchen-ansible/.kitchen/kitchen-vagrant/kitchen-kitchen-ansible-default-ubuntu-1204 → test/integration/.kitchen/kitchen-vagrant/kitchen-integration-default-chef-solaris-113}/.vagrant/machines/default/virtualbox/creator_uid +0 -0
  115. data/test/integration/.kitchen/kitchen-vagrant/kitchen-integration-default-chef-solaris-113/.vagrant/machines/default/virtualbox/id +1 -0
  116. data/test/integration/.kitchen/kitchen-vagrant/kitchen-integration-default-chef-solaris-113/.vagrant/machines/default/virtualbox/index_uuid +1 -0
  117. data/test/integration/.kitchen/kitchen-vagrant/kitchen-integration-default-chef-solaris-113/.vagrant/machines/default/virtualbox/private_key +27 -0
  118. data/{examples/kitchen-ansible/.kitchen/kitchen-vagrant/kitchen-kitchen-ansible-default-ubuntu-1204 → test/integration/.kitchen/kitchen-vagrant/kitchen-integration-default-chef-solaris-113}/.vagrant/machines/default/virtualbox/synced_folders +0 -0
  119. data/test/integration/.kitchen/kitchen-vagrant/{kitchen-integration-default-chef-windows-server-2012r2-standard → kitchen-integration-default-chef-solaris-113}/Vagrantfile +2 -2
  120. data/test/integration/.kitchen/logs/default-aws-linux.log +0 -3
  121. data/test/integration/.kitchen/logs/default-centos-7.log +0 -3
  122. data/test/integration/.kitchen/logs/default-chef-solaris-113.log +0 -0
  123. data/test/integration/.kitchen/logs/default-chef-windows-server-2008r2-standard.log +43 -0
  124. data/test/integration/.kitchen/logs/default-chris-rock-omnios-r151014.log +41 -23
  125. data/test/integration/.kitchen/logs/default-debian-8.log +0 -3
  126. data/test/integration/.kitchen/logs/default-fedora-22.log +0 -3
  127. data/test/integration/.kitchen/logs/default-redhat-65.log +0 -3
  128. data/test/integration/.kitchen/logs/default-redhat-71.log +0 -3
  129. data/test/integration/.kitchen/logs/default-suse-11sp3.log +0 -3
  130. data/test/integration/.kitchen/logs/default-suse-12.log +0 -3
  131. data/test/integration/.kitchen/logs/default-suse-hi11sp3.log +37 -0
  132. data/test/integration/.kitchen/logs/default-ubuntu-1204.log +23 -3
  133. data/test/integration/.kitchen/logs/default-ubuntu-1404.log +0 -3
  134. data/test/integration/.kitchen/logs/default-ubuntu-1510.log +0 -3
  135. data/test/integration/.kitchen/logs/default-windows-2012r2.log +0 -2
  136. data/test/integration/.kitchen/logs/kitchen.log +3 -14
  137. data/test/integration/cookbooks/os_prepare/recipes/_upstart_service_centos.rb +21 -0
  138. data/test/integration/cookbooks/os_prepare/recipes/apache.rb +14 -0
  139. data/test/integration/cookbooks/os_prepare/recipes/service.rb +1 -0
  140. data/test/integration/test/integration/default/service_spec.rb +24 -0
  141. data/test/solaris_test.rb +70 -0
  142. data/test/unit/mock/cmd/initctl--version +5 -0
  143. data/test/unit/plugin_test.rb +46 -0
  144. data/test/unit/profile_test.rb +136 -21
  145. data/test/unit/resources/file_test.rb +13 -25
  146. metadata +105 -51
  147. data/examples/kitchen-ansible/.kitchen/default-centos-71.yml +0 -6
  148. data/examples/kitchen-ansible/.kitchen/default-ubuntu-1204.yml +0 -6
  149. data/examples/kitchen-ansible/.kitchen/kitchen-vagrant/kitchen-kitchen-ansible-default-centos-71/.vagrant/machines/default/virtualbox/action_set_name +0 -1
  150. data/examples/kitchen-ansible/.kitchen/kitchen-vagrant/kitchen-kitchen-ansible-default-centos-71/.vagrant/machines/default/virtualbox/id +0 -1
  151. data/examples/kitchen-ansible/.kitchen/kitchen-vagrant/kitchen-kitchen-ansible-default-centos-71/.vagrant/machines/default/virtualbox/index_uuid +0 -1
  152. data/examples/kitchen-ansible/.kitchen/kitchen-vagrant/kitchen-kitchen-ansible-default-centos-71/.vagrant/machines/default/virtualbox/private_key +0 -27
  153. data/examples/kitchen-ansible/.kitchen/kitchen-vagrant/kitchen-kitchen-ansible-default-ubuntu-1204/.vagrant/machines/default/virtualbox/action_set_name +0 -1
  154. data/examples/kitchen-ansible/.kitchen/kitchen-vagrant/kitchen-kitchen-ansible-default-ubuntu-1204/.vagrant/machines/default/virtualbox/id +0 -1
  155. data/examples/kitchen-ansible/.kitchen/kitchen-vagrant/kitchen-kitchen-ansible-default-ubuntu-1204/.vagrant/machines/default/virtualbox/index_uuid +0 -1
  156. data/examples/kitchen-ansible/.kitchen/kitchen-vagrant/kitchen-kitchen-ansible-default-ubuntu-1204/.vagrant/machines/default/virtualbox/private_key +0 -27
  157. data/examples/kitchen-ansible/.kitchen/kitchen-vagrant/kitchen-kitchen-ansible-default-ubuntu-1204/Vagrantfile +0 -9
  158. data/examples/kitchen-chef/.kitchen/default-centos-71.yml +0 -6
  159. data/examples/kitchen-chef/.kitchen/kitchen-vagrant/kitchen-kitchen-chef-default-centos-71/.vagrant/machines/default/virtualbox/action_set_name +0 -1
  160. data/examples/kitchen-chef/.kitchen/kitchen-vagrant/kitchen-kitchen-chef-default-centos-71/.vagrant/machines/default/virtualbox/creator_uid +0 -1
  161. data/examples/kitchen-chef/.kitchen/kitchen-vagrant/kitchen-kitchen-chef-default-centos-71/.vagrant/machines/default/virtualbox/id +0 -1
  162. data/examples/kitchen-chef/.kitchen/kitchen-vagrant/kitchen-kitchen-chef-default-centos-71/.vagrant/machines/default/virtualbox/index_uuid +0 -1
  163. data/examples/kitchen-chef/.kitchen/kitchen-vagrant/kitchen-kitchen-chef-default-centos-71/.vagrant/machines/default/virtualbox/private_key +0 -27
  164. data/examples/kitchen-chef/.kitchen/kitchen-vagrant/kitchen-kitchen-chef-default-centos-71/.vagrant/machines/default/virtualbox/synced_folders +0 -1
  165. data/examples/kitchen-chef/.kitchen/kitchen-vagrant/kitchen-kitchen-chef-default-centos-71/Vagrantfile +0 -9
  166. data/examples/kitchen-chef/.kitchen/kitchen-vagrant/kitchen-kitchen-chef-default-ubuntu-1204/.vagrant/machines/default/virtualbox/action_set_name +0 -1
  167. data/examples/kitchen-chef/.kitchen/kitchen-vagrant/kitchen-kitchen-chef-default-ubuntu-1204/.vagrant/machines/default/virtualbox/creator_uid +0 -1
  168. data/examples/kitchen-chef/.kitchen/kitchen-vagrant/kitchen-kitchen-chef-default-ubuntu-1204/.vagrant/machines/default/virtualbox/id +0 -1
  169. data/examples/kitchen-chef/.kitchen/kitchen-vagrant/kitchen-kitchen-chef-default-ubuntu-1204/.vagrant/machines/default/virtualbox/index_uuid +0 -1
  170. data/examples/kitchen-chef/.kitchen/kitchen-vagrant/kitchen-kitchen-chef-default-ubuntu-1204/.vagrant/machines/default/virtualbox/private_key +0 -27
  171. data/examples/kitchen-chef/.kitchen/kitchen-vagrant/kitchen-kitchen-chef-default-ubuntu-1204/.vagrant/machines/default/virtualbox/synced_folders +0 -1
  172. data/examples/kitchen-chef/.kitchen/kitchen-vagrant/kitchen-kitchen-chef-default-ubuntu-1204/Vagrantfile +0 -9
  173. data/test/integration/.kitchen/default-chef-windows-server-2012r2-standard.yml +0 -7
  174. data/test/integration/.kitchen/kitchen-vagrant/kitchen-integration-default-chef-windows-server-2012r2-standard/.vagrant/machines/default/virtualbox/action_set_name +0 -1
  175. data/test/integration/.kitchen/kitchen-vagrant/kitchen-integration-default-chef-windows-server-2012r2-standard/.vagrant/machines/default/virtualbox/creator_uid +0 -1
  176. data/test/integration/.kitchen/kitchen-vagrant/kitchen-integration-default-chef-windows-server-2012r2-standard/.vagrant/machines/default/virtualbox/id +0 -1
  177. data/test/integration/.kitchen/kitchen-vagrant/kitchen-integration-default-chef-windows-server-2012r2-standard/.vagrant/machines/default/virtualbox/index_uuid +0 -1
  178. data/test/integration/.kitchen/kitchen-vagrant/kitchen-integration-default-chef-windows-server-2012r2-standard/.vagrant/machines/default/virtualbox/synced_folders +0 -1
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+ # author: Christoph Hartmann
3
+ # author: Dominik Richter
4
+
5
+ module Inspec
6
+ module Plugins
7
+ # stores all CLI plugin, we expect those to the `Thor` subclasses
8
+ class CLI
9
+ def self.registry
10
+ @registry ||= {}
11
+ end
12
+
13
+ def self.register(klass, subcommand_name, usage, description, options = {})
14
+ registry[subcommand_name] = {
15
+ klass: klass,
16
+ subcommand_name: subcommand_name,
17
+ usage: usage,
18
+ description: description,
19
+ options: options,
20
+ }
21
+ end
22
+ end
23
+ end
24
+ end
@@ -19,29 +19,33 @@ module Inspec
19
19
  attr_reader :path
20
20
  attr_reader :metadata
21
21
 
22
+ # rubocop:disable Metrics/AbcSize
22
23
  def initialize(options = nil)
23
24
  @options = options || {}
24
-
25
- @params = {}
26
25
  @logger = options[:logger] || Logger.new(nil)
27
-
28
26
  @path = @options[:path]
29
- fail 'Cannot read an empty path.' if @path.nil? || @path.empty?
30
- fail "Cannot find directory #{@path}" unless File.directory?(@path)
31
-
32
- @metadata = read_metadata
33
- @params = @metadata.params
34
- # use the id from parameter, name or fallback to nil
35
- @profile_id = options[:id] || params[:name] || nil
36
- @params[:name] = @profile_id
27
+ @profile_id = options[:id]
37
28
 
38
- @params[:rules] = rules = {}
39
29
  @runner = Runner.new(
40
30
  id: @profile_id,
41
31
  backend: :mock,
42
32
  test_collector: @options.delete(:test_collector),
43
33
  )
44
- @runner.add_tests([@path], @options)
34
+
35
+ # we're checking a profile, we don't care if it runs on the host machine
36
+ @options[:ignore_supports] = true
37
+ tests, libs, metadata = @runner.add_tests([@path], @options)
38
+ @content = tests + libs + metadata
39
+
40
+ # NB if you want to check more than one profile, use one
41
+ # Inspec::Profile#from_file per profile
42
+ @metadata_source = metadata.first
43
+ @metadata = Metadata.from_ref(@metadata_source[:ref], @metadata_source[:content], @profile_id, @logger)
44
+ @params = @metadata.params
45
+ @profile_id ||= params[:name]
46
+ @params[:name] = @profile_id
47
+ @params[:rules] = rules = {}
48
+
45
49
  @runner.rules.each do |id, rule|
46
50
  file = rule.instance_variable_get(:@__file)
47
51
  rules[file] ||= {}
@@ -51,6 +55,7 @@ module Inspec
51
55
  impact: rule.impact,
52
56
  checks: rule.instance_variable_get(:@checks),
53
57
  code: rule.instance_variable_get(:@__code),
58
+ source_location: rule.instance_variable_get(:@__source_location),
54
59
  group_title: rule.instance_variable_get(:@__group_title),
55
60
  }
56
61
  end
@@ -84,55 +89,91 @@ module Inspec
84
89
  # used to print information on errors and warnings which are found.
85
90
  #
86
91
  # @return [Boolean] true if no errors were found, false otherwise
87
- def check # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
88
- no_errors = true
89
- no_warnings = true
90
- warn = lambda { |msg|
92
+ def check # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength
93
+ # initial values for response object
94
+ result = {
95
+ summary: {
96
+ valid: false,
97
+ timestamp: Time.now.iso8601,
98
+ location: @path,
99
+ profile: nil,
100
+ controls: 0,
101
+ },
102
+ errors: [],
103
+ warnings: [],
104
+ }
105
+
106
+ entry = lambda { |file, line, column, control, msg|
107
+ {
108
+ file: file,
109
+ line: line,
110
+ column: column,
111
+ control_id: control,
112
+ msg: msg,
113
+ }
114
+ }
115
+
116
+ warn = lambda { |file, line, column, control, msg|
91
117
  @logger.warn(msg)
92
- no_warnings = false
118
+ result[:warnings].push(entry.call(file, line, column, control, msg))
93
119
  }
94
- error = lambda { |msg|
120
+
121
+ error = lambda { |file, line, column, control, msg|
95
122
  @logger.error(msg)
96
- no_warnings = no_errors = false
123
+ result[:errors].push(entry.call(file, line, column, control, msg))
97
124
  }
98
125
 
99
126
  @logger.info "Checking profile in #{@path}"
100
127
 
101
- if Pathname.new(path).join('metadata.rb').exist?
102
- warn.call('The use of `metadata.rb` is deprecated. Use `inspec.yml`.')
128
+ if @content.any? { |h| h[:type] == :metadata && h[:ref] =~ /metadata\.rb$/ }
129
+ warn.call(Pathname.new(path).join('metadata.rb'), 0, 0, nil, 'The use of `metadata.rb` is deprecated. Use `inspec.yml`.')
103
130
  end
104
131
 
105
- @logger.info 'Metadata OK.' if @metadata.valid?
132
+ # verify metadata
133
+ m_errors, m_warnings = @metadata.valid
134
+ m_errors.each { |msg| error.call(@metadata_source[:ref], 0, 0, nil, msg) }
135
+ m_warnings.each { |msg| warn.call(@metadata_source[:ref], 0, 0, nil, msg) }
136
+ m_unsupported = @metadata.unsupported
137
+ m_unsupported.each { |u| warn.call(@metadata_source[:ref], 0, 0, nil, "doesn't support: #{u}") }
138
+ @logger.info 'Metadata OK.' if m_errors.empty? && m_unsupported.empty?
139
+
140
+ # extract profile name
141
+ result[:summary][:profile] = @metadata.params[:name]
106
142
 
107
143
  # check if the profile is using the old test directory instead of the
108
144
  # new controls directory
109
- if Pathname.new(path).join('test').exist? && !Pathname.new(path).join('controls').exist?
110
- warn.call('Profile uses deprecated `test` directory, rename it to `controls`.')
145
+ if @content.any? { |h| h[:type] == :test && h[:ref] =~ %r{test/[^/]+$} }
146
+ warn.call(Pathname.new(path).join('test'), 0, 0, nil, 'Profile uses deprecated `test` directory, rename it to `controls`.')
111
147
  end
112
148
 
113
149
  count = rules_count
150
+ result[:summary][:controls] = count
114
151
  if count == 0
115
- warn.call('No controls or tests were defined.')
152
+ warn.call(nil, nil, nil, nil, 'No controls or tests were defined.')
116
153
  else
117
- @logger.info("Found #{count} rules.")
154
+ @logger.info("Found #{count} controls.")
118
155
  end
119
156
 
120
157
  # iterate over hash of groups
121
- @params[:rules].each do |group, rules_array|
122
- @logger.debug "Verify all rules in #{group}"
123
- rules_array.each do |id, rule|
124
- error.call('Avoid rules with empty IDs') if id.nil? or id.empty?
158
+ @params[:rules].each { |group, controls|
159
+ @logger.info "Verify all controls in #{group}"
160
+ controls.each { |id, control|
161
+ sfile, sline = control[:source_location]
162
+ error.call(sfile, sline, nil, id, 'Avoid controls with empty IDs') if id.nil? or id.empty?
125
163
  next if id.start_with? '(generated '
126
- warn.call("Rule #{id} has no title") if rule[:title].to_s.empty?
127
- warn.call("Rule #{id} has no description") if rule[:desc].to_s.empty?
128
- warn.call("Rule #{id} has impact > 1.0") if rule[:impact].to_f > 1.0
129
- warn.call("Rule #{id} has impact < 0.0") if rule[:impact].to_f < 0.0
130
- warn.call("Rule #{id} has no tests defined") if rule[:checks].nil? or rule[:checks].empty?
131
- end
132
- end
164
+ warn.call(sfile, sline, nil, id, "Control #{id} has no title") if control[:title].to_s.empty?
165
+ warn.call(sfile, sline, nil, id, "Control #{id} has no description") if control[:desc].to_s.empty?
166
+ warn.call(sfile, sline, nil, id, "Control #{id} has impact > 1.0") if control[:impact].to_f > 1.0
167
+ warn.call(sfile, sline, nil, id, "Control #{id} has impact < 0.0") if control[:impact].to_f < 0.0
168
+ warn.call(sfile, sline, nil, id, "Control #{id} has no tests defined") if control[:checks].nil? or control[:checks].empty?
169
+ }
170
+ }
133
171
 
134
- @logger.info 'Rule definitions OK.' if no_warnings
135
- no_errors
172
+ # profile is valid if we could not find any error
173
+ result[:summary][:valid] = result[:errors].empty?
174
+
175
+ @logger.info 'Control definitions OK.' if result[:warnings].empty?
176
+ result
136
177
  end
137
178
 
138
179
  def rules_count
@@ -140,19 +181,18 @@ module Inspec
140
181
  end
141
182
 
142
183
  # generates a archive of a folder profile
184
+ # assumes that the profile was checked before
143
185
  def archive(opts) # rubocop:disable Metrics/AbcSize
144
- check_result = check
145
-
146
- if check_result && !opts.ignore_errors == false
147
- @logger.info 'Profile check failed. Please fix the profile before generating an archive.'
148
- return false
149
- end
150
-
151
186
  profile_name = @params[:name]
152
187
 
153
188
  ext = opts[:zip] ? 'zip' : 'tar.gz'
154
- slug = profile_name.downcase.strip.tr(' ', '-').gsub(/[^\w-]/, '_')
155
- archive = Pathname.new(File.dirname(__FILE__)).join('../..', "#{slug}.#{ext}")
189
+
190
+ if opts[:archive]
191
+ archive = Pathname.new(opts[:archive])
192
+ else
193
+ slug = profile_name.downcase.strip.tr(' ', '-').gsub(/[^\w-]/, '_')
194
+ archive = Pathname.new(File.dirname(__FILE__)).join('../..', "#{slug}.#{ext}")
195
+ end
156
196
 
157
197
  # check if file exists otherwise overwrite the archive
158
198
  if archive.exist? && !opts[:overwrite]
@@ -163,7 +203,7 @@ module Inspec
163
203
  # remove existing archive
164
204
  File.delete(archive) if archive.exist?
165
205
 
166
- @logger.info "Profile check finished. Generate archive #{archive}."
206
+ @logger.info "Generate archive #{archive}."
167
207
 
168
208
  # find all files
169
209
  files = Dir.glob("#{path}/**/*")
@@ -195,16 +235,5 @@ module Inspec
195
235
  @logger.info 'Finished archive generation.'
196
236
  true
197
237
  end
198
-
199
- private
200
-
201
- def read_metadata
202
- mpath = Pathname.new(path).join('inspec.yml')
203
-
204
- # fallback to metadata.rb if inspec.yml does not exist
205
- # TODO deprecated, will be removed in InSpec 1.0
206
- mpath = File.join(@path, 'metadata.rb') if !mpath.exist?
207
- Metadata.from_file(mpath, @profile_id, @logger)
208
- end
209
238
  end
210
239
  end
@@ -53,6 +53,7 @@ module Inspec
53
53
  @impact = nil
54
54
  @__block = block
55
55
  @__code = __get_block_source(&block)
56
+ @__source_location = __get_block_source_location(&block)
56
57
  @title = nil
57
58
  @desc = nil
58
59
  # not changeable by the user:
@@ -166,5 +167,13 @@ module Inspec
166
167
  rescue MethodSource::SourceNotFoundError
167
168
  ''
168
169
  end
170
+
171
+ # get the source location of the block
172
+ def __get_block_source_location(&block)
173
+ return [nil, nil] unless block_given?
174
+ block.source_location
175
+ rescue MethodSource::SourceNotFoundError
176
+ [nil, nil]
177
+ end
169
178
  end
170
179
  end
@@ -4,6 +4,7 @@
4
4
  # author: Dominik Richter
5
5
  # author: Christoph Hartmann
6
6
 
7
+ require 'forwardable'
7
8
  require 'uri'
8
9
  require 'inspec/backend'
9
10
  require 'inspec/profile_context'
@@ -13,6 +14,7 @@ require 'inspec/metadata'
13
14
 
14
15
  module Inspec
15
16
  class Runner # rubocop:disable Metrics/ClassLength
17
+ extend Forwardable
16
18
  attr_reader :backend, :rules
17
19
  def initialize(conf = {})
18
20
  @rules = {}
@@ -64,6 +66,7 @@ module Inspec
64
66
 
65
67
  tests = items.find_all { |i| i[:type] == :test }
66
68
  libs = items.find_all { |i| i[:type] == :library }
69
+ meta = items.find_all { |i| i[:type] == :metadata }
67
70
 
68
71
  # Ensure each test directory exists on the $LOAD_PATH. This
69
72
  # will ensure traditional RSpec-isms like `require 'spec_helper'`
@@ -80,6 +83,8 @@ module Inspec
80
83
  tests.flatten.each do |test|
81
84
  add_content(test, libs)
82
85
  end
86
+
87
+ [tests, libs, meta]
83
88
  end
84
89
 
85
90
  def create_context
@@ -106,9 +111,8 @@ module Inspec
106
111
  end
107
112
  end
108
113
 
109
- def run(with = nil)
110
- @test_collector.run(with)
111
- end
114
+ def_delegator :@test_collector, :run
115
+ def_delegator :@test_collector, :report
112
116
 
113
117
  private
114
118
 
@@ -55,6 +55,11 @@ module Inspec
55
55
  with.run_specs(tests)
56
56
  end
57
57
 
58
+ def report
59
+ reporter = RSpec.configuration.formatters.find { |f| f.is_a? Inspec::RSpecReporter }
60
+ reporter.output_hash
61
+ end
62
+
58
63
  private
59
64
 
60
65
  # Empty the list of registered tests.
@@ -71,6 +76,12 @@ module Inspec
71
76
  # @return [nil]
72
77
  def configure_output
73
78
  RSpec.configuration.add_formatter(@conf['format'] || 'progress')
79
+
80
+ setup_reporting if @conf['report']
81
+ end
82
+
83
+ def setup_reporting
84
+ RSpec.configuration.add_formatter(Inspec::RSpecReporter)
74
85
  end
75
86
 
76
87
  # Make sure that all RSpec example groups use the provided ID.
@@ -91,4 +102,12 @@ module Inspec
91
102
  end
92
103
  end
93
104
  end
105
+
106
+ class RSpecReporter < RSpec::Core::Formatters::JsonFormatter
107
+ RSpec::Core::Formatters.register Inspec::RSpecReporter
108
+
109
+ def initialize(*)
110
+ super(StringIO.new)
111
+ end
112
+ end
94
113
  end
@@ -23,17 +23,21 @@ module Inspec::Targets
23
23
  fail "Don't know how to handle folder #{target}"
24
24
  end
25
25
 
26
- # get all test file contents
27
- raw_files = helper.get_filenames(files)
28
- tests = content(target, raw_files, rootdir, base_folder: target)
29
-
30
- libs = []
31
- if helper.respond_to? :get_libraries
32
- raw_libs = helper.get_libraries(files)
33
- libs = content(target, raw_libs, rootdir, base_folder: target, as: :library)
34
- end
26
+ res = {
27
+ test: collect(helper, files, :get_filenames),
28
+ library: collect(helper, files, :get_libraries),
29
+ metadata: collect(helper, files, :get_metadata),
30
+ }.map { |as, list|
31
+ content(target, list, rootdir, base_folder: target, as: as)
32
+ }
33
+
34
+ res.flatten
35
+ end
35
36
 
36
- libs + tests
37
+ # FIXME(sr) dedup inspec/targets/folder
38
+ def collect(helper, files, getter)
39
+ return [] unless helper.respond_to? getter
40
+ helper.method(getter).call(files)
37
41
  end
38
42
  end
39
43
  end
@@ -39,9 +39,10 @@ module Inspec::Targets
39
39
  elsif entry.file?
40
40
  if files.include?(entry.full_name.gsub(rootdir, ''))
41
41
  h = {
42
- content: entry.read,
42
+ # NB if some file is empty, return empty-string, not nil
43
+ content: entry.read || '',
43
44
  type: opts[:as] || :test,
44
- # ref: File.join(input, entry.name),
45
+ ref: entry.full_name,
45
46
  }
46
47
  content.push(h)
47
48
  end
@@ -13,6 +13,8 @@ module Inspec::Targets
13
13
  uri = URI.parse(target)
14
14
  return false if uri.nil? or uri.scheme.nil?
15
15
  %{ http https }.include? uri.scheme
16
+ rescue URI::Error => _e
17
+ false
16
18
  end
17
19
 
18
20
  def resolve(target, opts = {})
@@ -20,14 +22,13 @@ module Inspec::Targets
20
22
  return nil unless target.start_with?('https://', 'http://')
21
23
 
22
24
  # support for github url
23
- m = %r{^https?://(www\.)?github\.com/(?<user>[\w-]+)/(?<repo>[\w-]+)(\.git)?$}.match(target)
25
+ m = %r{^https?://(www\.)?github\.com/(?<user>[\w-]+)/(?<repo>[\w-]+)(\.git)?(/)?$}.match(target)
24
26
  if m
25
27
  url = "https://github.com/#{m[:user]}/#{m[:repo]}/archive/master.tar.gz"
26
28
  else
27
29
  url = target
28
30
  end
29
-
30
- resolve_zip(url, opts)
31
+ resolve_archive(url, opts)
31
32
  end
32
33
 
33
34
  # download url into archive using opts,
@@ -47,7 +48,7 @@ module Inspec::Targets
47
48
  [archive, remote.meta['content-type']]
48
49
  end
49
50
 
50
- def resolve_zip(url, opts)
51
+ def resolve_archive(url, opts)
51
52
  archive, content_type = download_archive(url, Tempfile.new(['inspec-dl-', '.tar.gz']), opts)
52
53
 
53
54
  # replace extension with zip if we detected a zip content type
@@ -18,9 +18,10 @@ module Inspec::Targets
18
18
  while (entry = io.get_next_entry)
19
19
  next if !files.include?(entry.name.gsub(rootdir, ''))
20
20
  h = {
21
- content: io.read,
21
+ # NB if some file is empty, return empty-string, not nil
22
+ content: io.read || '',
22
23
  type: opts[:as] || :test,
23
- # ref: File.join(input, entry.name),
24
+ ref: entry.name,
24
25
  }
25
26
  content.push(h)
26
27
  end
@@ -3,5 +3,5 @@
3
3
  # author: Christoph Hartmann
4
4
 
5
5
  module Inspec
6
- VERSION = '0.9.11'.freeze
6
+ VERSION = '0.10.1'.freeze
7
7
  end