inspec 0.14.8 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -2
  3. data/bin/inspec +3 -4
  4. data/examples/inheritance/README.md +19 -0
  5. data/examples/inheritance/controls/example.rb +11 -0
  6. data/examples/inheritance/inspec.yml +10 -0
  7. data/lib/bundles/inspec-compliance/cli.rb +1 -4
  8. data/lib/bundles/inspec-supermarket/cli.rb +1 -4
  9. data/lib/inspec/dsl.rb +48 -55
  10. data/lib/inspec/profile.rb +6 -2
  11. data/lib/inspec/profile_context.rb +21 -8
  12. data/lib/inspec/runner.rb +17 -12
  13. data/lib/inspec/runner_rspec.rb +1 -0
  14. data/lib/inspec/version.rb +1 -1
  15. data/lib/resources/apache.rb +20 -18
  16. data/lib/resources/apache_conf.rb +92 -90
  17. data/lib/resources/apt.rb +92 -90
  18. data/lib/resources/audit_policy.rb +35 -33
  19. data/lib/resources/auditd_conf.rb +41 -39
  20. data/lib/resources/auditd_rules.rb +155 -153
  21. data/lib/resources/bond.rb +1 -1
  22. data/lib/resources/bridge.rb +97 -95
  23. data/lib/resources/command.rb +47 -45
  24. data/lib/resources/csv.rb +23 -21
  25. data/lib/resources/directory.rb +1 -1
  26. data/lib/resources/etc_group.rb +116 -114
  27. data/lib/resources/file.rb +1 -1
  28. data/lib/resources/gem.rb +39 -37
  29. data/lib/resources/group.rb +100 -98
  30. data/lib/resources/host.rb +103 -101
  31. data/lib/resources/inetd_conf.rb +42 -40
  32. data/lib/resources/ini.rb +15 -13
  33. data/lib/resources/interface.rb +106 -104
  34. data/lib/resources/iptables.rb +36 -34
  35. data/lib/resources/json.rb +64 -62
  36. data/lib/resources/kernel_module.rb +30 -28
  37. data/lib/resources/kernel_parameter.rb +44 -42
  38. data/lib/resources/limits_conf.rb +41 -39
  39. data/lib/resources/login_def.rb +38 -36
  40. data/lib/resources/mount.rb +43 -41
  41. data/lib/resources/mysql.rb +67 -65
  42. data/lib/resources/mysql_conf.rb +89 -87
  43. data/lib/resources/mysql_session.rb +46 -44
  44. data/lib/resources/npm.rb +35 -33
  45. data/lib/resources/ntp_conf.rb +44 -42
  46. data/lib/resources/oneget.rb +46 -44
  47. data/lib/resources/os.rb +22 -20
  48. data/lib/resources/os_env.rb +47 -45
  49. data/lib/resources/package.rb +213 -211
  50. data/lib/resources/parse_config.rb +59 -57
  51. data/lib/resources/passwd.rb +89 -87
  52. data/lib/resources/pip.rb +60 -58
  53. data/lib/resources/port.rb +352 -350
  54. data/lib/resources/postgres.rb +26 -24
  55. data/lib/resources/postgres_conf.rb +66 -64
  56. data/lib/resources/postgres_session.rb +47 -45
  57. data/lib/resources/processes.rb +56 -54
  58. data/lib/resources/registry_key.rb +150 -148
  59. data/lib/resources/script.rb +30 -28
  60. data/lib/resources/security_policy.rb +56 -54
  61. data/lib/resources/service.rb +638 -636
  62. data/lib/resources/shadow.rb +98 -96
  63. data/lib/resources/ssh_conf.rb +58 -56
  64. data/lib/resources/user.rb +363 -361
  65. data/lib/resources/windows_feature.rb +46 -44
  66. data/lib/resources/xinetd.rb +111 -109
  67. data/lib/resources/yaml.rb +16 -14
  68. data/lib/resources/yum.rb +107 -105
  69. data/lib/utils/base_cli.rb +18 -0
  70. data/test/helper.rb +2 -2
  71. data/test/unit/profile_context_test.rb +1 -1
  72. data/test/unit/resources/file_test.rb +1 -1
  73. data/test/unit/resources/mount_test.rb +1 -1
  74. metadata +5 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 44a85cca34621ed900f32162b2c6533a7315bfe5
