inspec 1.41.0 → 1.42.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 111ac2cdb0069f50d575dfd47e2644489c3b8296
4
- data.tar.gz: b989512dea168e62bc8092c1e3df498a706badd3
3
+ metadata.gz: 6253ad47423d8b2a7bfc56409b61d31c0065aa6e
4
+ data.tar.gz: 7e3e02b74a6a6af95e62c09b62e949bf95eea242
5
5
  SHA512:
6
- metadata.gz: 1cca620d9852d2a6369bbc0bec4663514abcd80e102a7d7b75a3f62f61c1438df5810bc25d81453fda09cd1b72f59ab648bea045b72c95b42da7211b5dda3c4a
7
- data.tar.gz: efa759491e6cadb78ee7f97a2e626663a18548f7f3d60db9fc04d431ad19c5fe11f9427a0a124a05abca26242c12fefd54951b395dc30683253d72dbdc8ef88c
6
+ metadata.gz: 85007c9bc4574c090be7315dc133d21a364afd72af9115ea470fe026aeed18443d50271523ce2ea64d5c729315a0f0dd4433b807b23f4285ce3b8a1537174274
7
+ data.tar.gz: 8a1cc9ab25dd32116be49e3a05c67234040cb47d7db36629ff2fe38bfdb85684b3a9a9846900ea997054c8ac2ce140f4e27e0f4b5998980714382446e6d0a6de
@@ -1,41 +1,58 @@
1
1
  # Change Log
2
2
  <!-- usage documentation: http://expeditor-docs.es.chef.io/configuration/changelog/ -->
3
- <!-- latest_release 1.40.13 -->
4
- ## [v1.40.13](https://github.com/chef/inspec/tree/v1.40.13) (2017-10-07)
3
+ <!-- latest_release 1.42.3 -->
4
+ ## [v1.42.3](https://github.com/chef/inspec/tree/v1.42.3) (2017-10-18)
5
5
 
6
6
  #### Enhancements
