inspec 0.14.8 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
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 = {}