4
- data.tar.gz: 921d12e76104f1676883b087e5ab9f050de4db8d
3
+ metadata.gz: 6ca71e169ffd037a7a61f99fc09188424a137168
4
+ data.tar.gz: 1aa83936f8b464a2044a7fae20cb14ddce1bdb87
5
5
  SHA512:
6
- metadata.gz: 7d61ff5f5528d764df121aaed034e7bb6c25f46e7c2967bbea21d499e7a22c43f8ce24f7eec0a777a55056170a750ad8d6beb5f5a2680d8072cb8430a80ee684
7
- data.tar.gz: e672dfb4be6c4cd21e8d6e0d0ecc084df103ee53a93a0da36b565fb7b785d20f808f36846ea2078134f14844ce539414bff6591a086bfedc693f82a1ba2cefdf
6
+ metadata.gz: 774c8531d3bfdcab1c0a0587f670c09ab39099e89ff07a79e68c37bb3798e1a1a75e0b613c80a7bc7f8fb492c797ec26b04a12298a0493ddfd0d7784059cfb99
7
+ data.tar.gz: 4335e3fa250d9b6e3b54e25c82289fb3f232452ced7ad0d1a781349b2ae415d8b9533824c4ffda2f53340a96da0cea3720dd630637b59a6286511021672c3945
data/CHANGELOG.md CHANGED
@@ -1,7 +1,29 @@
1
1
  # Change Log
2
2
 