7
- - Enhance cmp matcher to work with symbols, fix file documentation [#2224](https://github.com/chef/inspec/pull/2224) ([adamleff](https://github.com/adamleff))
7
+ - windows_hotfix resource: Replace WMI query with PowerShell cmdlet &quot;get-hotfix&quot; [#2252](https://github.com/chef/inspec/pull/2252) ([mattray](https://github.com/mattray))
8
8
  <!-- latest_release -->
9
9
 
10
- <!-- release_rollup since=1.40.0 -->
11
- ### Changes since 1.40.0 release
10
+ <!-- release_rollup since=1.41.0 -->
11
+ ### Changes since 1.41.0 release
12
+
13
+ #### Merged Pull Requests
14
+ - Squashed some unit test warnings [#2242](https://github.com/chef/inspec/pull/2242) ([username-is-already-taken2](https://github.com/username-is-already-taken2)) <!-- 1.41.9 -->
15
+ - Fix documentation of `split` matcher [#2240](https://github.com/chef/inspec/pull/2240) ([eramoto](https://github.com/eramoto)) <!-- 1.41.4 -->
16
+ - Update the profile tempate [#2238](https://github.com/chef/inspec/pull/2238) ([nathenharvey](https://github.com/nathenharvey)) <!-- 1.41.3 -->
12
17
 
13
18
  #### Bug Fixes
14
- - ssl resource: properly raise error when unable to determine if port is enabled [#2205](https://github.com/chef/inspec/pull/2205) ([jquick](https://github.com/jquick)) <!-- 1.40.12 -->
15
- - Fix loading profile files when executing multiple profiles [#2223](https://github.com/chef/inspec/pull/2223) ([adamleff](https://github.com/adamleff)) <!-- 1.40.11 -->
16
- - Support symbol keys in ObjectTraverser [#2221](https://github.com/chef/inspec/pull/2221) ([adamleff](https://github.com/adamleff)) <!-- 1.40.8 -->
17
- - Add nil check for sshd config file [#2217](https://github.com/chef/inspec/pull/2217) ([jquick](https://github.com/jquick)) <!-- 1.40.7 -->
19
+ - Fix `only_if` behavior when used outside controls [#2216](https://github.com/chef/inspec/pull/2216) ([jerryaldrichiii](https://github.com/jerryaldrichiii)) <!-- 1.41.8 -->
20
+ - Fix port ressource ss line parsing [#2243](https://github.com/chef/inspec/pull/2243) ([narkaTee](https://github.com/narkaTee)) <!-- 1.41.7 -->
21
+ - Support PAX-formatted tar files, standardize file lists [#2225](https://github.com/chef/inspec/pull/2225) ([adamleff](https://github.com/adamleff)) <!-- 1.41.2 -->
22
+ - Fix typo in error message in postgres resource [#2248](https://github.com/chef/inspec/pull/2248) ([rndmh3ro](https://github.com/rndmh3ro)) <!-- 1.42.2 -->
23
+ - Resolve the weird encoding issue within inspec shell [#2234](https://github.com/chef/inspec/pull/2234) ([username-is-already-taken2](https://github.com/username-is-already-taken2)) <!-- 1.41.10 -->
18
24
 
19
25
  #### Enhancements
20
- - Enhance cmp matcher to work with symbols, fix file documentation [#2224](https://github.com/chef/inspec/pull/2224) ([adamleff](https://github.com/adamleff)) <!-- 1.40.13 -->
21
- - processes resource: support busybox ps [#2222](https://github.com/chef/inspec/pull/2222) ([adamleff](https://github.com/adamleff)) <!-- 1.40.10 -->
22
- - Update shell resource help to return what is defined [#2219](https://github.com/chef/inspec/pull/2219) ([jquick](https://github.com/jquick)) <!-- 1.40.9 -->
23
- - Add output for port/protocol for host resource. [#2202](https://github.com/chef/inspec/pull/2202) ([jquick](https://github.com/jquick)) <!-- 1.40.3 -->
24
-
25
- #### Merged Pull Requests
26
- - Add Segment tag to enable Google Analytics [#2220](https://github.com/chef/inspec/pull/2220) ([hamburglar](https://github.com/hamburglar)) <!-- 1.40.6 -->
27
- - http resource: properly execute tests on remote target [#2209](https://github.com/chef/inspec/pull/2209) ([adamleff](https://github.com/adamleff)) <!-- 1.40.5 -->
28
- - Adding examples of using expect syntax [#2213](https://github.com/chef/inspec/pull/2213) ([adamleff](https://github.com/adamleff)) <!-- 1.40.4 -->
29
- - Add bsd platform family to etc_hosts resource [#2192](https://github.com/chef/inspec/pull/2192) ([ctbarrett](https://github.com/ctbarrett)) <!-- 1.40.2 -->
30
- - Clean-up kitchen-inspec reference doc [#2208](https://github.com/chef/inspec/pull/2208) ([nathenharvey](https://github.com/nathenharvey)) <!-- 1.40.1 -->
26
+ - windows_hotfix resource: Replace WMI query with PowerShell cmdlet &quot;get-hotfix&quot; [#2252](https://github.com/chef/inspec/pull/2252) ([mattray](https://github.com/mattray)) <!-- 1.42.3 -->
27
+ - Extend Windows ACL matchers [#1744](https://github.com/chef/inspec/pull/1744) ([TheLonelyGhost](https://github.com/TheLonelyGhost)) <!-- 1.42.1 -->
28
+ - Add inspec habitat profile setup command [#2239](https://github.com/chef/inspec/pull/2239) ([adamleff](https://github.com/adamleff)) <!-- 1.42.0 -->
29
+ - Add missed &#39;html&#39; to &#39;format&#39; option explanation and arrange formatters in alphabetical order [#2244](https://github.com/chef/inspec/pull/2244) ([strangeman](https://github.com/strangeman)) <!-- 1.41.6 -->
30
+ - Uses netstat to detect open ports on AIX [#2210](https://github.com/chef/inspec/pull/2210) ([cattywampus](https://github.com/cattywampus)) <!-- 1.41.1 -->
31
+ - etc_fstab resource: properly namespace the resource, add nfs_file_systems documentation [#2190](https://github.com/chef/inspec/pull/2190) ([jburns12](https://github.com/jburns12)) <!-- 1.41.5 -->
31
32
  <!-- release_rollup -->
32
33
 
33
34
  <!-- latest_stable_release -->
35
+ ## [v1.41.0](https://github.com/chef/inspec/tree/v1.41.0) (2017-10-09)
36
+
37
+ #### Enhancements
38
+ - Add bsd platform family to etc_hosts resource [#2192](https://github.com/chef/inspec/pull/2192) ([ctbarrett](https://github.com/ctbarrett))
39
+ - http resource: properly execute tests on remote target [#2209](https://github.com/chef/inspec/pull/2209) ([adamleff](https://github.com/adamleff))
40
+ - Add output for port/protocol for host resource. [#2202](https://github.com/chef/inspec/pull/2202) ([jquick](https://github.com/jquick))
41
+ - Update shell resource help to return what is defined [#2219](https://github.com/chef/inspec/pull/2219) ([jquick](https://github.com/jquick))
42
+ - processes resource: support busybox ps [#2222](https://github.com/chef/inspec/pull/2222) ([adamleff](https://github.com/adamleff))
43
+ - Enhance cmp matcher to work with symbols, fix file documentation [#2224](https://github.com/chef/inspec/pull/2224) ([adamleff](https://github.com/adamleff))
44
+
45
+ #### Bug Fixes
46
+ - Add nil check for sshd config file [#2217](https://github.com/chef/inspec/pull/2217) ([jquick](https://github.com/jquick))
47
+ - Support symbol keys in ObjectTraverser [#2221](https://github.com/chef/inspec/pull/2221) ([adamleff](https://github.com/adamleff))
48
+ - Fix loading profile files when executing multiple profiles [#2223](https://github.com/chef/inspec/pull/2223) ([adamleff](https://github.com/adamleff))
49
+ - ssl resource: properly raise error when unable to determine if port is enabled [#2205](https://github.com/chef/inspec/pull/2205) ([jquick](https://github.com/jquick))
50
+ <!-- latest_stable_release -->
51
+
34
52
  ## [v1.40.0](https://github.com/chef/inspec/tree/v1.40.0) (2017-09-28)
35
53
 
36
54
  #### New Resources
37
55
  - firewalld resource: inspect the status and configuration of firewalld [#2074](https://github.com/chef/inspec/pull/2074) ([dromazmj](https://github.com/dromazmj))
38
- <!-- latest_stable_release -->
39
56
 
40
57
  ## [v1.39.0](https://github.com/chef/inspec/tree/v1.39.0) (2017-09-25)
41
58
 
@@ -100,7 +100,7 @@ The following examples show how to use this InSpec resource.
100
100
 
101
101
  ### Check all partitions that have type of 'nfs'.
102
102
 
103
- nfs_systems = etc_fstab.nfs_file_systems
103
+ nfs_systems = etc_fstab.nfs_file_systems.entries
104
104
  nfs_systems.each do |partition|
105
105
  describe partition do
106
106
  its('mount_options') { should include 'nosuid' }
@@ -70,14 +70,8 @@ The `content` matcher return the value of the environment variable:
70
70
 
71
71
  ### split
72
72
 
73
- The `split` splits the content with the `:` deliminator:
73
+ The `split` matcher splits the value of the environment variable with the `:` deliminator (use the `;` deliminator if Windows):
74
74
 
75
- its('split') { should include (':') }
75
+ its('split') { should include ('/usr/bin') }
76
76
 
77
- or:
78
-
79
- its('split') { should_not include ('.') }
80
-
81
- Use `-1` to test for cases where there is a trailing colon (`:`), such as `dir1::dir2:`:
82
-
83
- its('split') { should include ('-1') }
77
+ Note: the `split` matcher returns an array including `""` for cases where there is a trailing colon (`:`), such as `dir1::dir2:`
@@ -7,14 +7,19 @@ module Habitat
7
7
  class HabitatProfileCLI < Thor
8
8
  namespace 'habitat profile'
9
9
 
10
- desc 'create PATH', 'Create a Habitat artifact for the profile found at PATH'
10
+ desc 'create PATH', 'Create a one-time Habitat artifact for the profile found at PATH'
11
11
  option :output_dir, type: :string, required: false,
12
12
  desc: 'Directory in which to save the generated Habitat artifact. Default: current directory'
13
13
  def create(path)
14
14
  Habitat::Profile.create(path, options)
15
15
  end
16
16
 
17
- desc 'upload PATH', 'Create a Habitat artifact for the profile found at PATH, and upload it to a Habitat Depot'
17
+ desc 'setup PATH', 'Configure the profile at PATH for Habitat, including a plan and hooks'
18
+ def setup(path)
19
+ Habitat::Profile.setup(path)
20
+ end
21
+
22
+ desc 'upload PATH', 'Create a one-time Habitat artifact for the profile found at PATH, and upload it to a Habitat Depot'
18
23
  def upload(path)
19
24
  Habitat::Profile.upload(path, options)
20
25
  end
@@ -17,6 +17,10 @@ module Habitat
17
17
  creator.delete_work_dir
18
18
  end
19
19
 
20
+ def self.setup(path)
21
+ new(path).setup
22
+ end
23
+
20
24
  def self.upload(path, options = {})
21
25
  uploader = new(path, options)
22
26
  uploader.upload
@@ -41,10 +45,11 @@ module Habitat
41
45
  verify_profile
42
46
  vendor_profile_dependencies
43
47
  copy_profile_to_work_dir
44
- create_plan
45
- create_run_hook
46
- create_settings_file
47
- create_default_config
48
+ create_habitat_directories(work_dir)
49
+ create_plan(work_dir)
50
+ create_run_hook(work_dir)
51
+ create_settings_file(work_dir)
52
+ create_default_config(work_dir)
48
53
 
49
54
  # returns the path to the .hart file in the work directory
50
55
  build_hart
@@ -80,6 +85,18 @@ module Habitat
80
85
  FileUtils.rm_rf(work_dir) if Dir.exist?(work_dir)
81
86
  end
82
87
 
88
+ def setup
89
+ Habitat::Log.info("Setting up profile at #{path} for Habitat...")
90
+ create_profile_object
91
+ verify_profile
92
+ vendor_profile_dependencies
93
+ create_habitat_directories(path)
94
+ create_plan(path)
95
+ create_run_hook(path)
96
+ create_settings_file(path)
97
+ create_default_config(path)
98
+ end
99
+
83
100
  private
84
101
 
85
102
  def create_profile_object
@@ -151,20 +168,26 @@ module Habitat
151
168
  return @work_dir if @work_dir
152
169
 
153
170
  @work_dir ||= Dir.mktmpdir('inspec-habitat-exporter')
154
- Dir.mkdir(File.join(@work_dir, 'src'))
155
- Dir.mkdir(File.join(@work_dir, 'habitat'))
156
- Dir.mkdir(File.join(@work_dir, 'habitat', 'config'))
157
- Dir.mkdir(File.join(@work_dir, 'habitat', 'hooks'))
158
171
  Habitat::Log.debug("Generated work directory #{@work_dir}")
159
172
 
160
173
  @work_dir
161
174
  end
162
175
 
176
+ def create_habitat_directories(parent_directory)
177
+ [
178
+ File.join(parent_directory, 'habitat'),
179
+ File.join(parent_directory, 'habitat', 'config'),
180
+ File.join(parent_directory, 'habitat', 'hooks'),
181
+ ].each do |dir|
182
+ Dir.mkdir(dir) unless Dir.exist?(dir)
183
+ end
184
+ end
185
+
163
186
  def copy_profile_to_work_dir
164
187
  Habitat::Log.info('Copying profile contents to the work directory...')
165
188
  profile.files.each do |f|
166
189
  src = File.join(profile.root_path, f)
167
- dst = File.join(work_dir, 'src', f)
190
+ dst = File.join(work_dir, f)
168
191
  if File.directory?(f)
169
192
  Habitat::Log.debug("Creating directory #{dst}")
170
193
  FileUtils.mkdir_p(dst)
@@ -175,26 +198,26 @@ module Habitat
175
198
  end
176
199
  end
177
200
 
178
- def create_plan
179
- plan_file = File.join(work_dir, 'habitat', 'plan.sh')
201
+ def create_plan(directory)
202
+ plan_file = File.join(directory, 'habitat', 'plan.sh')
180
203
  Habitat::Log.info("Generating Habitat plan at #{plan_file}...")
181
204
  File.write(plan_file, plan_contents)
182
205
  end
183
206
 
184
- def create_run_hook
185
- run_hook_file = File.join(work_dir, 'habitat', 'hooks', 'run')
207
+ def create_run_hook(directory)
208
+ run_hook_file = File.join(directory, 'habitat', 'hooks', 'run')
186
209
  Habitat::Log.info("Generating a Habitat run hook at #{run_hook_file}...")
187
210
  File.write(run_hook_file, run_hook_contents)
188
211
  end
189
212
 
190
- def create_settings_file
191
- settings_file = File.join(work_dir, 'habitat', 'config', 'settings.sh')
213
+ def create_settings_file(directory)
214
+ settings_file = File.join(directory, 'habitat', 'config', 'settings.sh')
192
215
  Habitat::Log.info("Generating a settings file at #{settings_file}...")
193
216
  File.write(settings_file, "SLEEP_TIME={{cfg.sleep_time}}\n")
194
217
  end
195
218
 
196
- def create_default_config
197
- default_toml = File.join(work_dir, 'habitat', 'default.toml')
219
+ def create_default_config(directory)
220
+ default_toml = File.join(directory, 'habitat', 'default.toml')
198
221
  Habitat::Log.info("Generating Habitat's default.toml configuration...")
199
222
  File.write(default_toml, 'sleep_time = 300')
200
223
  end
@@ -308,7 +331,7 @@ EOL
308
331
  plan += <<-EOL
309
332
 
310
333
  do_build() {
311
- cp -vr $PLAN_CONTEXT/../src/* $HAB_CACHE_SRC_PATH/$pkg_dirname
334
+ cp -vr $PLAN_CONTEXT/../* $HAB_CACHE_SRC_PATH/$pkg_dirname
312
335
  }
313
336
 
314
337
  do_install() {
@@ -321,6 +344,7 @@ do_install() {
321
344
  profile_contents=(${profile_contents[@]/$item/})
322
345
  done
323
346
 
347
+ mkdir ${pkg_prefix}/dist
324
348
  cp -r ${profile_contents[@]} ${pkg_prefix}/dist/
325
349
  }
326
350
  EOL
@@ -1,3 +1,3 @@
1
1
  # Example InSpec Profile
2
2
 
3
- This example shows the implementation of an InSpec [profile](../../docs/profiles.rst).
3
+ This example shows the implementation of an InSpec profile.
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
- # copyright: 2015, The Authors
2
+ # copyright: 2017, The Authors
3
3
 
4
4
  title 'sample section'
5
5
 
@@ -186,7 +186,7 @@ class Inspec::InspecCLI < Inspec::BaseCLI # rubocop:disable Metrics/ClassLength
186
186
  option :command, aliases: :c,
187
187
  desc: 'A single command string to run instead of launching the shell'
188
188
  option :format, type: :string, default: nil, hide: true,
189
- desc: 'Which formatter to use: cli, progress, documentation, json, json-min, junit'
189
+ desc: 'Which formatter to use: cli, documentation, html, json, json-min, junit, progress'
190
190
  def shell_func
191
191
  diagnose
192
192
  o = opts.dup
@@ -35,7 +35,7 @@ module Inspec
35
35
  # @param profile_context [Inspec::ProfileContext]
36
36
  # @param outer_dsl [OuterDSLClass]
37
37
  # @return [ProfileContextClass]
38
- def self.create(profile_context, resources_dsl) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
38
+ def self.create(profile_context, resources_dsl) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
39
39
  rule_class = rule_context(resources_dsl)
40
40
  profile_context_owner = profile_context
41
41
  profile_id = profile_context.profile_id
@@ -45,12 +45,14 @@ module Inspec
45
45
  include Inspec::DSL::RequireOverride
46
46
  include resources_dsl
47
47
 
48
+ attr_accessor :skip_file
49
+
48
50
  def initialize(backend, conf, dependencies, require_loader)
49
51
  @backend = backend
50
52
  @conf = conf
51
53
  @dependencies = dependencies
52
54
  @require_loader = require_loader
53
- @skip_profile = false
55
+ @skip_file = false
54
56
  end
55
57
 
56
58
  define_method :title do |arg|
@@ -113,7 +115,7 @@ module Inspec
113
115
  end
114
116
 
115
117
  define_method :register_control do |control, &block|
116
- if @skip_profile || !profile_context_owner.profile_supports_os?
118
+ if @skip_file || !profile_context_owner.profile_supports_os?
117
119
  ::Inspec::Rule.set_skip_rule(control, true)
118
120
  end
119
121
 
@@ -129,9 +131,17 @@ module Inspec
129
131
  profile_context_owner.unregister_rule(id)
130
132
  end
131
133
 
132
- def only_if
133
- return unless block_given?
134
- @skip_profile ||= !yield
134
+ define_method :only_if do |&block|
135
+ return unless block
136
+ return if @skip_file == true || block.yield == true
137
+
138
+ # Apply `set_skip_rule` for other rules in the same file
139
+ profile_context_owner.rules.values.each do |r|
140
+ sources_match = r.source_file == block.source_location[0]
141
+ Inspec::Rule.set_skip_rule(r, true) if sources_match
142
+ end
143
+
144
+ @skip_file = true
135
145
  end
136
146
 
137
147
  alias_method :rule, :control
@@ -137,7 +137,16 @@ module Inspec
137
137
  @contents = {}
138
138
  @files = []
139
139
  walk_tar(@path) do |tar|
140
- @files = tar.map(&:full_name).find_all { |x| !x.empty? }
140
+ @files = tar.find_all(&:file?)
141
+
142
+ # delete all entries with no name
143
+ @files = @files.find_all { |x| !x.full_name.empty? }
144
+
145
+ # delete all entries that have a PaxHeader
146
+ @files = @files.delete_if { |x| x.full_name.include?('PaxHeader/') }
147
+
148
+ # replace all items of the array simply with the relative filename of the file
149
+ @files.map! { |x| Pathname.new(x.full_name).relative_path_from(Pathname.new('.')).to_s }
141
150
  end
142
151
  end
143
152
 
@@ -157,7 +166,7 @@ module Inspec
157
166
  # NB `TarReader` includes `Enumerable` beginning with Ruby 2.x
158
167
  walk_tar(@path) do |tar|
159
168
  tar.each do |entry|
160
- next unless entry.file? && file == entry.full_name
169
+ next unless entry.file? && [file, "./#{file}"].include?(entry.full_name)
161
170
  res = entry.read
162
171
  break
163
172
  end
@@ -182,8 +191,19 @@ module Inspec
182
191
  if @prefix.nil?
183
192
  raise "Could not determine path prefix for #{parent}"
184
193
  end
185
- @files = parent.files.find_all { |x| x.start_with?(prefix) && x != prefix }
194
+
195
+ # select all files that begin with the prefix, and strip off the prefix from the file.
196
+ #
197
+ # strip off any leading top-level relative path (./) which is common in
198
+ # PAX-formatted tar files. Do not do any translation of the path if the
199
+ # path is an absolute path.
200
+ @files = parent.files
201
+ .find_all { |x| x.start_with?(prefix) && x != prefix }
186
202
  .map { |x| x[prefix.length..-1] }
203
+ .map do |x|
204
+ path = Pathname.new(x)
205
+ path.absolute? ? path.to_s : path.relative_path_from(Pathname.new('.')).to_s
206
+ end
187
207
  end
188
208
 
189
209
  def abs_path(file)
@@ -127,6 +127,8 @@ module Inspec
127
127
  end
128
128
 
129
129
  def load_control_file(*args)
130
+ # Set `skip_file` to `false` between file loads to prevent skips from spanning multiple control files
131
+ control_eval_context.skip_file = false
130
132
  load_with_context(control_eval_context, *args)
131
133
  end
132
134
  alias load load_control_file
@@ -94,6 +94,10 @@ module Inspec
94
94
  @tags
95
95
  end
96
96
 
97
+ def source_file
98
+ @__file
99
+ end
100
+
97
101
  # Skip all checks if only_if is false
98
102
  #
99
103
  # @param [Type] &block returns true if tests are added, false otherwise
@@ -42,7 +42,7 @@ module Inspec
42
42
 
43
43
  # configure pry shell prompt
44
44
  Pry.config.prompt_name = 'inspec'
45
- Pry.prompt = [proc { "#{readline_ignore("\e[0;32m")}#{Pry.config.prompt_name}> #{readline_ignore("\e[0m")}" }]
45
+ Pry.prompt = [proc { "#{readline_ignore("\e[1m\e[32m")}#{Pry.config.prompt_name}> #{readline_ignore("\e[0m")}" }]
46
46
 
47
47
  # Add a help menu as the default intro
48
48
  Pry.hooks.add_hook(:before_session, 'inspec_intro') do
@@ -79,7 +79,7 @@ module Inspec
79
79
  end
80
80
 
81
81
  def mark(x)
82
- "#{readline_ignore("\033[1m")}#{x}#{readline_ignore("\033[0m")}"
82
+ "\e[1m\e[39m#{x}\e[0m"
83
83
  end
84
84
 
85
85
  def print_example(example)
@@ -106,8 +106,8 @@ module Inspec
106
106
  puts <<EOF
107
107
  You are currently running on:
108
108
 
109
- OS platform: #{mark ctx.os[:name] || 'unknown'}
110
- OS family: #{mark ctx.os[:family] || 'unknown'}
109
+ OS platform: #{mark ctx.os[:name] || 'unknown'}
110
+ OS family: #{mark ctx.os[:family] || 'unknown'}
111
111
  OS release: #{mark ctx.os[:release] || 'unknown'}
112
112
  EOF
113
113
  end
@@ -4,5 +4,5 @@
4
4
  # author: Christoph Hartmann
5
5
 
6
6
  module Inspec
7
- VERSION = '1.41.0'.freeze
7
+ VERSION = '1.42.3'.freeze
8
8
  end
@@ -4,104 +4,99 @@
4
4
 
5
5
  require 'utils/parser'
6
6
 
7
- class EtcFstab < Inspec.resource(1)
8
- name 'etc_fstab'
9
- desc 'Use the etc_fstab InSpec audit resource to check the configuration of the etc/fstab file.'
10
- example "
11
- removable_media = etc_fstab.removable_media_file_systems
12
- removable_media.each do |media|
13
- describe media do
14
- its ('mount_options') { should include 'nosuid' }
7
+ module Inspec::Resources
8
+ class EtcFstab < Inspec.resource(1)
9
+ name 'etc_fstab'
10
+ desc 'Use the etc_fstab InSpec audit resource to check the configuration of the etc/fstab file.'
11
+ example "
12
+ nfs_systems = etc_fstab.nfs_file_systems.entries
13
+ nfs_systems.each do |file_system|
14
+ describe file_system do
15
+ its ('mount_options') { should include 'nosuid' }
16
+ its ('mount_options') { should include 'noexec' }
17
+ its ('mount_options') { should include 'sec=krb5:krb5i:krb5p }
18
+ end
15
19
  end
16
- end
17
20
 
18
- nfs_systems = etc_fstab.nfs_file_systems
19
- nfs_systems.each do |file_system|
20
- describe file_system do
21
- its ('mount_options') { should include 'nosuid' }
22
- its ('mount_options') { should include 'noexec' }
23
- its ('mount_options') { should include '\'sec=krb5:krb5i:krb5p\'' }
21
+ describe etc_fstab do
22
+ its ('home_mount_options') { should include 'nosuid' }
24
23
  end
25
- end
26
-
27
- describe etc_fstab do
28
- its ('home_mount_options') { should include 'nosuid' }
29
- end
30
- "
31
-
32
- attr_reader :params
24
+ "
33
25
 
34
- include CommentParser
26
+ attr_reader :params
35
27
 
36
- def initialize(fstab_path = nil)
37
- return skip_resource 'The `etc_fstab` resource is not supported on your OS.' unless inspec.os.linux?
38
- @conf_path = fstab_path || '/etc/fstab'
39
- @files_contents = {}
40
- @content = nil
41
- @params = nil
42
- read_content
43
- end
28
+ include CommentParser
44
29
 
45
- filter = FilterTable.create
46
- filter.add_accessor(:where)
47
- .add_accessor(:entries)
48
- .add(:device_name, field: 'device_name')
49
- .add(:mount_point, field: 'mount_point')
50
- .add(:file_system_type, field: 'file_system_type')
51
- .add(:mount_options, field: 'mount_options')
52
- .add(:dump_options, field: 'dump_options')
53
- .add(:file_system_options, field: 'file_system_options')
54
- .add(:configured?) { |x| x.entries.any? }
55
-
56
- filter.connect(self, :params)
57
-
58
- def nfs_file_systems
59
- where { file_system_type.match(/nfs/) }
60
- end
30
+ def initialize(fstab_path = nil)
31
+ return skip_resource 'The `etc_fstab` resource is not supported on your OS.' unless inspec.os.linux?
32
+ @conf_path = fstab_path || '/etc/fstab'
33
+ @files_contents = {}
34
+ @content = nil
35
+ @params = nil
36
+ read_content
37
+ end
61
38
 
62
- def home_mount_options
63
- return nil unless where { mount_point == '/home' }.configured?
64
- where { mount_point == '/home' }.entries[0].mount_options
65
- end
39
+ filter = FilterTable.create
40
+ filter.add_accessor(:where)
41
+ .add_accessor(:entries)
42
+ .add(:device_name, field: 'device_name')
43
+ .add(:mount_point, field: 'mount_point')
44
+ .add(:file_system_type, field: 'file_system_type')
45
+ .add(:mount_options, field: 'mount_options')
46
+ .add(:dump_options, field: 'dump_options')
47
+ .add(:file_system_options, field: 'file_system_options')
48
+ .add(:configured?) { |x| x.entries.any? }
49
+
50
+ filter.connect(self, :params)
51
+
52
+ def nfs_file_systems
53
+ where { file_system_type.match(/nfs/) }
54
+ end
66
55
 
67
- private
56
+ def home_mount_options
57
+ return nil unless where { mount_point == '/home' }.configured?
58
+ where { mount_point == '/home' }.entries[0].mount_options
59
+ end
68
60
 
69
- def read_content
70
- @content = ''
71
- @params = {}
72
- @content = read_file(@conf_path)
73
- @params = parse_conf(@content)
74
- end
61
+ private
75
62
 
76
- def parse_conf(content)
77
- content.map do |line|
78
- data, = parse_comment_line(line, comment_char: '#', standalone_comments: false)
79
- parse_line(data) unless data == ''
80
- end.compact
81
- end
63
+ def read_content
64
+ @content = ''
65
+ @params = {}
66
+ @content = read_file(@conf_path)
67
+ @params = parse_conf(@content)
68
+ end
82
69
 
83
- def parse_line(line)
84
- attributes = line.split
85
- {
86
- 'device_name' => attributes[0],
87
- 'mount_point' => attributes[1],
88
- 'file_system_type' => attributes[2],
89
- 'mount_options' => attributes[3].split(','),
90
- 'dump_options' => attributes[4].to_i,
91
- 'file_system_options' => attributes[5].to_i,
92
- }
93
- end
70
+ def parse_conf(content)
71
+ content.map do |line|
72
+ data, = parse_comment_line(line, comment_char: '#', standalone_comments: false)
73
+ parse_line(data) unless data == ''
74
+ end.compact
75
+ end
94
76
 
95
- def read_file(conf_path = @conf_path)
96
- file = inspec.file(conf_path)
97
- if !file.file?
98
- return skip_resource "Can't find \"#{@conf_path}\""
77
+ def parse_line(line)
78
+ attributes = line.split
79
+ {
80
+ 'device_name' => attributes[0],
81
+ 'mount_point' => attributes[1],
82
+ 'file_system_type' => attributes[2],
83
+ 'mount_options' => attributes[3].split(','),
84
+ 'dump_options' => attributes[4].to_i,
85
+ 'file_system_options' => attributes[5].to_i,
86
+ }
99
87
  end
100
88
 
101
- raw_conf = file.content
102
- if raw_conf.empty? && !file.empty?
103
- return skip_resource("File is empty or unable to read file at path:\"#{@conf_path}\"")
89
+ def read_file(conf_path = @conf_path)
90
+ file = inspec.file(conf_path)
91
+ if !file.file?
92
+ return skip_resource "Can't find \"#{@conf_path}\""
93
+ end
94
+
95
+ raw_conf = file.content
96
+ if raw_conf.empty? && !file.empty?
97
+ return skip_resource("File is empty or unable to read file at path:\"#{@conf_path}\"")
98
+ end
99
+ raw_conf.lines
104
100
  end
105
- raw_conf.lines
106
101
  end
107
102
  end
@@ -84,6 +84,13 @@ module Inspec::Resources
84
84
  file_permission_granted?('execute', by_usergroup, by_specific_user)
85
85
  end
86
86
 
87
+ def allowed?(permission, opts = {})
88
+ return false unless exist?
89
+ return skip_resource '`allowed?` is not supported on your OS yet.' if @perms_provider.nil?
90
+
91
+ file_permission_granted?(permission, opts[:by], opts[:by_user])
92
+ end
93
+
87
94
  def mounted?(expected_options = nil, identical = false)
88
95
  mounted = file.mounted
89
96
 
@@ -206,18 +213,82 @@ module Inspec::Resources
206
213
  end
207
214
 
208
215
  def check_file_permission_by_user(access_type, user, path)
209
- access_rule = case access_type
210
- when 'read'
211
- '@(\'FullControl\', \'Modify\', \'ReadAndExecute\', \'Read\', \'ListDirectory\')'
212
- when 'write'
213
- '@(\'FullControl\', \'Modify\', \'Write\')'
214
- when 'execute'
215
- '@(\'FullControl\', \'Modify\', \'ReadAndExecute\', \'ExecuteFile\')'
216
- else
217
- raise 'Invalid access_type provided'
218
- end
216
+ access_rule = translate_perm_names(access_type)
217
+ access_rule = convert_to_powershell_array(access_rule)
218
+
219
219
  cmd = inspec.command("@(@((Get-Acl '#{path}').access | Where-Object {$_.AccessControlType -eq 'Allow' -and $_.IdentityReference -eq '#{user}' }) | Where-Object {($_.FileSystemRights.ToString().Split(',') | % {$_.trim()} | ? {#{access_rule} -contains $_}) -ne $null}) | measure | % { $_.Count }")
220
220
  cmd.stdout.chomp == '0' ? false : true
221
221
  end
222
+
223
+ private
224
+
225
+ def convert_to_powershell_array(arr)
226
+ if arr.empty?
227
+ '@()'
228
+ else
229
+ %{@('#{arr.join("', '")}')}
230
+ end
231
+ end
232
+
233
+ # Translates a developer-friendly string into a list of acceptable
234
+ # FileSystemRights that match it, because Windows has a fun heirarchy
235
+ # of permissions that are able to be noted in multiple ways.
236
+ #
237
+ # See also: https://www.codeproject.com/Reference/871338/AccessControl-FileSystemRights-Permissions-Table
238
+ def translate_perm_names(access_type)
239
+ names = translate_common_perms(access_type)
240
+ names ||= translate_granular_perms(access_type)
241
+ names ||= translate_uncommon_perms(access_type)
242
+ raise 'Invalid access_type provided' unless names
243
+ end
244
+
245
+ def translate_common_perms(access_type)
246
+ case access_type
247
+ when 'full-control'
248
+ %w{FullControl}
249
+ when 'modify'
250
+ translate_perm_names('full-control') + %w{Modify}
251
+ when 'read'
252
+ translate_perm_names('modify') + %w{ReadAndExecute Read}
253
+ when 'write'
254
+ translate_perm_names('modify') + %w{Write}
255
+ when 'execute'
256
+ translate_perm_names('modify') + %w{ReadAndExecute ExecuteFile Traverse}
257
+ when 'delete'
258
+ translate_perm_names('modify') + %w{Delete}
259
+ end
260
+ end
261
+
262
+ def translate_uncommon_perms(access_type)
263
+ case access_type
264
+ when 'delete-subdirectories-and-files'
265
+ translate_perm_names('full-control') + %w{DeleteSubdirectoriesAndFiles}
266
+ when 'change-permissions'
267
+ translate_perm_names('full-control') + %w{ChangePermissions}
268
+ when 'take-ownership'
269
+ translate_perm_names('full-control') + %w{TakeOwnership}
270
+ end
271
+ end
272
+
273
+ def translate_granular_perms(access_type)
274
+ case access_type
275
+ when 'write-data', 'create-files'
276
+ translate_perm_names('write') + %w{WriteData CreateFiles}
277
+ when 'append-data', 'create-directories'
278
+ translate_perm_names('write') + %w{CreateDirectories AppendData}
279
+ when 'write-extended-attributes'
280
+ translate_perm_names('write') + %w{WriteExtendedAttributes}
281
+ when 'write-attributes'
282
+ translate_perm_names('write') + %w{WriteAttributes}
283
+ when 'read-data', 'list-directory'
284
+ translate_perm_names('read') + %w{ReadData ListDirectory}
285
+ when 'read-attributes'
286
+ translate_perm_names('read') + %w{ReadAttributes}
287
+ when 'read-extended-attributes'
288
+ translate_perm_names('read') + %w{ReadExtendedAttributes}
289
+ when 'read-permissions'
290
+ translate_perm_names('read') + %w{ReadPermissions}
291
+ end
292
+ end
222
293
  end
223
294
  end
@@ -59,9 +59,11 @@ module Inspec::Resources
59
59
  os = inspec.os
60
60
  if os.linux?
61
61
  LinuxPorts.new(inspec)
62
- elsif %w{darwin aix}.include?(os[:family])
62
+ elsif os.aix?
63
63
  # AIX: see http://www.ibm.com/developerworks/aix/library/au-lsof.html#resources
64
64
  # and https://www-01.ibm.com/marketing/iwm/iwm/web/reg/pick.do?source=aixbp
65
+ AixPorts.new(inspec)
66
+ elsif os.darwin?
65
67
  # Darwin: https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man8/lsof.8.html
66
68
  LsofPorts.new(inspec)
67
69
  elsif os.windows?
@@ -263,6 +265,121 @@ module Inspec::Resources
263
265
  end
264
266
  end
265
267
 
268
+ class AixPorts < PortsInfo
269
+ def info
270
+ ports_via_netstat || ports_via_lsof
271
+ end
272
+
273
+ def ports_via_lsof
274
+ return nil unless inspec.command('lsof').exist?
275
+ LsofPorts.new(inspec).info
276
+ end
277
+
278
+ def ports_via_netstat
279
+ return nil unless inspec.command('netstat').exist?
280
+
281
+ cmd = inspec.command('netstat -Aan | grep LISTEN')
282
+ return nil unless cmd.exit_status.to_i.zero?
283
+
284
+ ports = []
285
+ # parse all lines
286
+ cmd.stdout.each_line do |line|
287
+ port_info = parse_netstat_line(line)
288
+
289
+ # only push protocols we are interested in
290
+ next unless %w{tcp tcp6 udp udp6}.include?(port_info['protocol'])
291
+ ports.push(port_info)
292
+ end
293
+
294
+ ports
295
+ end
296
+
297
+ def parse_netstat_line(line)
298
+ # parse each line
299
+ # 1 - Socket, 2 - Proto, 3 - Receive-Q, 4 - Send-Q, 5 - Local address, 6 - Foreign Address, 7 - State
300
+ parsed = /^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)?\s+(\S+)/.match(line)
301
+ return {} if parsed.nil?
302
+
303
+ # parse ip4 and ip6 addresses
304
+ protocol = parsed[2].downcase
305
+
306
+ # detect protocol if not provided
307
+ protocol += '6' if parsed[5].count(':') > 1 && %w{tcp udp}.include?(protocol)
308
+ protocol.chop! if %w{tcp4 upd4}.include?(protocol)
309
+
310
+ # extract host and port information
311
+ host, port = parse_net_address(parsed[5], protocol)
312
+ return {} if host.nil?
313
+
314
+ # extract PID
315
+ cmd = inspec.command("rmsock #{parsed[1]} tcpcb")
316
+ parsed_pid = /^The socket (\S+) is being held by proccess (\d+) \((\S+)\)/.match(cmd.stdout)
317
+ return {} if parsed_pid.nil?
318
+ process = parsed_pid[3]
319
+ pid = parsed_pid[2]
320
+ pid = pid.to_i if pid =~ /^\d+$/
321
+
322
+ {
323
+ 'port' => port,
324
+ 'address' => host,
325
+ 'protocol' => protocol,
326
+ 'process' => process,
327
+ 'pid' => pid,
328
+ }
329
+ end
330
+
331
+ def parse_net_address(net_addr, protocol)
332
+ # local/foreign addresses on AIX use a '.' to separate the addresss
333
+ # from the port
334
+ address, _sep, port = net_addr.rpartition('.')
335
+ if protocol.eql?('tcp6') || protocol.eql?('udp6')
336
+ ip6addr = address
337
+ # AIX uses the wildcard character for ipv6 addresses listening on
338
+ # all interfaces.
339
+ ip6addr = '::' if ip6addr =~ /^\*$/
340
+
341
+ # v6 addresses need to end in a double-colon when using
342
+ # shorthand notation. netstat ends with a single colon.
343
+ # IPAddr will fail to properly parse an address unless it
344
+ # uses a double-colon for short-hand notation.
345
+ ip6addr += ':' if ip6addr =~ /\w:$/
346
+
347
+ begin
348
+ ip_parser = IPAddr.new(ip6addr)
349
+ rescue IPAddr::InvalidAddressError
350
+ # This IP is not parsable. There appears to be a bug in netstat
351
+ # output that truncates link-local IP addresses:
352
+ # example: udp6 0 0 fe80::42:acff:fe11::123 :::* 0 54550 3335/ntpd
353
+ # actual link address: inet6 fe80::42:acff:fe11:5/64 scope link
354
+ #
355
+ # in this example, the "5" is truncated making the netstat output
356
+ # an invalid IP address.
357
+ return [nil, nil]
358
+ end
359
+
360
+ # Check to see if this is a IPv4 address in a tcp6/udp6 line.
361
+ # If so, don't put brackets around the IP or URI won't know how
362
+ # to properly handle it.
363
+ # example: f000000000000000 tcp6 0 0 127.0.0.1.8005 *.* LISTEN
364
+ if ip_parser.ipv4?
365
+ ip_addr = URI("addr://#{ip6addr}:#{port}")
366
+ host = ip_addr.host
367
+ else
368
+ ip_addr = URI("addr://[#{ip6addr}]:#{port}")
369
+ host = ip_addr.host[1..ip_addr.host.size-2]
370
+ end
371
+ else
372
+ ip4addr = address
373
+ # In AIX the wildcard character is used to match all interfaces
374
+ ip4addr = '0.0.0.0' if ip4addr =~ /^\*$/
375
+ ip_addr = URI("addr://#{ip4addr}:#{port}")
376
+ host = ip_addr.host
377
+ end
378
+
379
+ [host, port.to_i]
380
+ end
381
+ end
382
+
266
383
  # extract port information from netstat
267
384
  class LinuxPorts < PortsInfo # rubocop:disable Metrics/ClassLength
268
385
  ALLOWED_PROTOCOLS = %w{tcp tcp6 udp udp6}.freeze
@@ -430,13 +547,33 @@ module Inspec::Resources
430
547
  # the netstat-provided data
431
548
  host = '0.0.0.0' if host == '*'
432
549
 
433
- # parse the process name from the processes information
434
- process_match = parsed[6].match(/users:\(\(\"(\S+)\"/)
435
- process = process_match.nil? ? nil : process_match[1]
436
-
437
- # parse the PID from the processes information
438
- pid_match = parsed[6].match(/pid=(\d+)/)
439
- pid = pid_match.nil? ? nil : pid_match[1].to_i
550
+ # in case process list parsing is not successfull
551
+ process = nil
552
+ pid = nil
553
+
554
+ # parse process and pid from the process list
555
+ #
556
+ # remove the "users:((" and "))" parts
557
+ # input: users:((\"nginx\",pid=583,fd=8),(\"nginx\",pid=582,fd=8),(\"nginx\",pid=580,fd=8),(\"nginx\",pid=579,fd=8))
558
+ # res: \"nginx\",pid=583,fd=8),(\"nginx\",pid=582,fd=8),(\"nginx\",pid=580,fd=8),(\"nginx\",pid=579,fd=8
559
+ process_list_match = parsed[6].match(/users:\(\((.+)\)\)/)
560
+ if process_list_match
561
+ # list entires are seperated by "," the braces can also be removed
562
+ # input: \"nginx\",pid=583,fd=8),(\"nginx\",pid=582,fd=8),(\"nginx\",pid=580,fd=8),(\"nginx\",pid=579,fd=8
563
+ # res: ["\"nginx\",pid=583,fd=8", "\"nginx\",pid=582,fd=8", "\"nginx\",pid=580,fd=8", "\"nginx\",pid=579,fd=8"]
564
+ process_list = process_list_match[1].split('),(')
565
+ # To stay backwards compatible with netstat we need to select
566
+ # the last element in the resulting array.
567
+ # res: "\"nginx\",pid=579,fd=8"
568
+
569
+ # parse the process name from the process list
570
+ process_match = process_list.last.match(/^\"(\S+)\"/)
571
+ process = process_match.nil? ? nil : process_match[1]
572
+
573
+ # parse the PID from the process list
574
+ pid_match = process_list.last.match(/pid=(\d+)/)
575
+ pid = pid_match.nil? ? nil : pid_match[1].to_i
576
+ end
440
577
 
441
578
  {
442
579
  'port' => port,
@@ -86,7 +86,7 @@ module Inspec::Resources
86
86
  if data_dir_loc.nil?
87
87
  warn 'Unable to find the PostgreSQL data_dir in expected location(s), please
88
88
  execute "psql -t -A -p <port> -h <host> -c "show hba_file";" as the PostgreSQL
89
- DBA to find the non-starndard data_dir location.'
89
+ DBA to find the non-standard data_dir location.'
90
90
  end
91
91
  data_dir_loc
92
92
  end
@@ -18,7 +18,7 @@ module Inspec::Resources
18
18
  @content = nil
19
19
  os = inspec.os
20
20
  return skip_resource 'The `windows_hotfix` resource is not a feature of your OS.' unless os.windows?
21
- query = "Get-WmiObject -class \"win32_quickfixengineering\" -filter \"HotFixID = '" + @id + "'\""
21
+ query = "get-hotfix -id #{@id}"
22
22
  cmd = inspec.powershell(query)
23
23
  @content = cmd.stdout
24
24
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: inspec
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.41.0
4
+ version: 1.42.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dominik Richter
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-10-09 00:00:00.000000000 Z
11
+ date: 2017-10-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: train