3
- ## [0.14.8](https://github.com/chef/inspec/tree/0.14.8) (2016-03-04)
4
- [Full Changelog](https://github.com/chef/inspec/compare/v0.14.7...0.14.8)
3
+ ## [0.15.0](https://github.com/chef/inspec/tree/0.15.0) (2016-03-09)
4
+ [Full Changelog](https://github.com/chef/inspec/compare/v0.14.8...0.15.0)
5
+
6
+ **Implemented enhancements:**
7
+
8
+ - add color output + make it the default [\#523](https://github.com/chef/inspec/pull/523) ([arlimus](https://github.com/arlimus))
9
+ - select controls to execute [\#522](https://github.com/chef/inspec/pull/522) ([arlimus](https://github.com/arlimus))
10
+
11
+ **Fixed bugs:**
12
+
13
+ - Rename internal File and OS resource classes [\#527](https://github.com/chef/inspec/pull/527) ([arlimus](https://github.com/arlimus))
14
+ - Placing all resources in the Inspec::Resources namespace [\#526](https://github.com/chef/inspec/pull/526) ([adamleff](https://github.com/adamleff))
15
+ - bugfix: inheritance of local profiles [\#524](https://github.com/chef/inspec/pull/524) ([arlimus](https://github.com/arlimus))
16
+
17
+ **Closed issues:**
18
+
19
+ - Colo\[u\]r those dots and Fs! [\#518](https://github.com/chef/inspec/issues/518)
20
+
21
+ **Merged pull requests:**
22
+
23
+ - 0.14.9 [\#525](https://github.com/chef/inspec/pull/525) ([arlimus](https://github.com/arlimus))
24
+
25
+ ## [v0.14.8](https://github.com/chef/inspec/tree/v0.14.8) (2016-03-04)
26
+ [Full Changelog](https://github.com/chef/inspec/compare/v0.14.7...v0.14.8)
5
27
 
6
28
  **Closed issues:**
7
29
 
@@ -9,6 +31,7 @@
9
31
 
10
32
  **Merged pull requests:**
11
33
 
34
+ - 0.14.8 [\#520](https://github.com/chef/inspec/pull/520) ([arlimus](https://github.com/arlimus))
12
35
  - expose control impacts in json [\#519](https://github.com/chef/inspec/pull/519) ([arlimus](https://github.com/arlimus))
13
36
 
14
37
  ## [v0.14.7](https://github.com/chef/inspec/tree/v0.14.7) (2016-03-01)
data/bin/inspec CHANGED
@@ -20,6 +20,7 @@ class Inspec::InspecCLI < Inspec::BaseCLI # rubocop:disable Metrics/ClassLength
20
20
  desc: 'Attach a profile ID to all test results'
21
21
  option :output, aliases: :o, type: :string,
22
22
  desc: 'Save the created profile to a path'
23
+ profile_options
23
24
  def json(target)
24
25
  diagnose
25
26
  o = opts.dup
@@ -42,6 +43,7 @@ class Inspec::InspecCLI < Inspec::BaseCLI # rubocop:disable Metrics/ClassLength
42
43
 
43
44
  desc 'check PATH', 'verify all tests at the specified PATH'
44
45
  option :format, type: :string
46
+ profile_options
45
47
  def check(path) # rubocop:disable Metrics/AbcSize
46
48
  diagnose
47
49
  o = opts.dup
@@ -101,10 +103,7 @@ class Inspec::InspecCLI < Inspec::BaseCLI # rubocop:disable Metrics/ClassLength
101
103
  end
102
104
 
103
105
  desc 'exec PATHS', 'run all test files at the specified PATH.'
104
- option :id, type: :string,
105
- desc: 'Attach a profile ID to all test results'
106
- target_options
107
- option :format, type: :string
106
+ exec_options
108
107
  def exec(*targets)
109
108
  diagnose
110
109
  run_tests(targets, opts)
@@ -0,0 +1,19 @@
1
+ # Example InSpec Profile
2
+
3
+ This example shows the use of InSpec [profile](../../docs/profiles.rst) inheritance.
4
+
5
+ ## Verify a profile
6
+
7
+ InSpec ships with built-in features to verify a profile structure.
8
+
9
+ ```bash
10
+ $ inspec check examples/inheritance --profiles-path examples
11
+ ```
12
+
13
+ ## Execute a profile
14
+
15
+ To run a profile on a local machine use `inspec exec /path/to/profile`.
16
+
17
+ ```bash
18
+ $ inspec exec examples/inheritance --profiles-path examples
19
+ ```
@@ -0,0 +1,11 @@
1
+ # encoding: utf-8
2
+ # copyright: 2015, Chef Software, Inc.
3
+ # license: All rights reserved
4
+
5
+ include_controls 'profile' do
6
+ skip_control 'tmp-1.0'
7
+
8
+ control 'gordon-1.0' do
9
+ impact 0.0
10
+ end
11
+ end
@@ -0,0 +1,10 @@
1
+ name: inheritance
2
+ title: InSpec example inheritance
3
+ maintainer: Chef Software, Inc.
4
+ copyright: Chef Software, Inc.
5
+ copyright_email: support@chef.io
6
+ license: Apache 2 license
7
+ summary: Demonstrates the use of InSpec profile inheritance
8
+ version: 1.0.0
9
+ supports:
10
+ - os-family: linux
@@ -39,10 +39,7 @@ module Compliance
39
39
  end
40
40
 
41
41
  desc 'exec PROFILE', 'executes a Chef Compliance profile'
42
- option :id, type: :string,
43
- desc: 'Attach a profile ID to all test results'
44
- target_options
45
- option :format, type: :string
42
+ exec_options
46
43
  def exec(*tests)
47
44
  # iterate over tests and add compliance scheme
48
45
  tests = tests.map { |t| 'compliance://' + t }
@@ -18,10 +18,7 @@ module Supermarket
18
18
  end
19
19
 
20
20
  desc 'exec PROFILE', 'execute a Supermarket profile'
21
- option :id, type: :string,
22
- desc: 'Attach a profile ID to all test results'
23
- target_options
24
- option :format, type: :string
21
+ exec_options
25
22
  def exec(*tests)
26
23
  # iterate over tests and add compliance scheme
27
24
  tests = tests.map { |t| 'supermarket://' + t }
data/lib/inspec/dsl.rb CHANGED
@@ -6,11 +6,13 @@
6
6
 
7
7
  module Inspec::DSL
8
8
  def require_controls(id, &block)
9
- ::Inspec::DSL.load_spec_files_for_profile self, id, false, &block
9
+ opts = { profile_id: id, include_all: false, backend: @backend, conf: @conf }
10
+ ::Inspec::DSL.load_spec_files_for_profile(self, opts, &block)
10
11
  end
11
12
 
12
13
  def include_controls(id, &block)
13
- ::Inspec::DSL.load_spec_files_for_profile self, id, true, &block
14
+ opts = { profile_id: id, include_all: true, backend: @backend, conf: @conf }
15
+ ::Inspec::DSL.load_spec_files_for_profile(self, opts, &block)
14
16
  end
15
17
 
16
18
  alias require_rules require_controls
@@ -60,72 +62,63 @@ module Inspec::DSL
60
62
  }
61
63
  end
62
64
 
63
- def self.load_spec_file_for_profile(profile_id, file, rule_registry, only_ifs)
64
- raw = File.read(file)
65
- # TODO: error-handling
65
+ def self.load_spec_files_for_profile(bind_context, opts, &block)
66
+ # get all spec files
67
+ target = get_reference_profile(opts[:profile_id], opts[:conf])
68
+ profile = Inspec::Profile.for_target(target, opts)
69
+ context = load_profile_context(opts[:profile_id], profile, opts)
66
70
 
67
- ctx = Inspec::ProfileContext.new(profile_id, rule_registry, only_ifs)
68
- ctx.instance_eval(raw, file, 1)
69
- end
71
+ # if we don't want all the rules, then just make 1 pass to get all rule_IDs
72
+ # that we want to keep from the original
73
+ filter_included_controls(context, opts, &block) if !opts[:include_all]
70
74
 
71
- def self.load_spec_files_for_profile(bind_context, profile_id, include_all, &block)
72
- # get all spec files
73
- files = get_spec_files_for_profile profile_id
74
- # load all rules from spec files
75
- rule_registry = {}
76
- # TODO: handling of only_ifs
77
- only_ifs = []
78
- files.each do |file|
79
- load_spec_file_for_profile(profile_id, file, rule_registry, only_ifs)
80
- end
75
+ # interpret the block and skip/modify as required
76
+ context.load(block) if block_given?
81
77
 
82
- # interpret the block and create a set of rules from it
83
- block_registry = {}
84
- if block_given?
85
- ctx = Inspec::ProfileContext.new(profile_id, block_registry, only_ifs)
86
- ctx.instance_eval(&block)
78
+ # finally register all combined rules
79
+ context.rules.values.each do |control|
80
+ bind_context.register_control(control)
87
81
  end
82
+ end
88
83
 
89
- # if all rules are not included, select only the ones
90
- # that were defined in the block
91
- unless include_all
92
- remove = rule_registry.keys - block_registry.keys
93
- remove.each { |key| rule_registry.delete(key) }
84
+ def self.filter_included_controls(context, opts, &block)
85
+ mock = Inspec::Backend.create({ backend: 'mock' })
86
+ include_ctx = Inspec::ProfileContext.new(opts[:profile_id], mock, opts[:conf])
87
+ include_ctx.load(block) if block_given?
88
+ # remove all rules that were not registered
89
+ context.rules.keys.each do |id|
90
+ unless include_ctx.rules[id]
91
+ context.rules[id] = nil
92
+ end
94
93
  end
94
+ end
95
95
 
96
- # merge the rules in the block_registry (adjustments) with
97
- # the rules in the rule_registry (included)
98
- block_registry.each do |id, r|
99
- org = rule_registry[id]
100
- if org.nil?
101
- # TODO: print error because we write alter a rule that doesn't exist
102
- elsif r.nil?
103
- rule_registry.delete(id)
104
- else
105
- merge_rules(org, r)
106
- end
96
+ def self.get_reference_profile(id, opts)
97
+ profiles_path = opts['profiles_path'] ||
98
+ fail('You must supply a --profiles-path to inherit from other profiles.')
99
+ abs_path = File.expand_path(profiles_path.to_s)
100
+ unless File.directory? abs_path
101
+ fail("Cannot find profiles path #{abs_path}")
107
102
  end
108
103
 
109
- # finally register all combined rules
110
- rule_registry.each do |_id, rule|
111
- bind_context.__register_rule rule
104
+ id_path = File.join(abs_path, id)
105
+ unless File.directory? id_path
106
+ fail("Cannot find referenced profile #{id} in #{id_path}")
112
107
  end
108
+
109
+ id_path
113
110
  end
114
111
 
115
- def self.get_spec_files_for_profile(id)
116
- base_path = '/etc/inspec/tests'
117
- path = File.join(base_path, id)
118
- # find all files to be included
119
- files = []
120
- if File.directory? path
121
- # include all library paths, if they exist
122
- libdir = File.join(path, 'lib')
123
- if File.directory? libdir and !$LOAD_PATH.include?(libdir)
124
- $LOAD_PATH.unshift(libdir)
125
- end
126
- files = Dir[File.join(path, 'spec', '*_spec.rb')]
112
+ def self.load_profile_context(id, profile, opts)
113
+ ctx = Inspec::ProfileContext.new(id, opts[:backend], opts[:conf])
114
+ profile.libraries.each do |path, content|
115
+ ctx.load(content.to_s, path, 1)
116
+ ctx.reload_dsl
117
+ end
118
+ profile.tests.each do |path, content|
119
+ ctx.load(content.to_s, path, 1)
127
120
  end
128
- files
121
+ ctx
129
122
  end
130
123
  end
131
124
 
@@ -13,7 +13,7 @@ module Inspec
13
13
  extend Forwardable
14
14
  attr_reader :path
15
15
 
16
- def self.for_target(target, opts)
16
+ def self.resolve_target(target, opts)
17
17
  # Fetchers retrieve file contents
18
18
  opts[:target] = target
19
19
  fetcher = Inspec::Fetcher.resolve(target)
@@ -27,7 +27,11 @@ module Inspec
27
27
  fail("Don't understand inspec profile in #{target.inspect}, it "\
28
28
  "doesn't look like a supported profile structure.")
29
29
  end
30
- new(reader, opts)
30
+ reader
31
+ end
32
+
33
+ def self.for_target(target, opts)
34
+ new(resolve_target(target, opts), opts)
31
35
  end
32
36
 
33
37
  attr_reader :source_reader
@@ -7,18 +7,18 @@ require 'inspec/dsl'
7
7
  require 'securerandom'
8
8
 
9
9
  module Inspec
10
- class ProfileContext
11
- attr_reader :rules, :only_ifs
12
- def initialize(profile_id, backend, profile_registry = {}, only_ifs = [])
10
+ class ProfileContext # rubocop:disable Metrics/ClassLength
11
+ attr_reader :rules
12
+ def initialize(profile_id, backend, conf)
13
13
  if backend.nil?
14
14
  fail 'ProfileContext is initiated with a backend == nil. ' \
15
15
  'This is a backend error which must be fixed upstream.'
16
16
  end
17
17
 
18
18
  @profile_id = profile_id
19
- @rules = profile_registry
20
- @only_ifs = only_ifs
21
19
  @backend = backend
20
+ @conf = conf.dup
21
+ @rules = {}
22
22
 
23
23
  reload_dsl
24
24
  end
@@ -26,12 +26,16 @@ module Inspec
26
26
  def reload_dsl
27
27
  resources_dsl = Inspec::Resource.create_dsl(@backend)
28
28
  ctx = create_context(resources_dsl, rule_context(resources_dsl))
29
- @profile_context = ctx.new
29
+ @profile_context = ctx.new(@backend, @conf)
30
30
  end
31
31
 
32
32
  def load(content, source = nil, line = nil)
33
33
  @current_load = { file: source }
34
- @profile_context.instance_eval(content, source || 'unknown', line || 1)
34
+ if content.is_a? Proc
35
+ @profile_context.instance_eval(&content)
36
+ else
37
+ @profile_context.instance_eval(content, source || 'unknown', line || 1)
38
+ end
35
39
  end
36
40
 
37
41
  def unregister_rule(id)
@@ -93,6 +97,11 @@ module Inspec
93
97
  include Inspec::DSL
94
98
  include resources_dsl
95
99
 
100
+ def initialize(backend, conf) # rubocop:disable Lint/NestedMethodDefinition, Lint/DuplicateMethods
101
+ @backend = backend
102
+ @conf = conf
103
+ end
104
+
96
105
  define_method :title do |arg|
97
106
  profile_context_owner.set_header(:title, arg)
98
107
  end
@@ -116,6 +125,10 @@ module Inspec
116
125
 
117
126
  alias_method :rule, :control
118
127
 
128
+ define_method :register_control do |control|
129
+ profile_context_owner.register_rule(control) unless control.nil?
130
+ end
131
+
119
132
  define_method :describe do |*args, &block|
120
133
  loc = block_location(block, caller[0])
121
134
  id = "(generated from #{loc} #{SecureRandom.hex})"
@@ -133,7 +146,7 @@ module Inspec
133
146
  nil
134
147
  end
135
148
 
136
- def skip_control(id)
149
+ define_method :skip_control do |id|
137
150
  profile_context_owner.unregister_rule(id)
138
151
  end
139
152
 
data/lib/inspec/runner.rb CHANGED
@@ -46,6 +46,12 @@ module Inspec
46
46
  @backend = Inspec::Backend.create(@conf)
47
47
  end
48
48
 
49
+ def add_target(target, options = {})
50
+ profile = Inspec::Profile.for_target(target, options)
51
+ fail "Could not resolve #{target} to valid input." if profile.nil?
52
+ add_profile(profile, options)
53
+ end
54
+
49
55
  def add_profile(profile, options = {})
50
56
  return unless options[:ignore_supports] ||
51
57
  profile.metadata.supports_transport?(@backend)
@@ -57,26 +63,20 @@ module Inspec
57
63
  profile.tests.each do |ref, content|
58
64
  r = profile.source_reader.target.abs_path(ref)
59
65
  test = { ref: r, content: content }
60
- add_content(test, libs)
66
+ add_content(test, libs, options)
61
67
  end
62
68
  end
63
69
 
64
- def add_target(target, options = {})
65
- profile = Inspec::Profile.for_target(target, options)
66
- fail "Could not resolve #{target} to valid input." if profile.nil?
67
- add_profile(profile)
68
- end
69
-
70
- def create_context
71
- Inspec::ProfileContext.new(@profile_id, @backend)
70
+ def create_context(options = {})
71
+ Inspec::ProfileContext.new(@profile_id, @backend, @conf.merge(options))
72
72
  end
73
73
 
74
- def add_content(test, libs)
74
+ def add_content(test, libs, options = {})
75
75
  content = test[:content]
76
76
  return if content.nil? || content.empty?
77
77
 
78
78
  # load all libraries
79
- ctx = create_context
79
+ ctx = create_context(options)
80
80
  libs.each do |lib|
81
81
  ctx.load(lib[:content].to_s, lib[:ref], lib[:line] || 1)
82
82
  ctx.reload_dsl
@@ -86,7 +86,7 @@ module Inspec
86
86
  ctx.load(content, test[:ref], test[:line] || 1)
87
87
 
88
88
  # process the resulting rules
89
- ctx.rules.each do |rule_id, rule|
89
+ filter_controls(ctx.rules, options[:controls]).each do |rule_id, rule|
90
90
  register_rule(rule_id, rule)
91
91
  end
92
92
  end
@@ -96,6 +96,11 @@ module Inspec
96
96
 
97
97
  private
98
98
 
99
+ def filter_controls(controls_map, include_list)
100
+ return controls_map if include_list.nil? || include_list.empty?
101
+ controls_map.select { |k, _| include_list.include?(k) }
102
+ end
103
+
99
104
  def block_source_info(block)
100
105
  return {} if block.nil? || !block.respond_to?(:source_location)
101
106
  opts = {}