inspec 1.47.0 → 1.48.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +32 -15
- data/Gemfile +1 -1
- data/inspec.gemspec +1 -2
- data/lib/inspec/backend.rb +4 -1
- data/lib/inspec/base_cli.rb +27 -8
- data/lib/inspec/cli.rb +3 -2
- data/lib/inspec/control_eval_context.rb +8 -3
- data/lib/inspec/profile.rb +2 -1
- data/lib/inspec/profile_context.rb +4 -2
- data/lib/inspec/rspec_json_formatter.rb +2 -2
- data/lib/inspec/rule.rb +4 -1
- data/lib/inspec/version.rb +1 -1
- data/lib/resources/command.rb +3 -3
- data/lib/resources/crontab.rb +101 -34
- metadata +10 -18
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '012308b85533b4379b4dae9b2d6bb956e4716dea'
|
|
4
|
+
data.tar.gz: a621d9a79814290988494ec07da9bad51057f33b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 93b4c27033acdb1e4559c48940d0c73b1d94b3b20e109ed6a3b2ecf57908143b8c133717790ff273253aa580d893ee3ecd9a75e1129d9125bbc64f2c7c2d8397
|
|
7
|
+
data.tar.gz: 8eb7fe1e83c0bba17b5ef763015c83be4952c622e80a80af68a702d829d78bed389864157cdee86352f4ae166213ddc17b4fd5fbd5455719c89c8efc3de77a30
|
data/CHANGELOG.md
CHANGED
|
@@ -1,29 +1,47 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
<!-- usage documentation: http://expeditor-docs.es.chef.io/configuration/changelog/ -->
|
|
3
|
-
<!-- latest_release 1.
|
|
4
|
-
## [v1.
|
|
3
|
+
<!-- latest_release 1.48.0 -->
|
|
4
|
+
## [v1.48.0](https://github.com/chef/inspec/tree/v1.48.0) (2017-12-07)
|
|
5
5
|
|
|
6
|
-
####
|
|
7
|
-
-
|
|
6
|
+
#### Merged Pull Requests
|
|
7
|
+
- Fix changelog categories, bump minor version for release [#2381](https://github.com/chef/inspec/pull/2381) ([adamleff](https://github.com/adamleff))
|
|
8
8
|
<!-- latest_release -->
|
|
9
9
|
|
|
10
|
-
<!-- release_rollup since=1.
|
|
11
|
-
### Changes since 1.
|
|
10
|
+
<!-- release_rollup since=1.47.0 -->
|
|
11
|
+
### Changes since 1.47.0 release
|
|
12
12
|
|
|
13
|
-
####
|
|
14
|
-
-
|
|
13
|
+
#### Enhancements
|
|
14
|
+
- Allow crontab resource to read crontab at user specified paths. [#2328](https://github.com/chef/inspec/pull/2328) ([miah](https://github.com/miah)) <!-- 1.47.7 -->
|
|
15
|
+
- Update default cli options to be uniq per command type [#2378](https://github.com/chef/inspec/pull/2378) ([jquick](https://github.com/jquick)) <!-- 1.47.6 -->
|
|
16
|
+
|
|
17
|
+
#### Bug Fixes
|
|
18
|
+
- Allow `inspec check` to ignore `only_if` [#2250](https://github.com/chef/inspec/pull/2250) ([jerryaldrichiii](https://github.com/jerryaldrichiii)) <!-- 1.47.2 -->
|
|
19
|
+
- Remove rainbow dependency, fix duplicate rake gem [#2374](https://github.com/chef/inspec/pull/2374) ([adamleff](https://github.com/adamleff)) <!-- 1.47.8 -->
|
|
20
|
+
- Resolve merge issue with json-config vs thor defaults [#2377](https://github.com/chef/inspec/pull/2377) ([jquick](https://github.com/jquick)) <!-- 1.47.5 -->
|
|
21
|
+
- Update rspec cli control summary to not uniq fails/skips [#2362](https://github.com/chef/inspec/pull/2362) ([jquick](https://github.com/jquick)) <!-- 1.47.1 -->
|
|
15
22
|
|
|
16
23
|
#### Merged Pull Requests
|
|
17
|
-
-
|
|
24
|
+
- Fix changelog categories, bump minor version for release [#2381](https://github.com/chef/inspec/pull/2381) ([adamleff](https://github.com/adamleff)) <!-- 1.48.0 -->
|
|
25
|
+
- Fix inspec appveyor test with the new local train transport [#2376](https://github.com/chef/inspec/pull/2376) ([jquick](https://github.com/jquick)) <!-- 1.47.4 -->
|
|
26
|
+
- Update command resource to check for mock backend [#2353](https://github.com/chef/inspec/pull/2353) ([jquick](https://github.com/jquick)) <!-- 1.47.3 -->
|
|
27
|
+
<!-- release_rollup -->
|
|
28
|
+
|
|
29
|
+
<!-- latest_stable_release -->
|
|
30
|
+
## [v1.47.0](https://github.com/chef/inspec/tree/v1.47.0) (2017-12-04)
|
|
31
|
+
|
|
32
|
+
#### New Features
|
|
33
|
+
- Enable caching for backend calls [#2309](https://github.com/chef/inspec/pull/2309) ([jquick](https://github.com/jquick))
|
|
18
34
|
|
|
19
35
|
#### Bug Fixes
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
<!-- release_rollup -->
|
|
36
|
+
- Unique export file for security policy resource [#2350](https://github.com/chef/inspec/pull/2350) ([jquick](https://github.com/jquick))
|
|
37
|
+
- json resource: ensure params is not nil in event of read/parse failure [#2354](https://github.com/chef/inspec/pull/2354) ([adamleff](https://github.com/adamleff))
|
|
38
|
+
- key_rsa resource: fix inline shell documentation help, wrong resource name used in examples [#2364](https://github.com/chef/inspec/pull/2364) ([eramoto](https://github.com/eramoto))
|
|
39
|
+
- security_policy resource: use PID for filename instead of random [#2368](https://github.com/chef/inspec/pull/2368) ([jquick](https://github.com/jquick))
|
|
25
40
|
|
|
41
|
+
#### Merged Pull Requests
|
|
42
|
+
- docker_image resource: properly handle registries in image strings [#2356](https://github.com/chef/inspec/pull/2356) ([adamleff](https://github.com/adamleff))
|
|
26
43
|
<!-- latest_stable_release -->
|
|
44
|
+
|
|
27
45
|
## [v1.46.2](https://github.com/chef/inspec/tree/v1.46.2) (2017-11-29)
|
|
28
46
|
|
|
29
47
|
#### Enhancements
|
|
@@ -36,7 +54,6 @@
|
|
|
36
54
|
- file resource: fix NilClass error when using advanced windows permissions [#2344](https://github.com/chef/inspec/pull/2344) ([TheLonelyGhost](https://github.com/TheLonelyGhost))
|
|
37
55
|
- wmi resource: properly escape quotes in WMI query [#2342](https://github.com/chef/inspec/pull/2342) ([TheLonelyGhost](https://github.com/TheLonelyGhost))
|
|
38
56
|
- Allow skipping/failing resources in FilterTable [#2349](https://github.com/chef/inspec/pull/2349) ([jerryaldrichiii](https://github.com/jerryaldrichiii))
|
|
39
|
-
<!-- latest_stable_release -->
|
|
40
57
|
|
|
41
58
|
## [v1.45.13](https://github.com/chef/inspec/tree/v1.45.13) (2017-11-21)
|
|
42
59
|
|
data/Gemfile
CHANGED
data/inspec.gemspec
CHANGED
|
@@ -26,10 +26,9 @@ Gem::Specification.new do |spec|
|
|
|
26
26
|
|
|
27
27
|
spec.required_ruby_version = '>= 2.3'
|
|
28
28
|
|
|
29
|
-
spec.add_dependency 'train', '~> 0.
|
|
29
|
+
spec.add_dependency 'train', '~> 0.31', '>= 0.31.1'
|
|
30
30
|
spec.add_dependency 'thor', '~> 0.19'
|
|
31
31
|
spec.add_dependency 'json', '>= 1.8', '< 3.0'
|
|
32
|
-
spec.add_dependency 'rainbow', '~> 2'
|
|
33
32
|
spec.add_dependency 'method_source', '~> 0.8'
|
|
34
33
|
spec.add_dependency 'rubyzip', '~> 1.1'
|
|
35
34
|
spec.add_dependency 'rspec', '~> 3'
|
data/lib/inspec/backend.rb
CHANGED
|
@@ -40,7 +40,7 @@ module Inspec
|
|
|
40
40
|
#
|
|
41
41
|
# @param [Hash] config for the transport backend
|
|
42
42
|
# @return [TransportBackend] enriched transport instance
|
|
43
|
-
def self.create(config)
|
|
43
|
+
def self.create(config) # rubocop:disable Metrics/AbcSize
|
|
44
44
|
conf = Train.target_config(config)
|
|
45
45
|
name = Train.validate_backend(conf)
|
|
46
46
|
transport = Train.create(name, conf)
|
|
@@ -56,12 +56,15 @@ module Inspec
|
|
|
56
56
|
# Set caching settings. We always want to enable caching for
|
|
57
57
|
# the Mock transport for testing.
|
|
58
58
|
if config[:backend_cache] || config[:backend] == :mock
|
|
59
|
+
Inspec::Log.debug 'Option backend_cache is enabled'
|
|
59
60
|
connection.enable_cache(:file)
|
|
60
61
|
connection.enable_cache(:command)
|
|
61
62
|
elsif config[:debug_shell]
|
|
63
|
+
Inspec::Log.debug 'Option backend_cache is disabled'
|
|
62
64
|
connection.disable_cache(:file)
|
|
63
65
|
connection.disable_cache(:command)
|
|
64
66
|
else
|
|
67
|
+
Inspec::Log.debug 'Option backend_cache is disabled'
|
|
65
68
|
connection.disable_cache(:command)
|
|
66
69
|
end
|
|
67
70
|
|
data/lib/inspec/base_cli.rb
CHANGED
|
@@ -59,18 +59,28 @@ module Inspec
|
|
|
59
59
|
desc: 'A list of controls to run. Ignore all other tests.'
|
|
60
60
|
option :format, type: :string,
|
|
61
61
|
desc: 'Which formatter to use: cli, progress, documentation, json, json-min, junit'
|
|
62
|
-
option :color, type: :boolean,
|
|
62
|
+
option :color, type: :boolean,
|
|
63
63
|
desc: 'Use colors in output.'
|
|
64
64
|
option :attrs, type: :array,
|
|
65
65
|
desc: 'Load attributes file (experimental)'
|
|
66
66
|
option :cache, type: :string,
|
|
67
67
|
desc: 'Use the given path for caching dependencies. (default: ~/.inspec/cache)'
|
|
68
|
-
option :create_lockfile, type: :boolean,
|
|
68
|
+
option :create_lockfile, type: :boolean,
|
|
69
69
|
desc: 'Write out a lockfile based on this execution (unless one already exists)'
|
|
70
|
-
option :backend_cache, type: :boolean,
|
|
70
|
+
option :backend_cache, type: :boolean,
|
|
71
71
|
desc: 'Allow caching for backend command output.'
|
|
72
72
|
end
|
|
73
73
|
|
|
74
|
+
def self.default_options
|
|
75
|
+
{
|
|
76
|
+
exec: {
|
|
77
|
+
'color' => true,
|
|
78
|
+
'create_lockfile' => true,
|
|
79
|
+
'backend_cache' => false,
|
|
80
|
+
},
|
|
81
|
+
}
|
|
82
|
+
end
|
|
83
|
+
|
|
74
84
|
private
|
|
75
85
|
|
|
76
86
|
# helper method to run tests
|
|
@@ -101,8 +111,8 @@ module Inspec
|
|
|
101
111
|
puts
|
|
102
112
|
end
|
|
103
113
|
|
|
104
|
-
def opts
|
|
105
|
-
o = merged_opts
|
|
114
|
+
def opts(type = nil)
|
|
115
|
+
o = merged_opts(type)
|
|
106
116
|
|
|
107
117
|
# Due to limitations in Thor it is not possible to set an argument to be
|
|
108
118
|
# both optional and its value to be mandatory. E.g. the user supplying
|
|
@@ -118,9 +128,18 @@ module Inspec
|
|
|
118
128
|
o
|
|
119
129
|
end
|
|
120
130
|
|
|
121
|
-
def merged_opts
|
|
122
|
-
|
|
123
|
-
|
|
131
|
+
def merged_opts(type = nil)
|
|
132
|
+
opts = {}
|
|
133
|
+
|
|
134
|
+
# start with default options if we have any
|
|
135
|
+
opts = BaseCLI.default_options[type] unless type.nil?
|
|
136
|
+
|
|
137
|
+
# merge in any options from json-config
|
|
138
|
+
opts.merge!(options_json)
|
|
139
|
+
|
|
140
|
+
# merge in any options defined via thor
|
|
141
|
+
opts.merge!(options)
|
|
142
|
+
Thor::CoreExt::HashWithIndifferentAccess.new(opts)
|
|
124
143
|
end
|
|
125
144
|
|
|
126
145
|
def options_json
|
data/lib/inspec/cli.rb
CHANGED
|
@@ -62,6 +62,7 @@ class Inspec::InspecCLI < Inspec::BaseCLI # rubocop:disable Metrics/ClassLength
|
|
|
62
62
|
o = opts.dup
|
|
63
63
|
o[:ignore_supports] = true # we check for integrity only
|
|
64
64
|
o[:backend] = Inspec::Backend.create(target: 'mock://')
|
|
65
|
+
o[:check_mode] = true
|
|
65
66
|
|
|
66
67
|
# run check
|
|
67
68
|
profile = Inspec::Profile.for_target(path, o)
|
|
@@ -151,8 +152,8 @@ class Inspec::InspecCLI < Inspec::BaseCLI # rubocop:disable Metrics/ClassLength
|
|
|
151
152
|
exec_options
|
|
152
153
|
def exec(*targets)
|
|
153
154
|
diagnose
|
|
154
|
-
|
|
155
|
-
o
|
|
155
|
+
o = opts(:exec).dup
|
|
156
|
+
configure_logger(o)
|
|
156
157
|
|
|
157
158
|
# run tests
|
|
158
159
|
run_tests(targets, o)
|
|
@@ -13,7 +13,7 @@ module Inspec
|
|
|
13
13
|
# as the basic DSL of the control files (describe, control, title,
|
|
14
14
|
# etc).
|
|
15
15
|
#
|
|
16
|
-
class ControlEvalContext
|
|
16
|
+
class ControlEvalContext # rubocop:disable Metrics/ClassLength
|
|
17
17
|
# Create the context for controls. This includes all components of the DSL,
|
|
18
18
|
# including matchers and resources.
|
|
19
19
|
#
|
|
@@ -47,12 +47,13 @@ module Inspec
|
|
|
47
47
|
|
|
48
48
|
attr_accessor :skip_file
|
|
49
49
|
|
|
50
|
-
def initialize(backend, conf, dependencies, require_loader)
|
|
50
|
+
def initialize(backend, conf, dependencies, require_loader, skip_only_if_eval)
|
|
51
51
|
@backend = backend
|
|
52
52
|
@conf = conf
|
|
53
53
|
@dependencies = dependencies
|
|
54
54
|
@require_loader = require_loader
|
|
55
55
|
@skip_file = false
|
|
56
|
+
@skip_only_if_eval = skip_only_if_eval
|
|
56
57
|
end
|
|
57
58
|
|
|
58
59
|
define_method :title do |arg|
|
|
@@ -70,6 +71,7 @@ module Inspec
|
|
|
70
71
|
define_method :control do |*args, &block|
|
|
71
72
|
id = args[0]
|
|
72
73
|
opts = args[1] || {}
|
|
74
|
+
opts[:skip_only_if_eval] = @skip_only_if_eval
|
|
73
75
|
register_control(rule_class.new(id, profile_id, opts, &block))
|
|
74
76
|
end
|
|
75
77
|
|
|
@@ -133,7 +135,10 @@ module Inspec
|
|
|
133
135
|
|
|
134
136
|
define_method :only_if do |&block|
|
|
135
137
|
return unless block
|
|
136
|
-
return if @skip_file == true
|
|
138
|
+
return if @skip_file == true
|
|
139
|
+
return if @skip_only_if_eval == true
|
|
140
|
+
|
|
141
|
+
return if block.yield == true
|
|
137
142
|
|
|
138
143
|
# Apply `set_skip_rule` for other rules in the same file
|
|
139
144
|
profile_context_owner.rules.values.each do |r|
|
data/lib/inspec/profile.rb
CHANGED
|
@@ -78,7 +78,7 @@ module Inspec
|
|
|
78
78
|
for_fetcher(fetcher, opts)
|
|
79
79
|
end
|
|
80
80
|
|
|
81
|
-
attr_reader :source_reader, :backend, :runner_context
|
|
81
|
+
attr_reader :source_reader, :backend, :runner_context, :check_mode
|
|
82
82
|
def_delegator :@source_reader, :tests
|
|
83
83
|
def_delegator :@source_reader, :libraries
|
|
84
84
|
def_delegator :@source_reader, :metadata
|
|
@@ -96,6 +96,7 @@ module Inspec
|
|
|
96
96
|
@attr_values = options[:attributes]
|
|
97
97
|
@tests_collected = false
|
|
98
98
|
@libraries_loaded = false
|
|
99
|
+
@check_mode = options[:check_mode] || false
|
|
99
100
|
Metadata.finalize(@source_reader.metadata, @profile_id, options)
|
|
100
101
|
|
|
101
102
|
# if a backend has already been created, clone it so each profile has its own unique backend object
|
|
@@ -14,7 +14,8 @@ module Inspec
|
|
|
14
14
|
class ProfileContext # rubocop:disable Metrics/ClassLength
|
|
15
15
|
def self.for_profile(profile, backend, attributes)
|
|
16
16
|
new(profile.name, backend, { 'profile' => profile,
|
|
17
|
-
'attributes' => attributes
|
|
17
|
+
'attributes' => attributes,
|
|
18
|
+
'check_mode' => profile.check_mode })
|
|
18
19
|
end
|
|
19
20
|
|
|
20
21
|
attr_reader :attributes, :profile_id, :resource_registry, :backend
|
|
@@ -27,6 +28,7 @@ module Inspec
|
|
|
27
28
|
@profile_id = profile_id
|
|
28
29
|
@backend = backend
|
|
29
30
|
@conf = conf.dup
|
|
31
|
+
@skip_only_if_eval = @conf['check_mode']
|
|
30
32
|
@rules = {}
|
|
31
33
|
@control_subcontexts = []
|
|
32
34
|
@lib_subcontexts = []
|
|
@@ -53,7 +55,7 @@ module Inspec
|
|
|
53
55
|
def control_eval_context
|
|
54
56
|
@control_eval_context ||= begin
|
|
55
57
|
ctx = Inspec::ControlEvalContext.create(self, to_resources_dsl)
|
|
56
|
-
ctx.new(@backend, @conf, dependencies, @require_loader)
|
|
58
|
+
ctx.new(@backend, @conf, dependencies, @require_loader, @skip_only_if_eval)
|
|
57
59
|
end
|
|
58
60
|
end
|
|
59
61
|
|
|
@@ -776,8 +776,8 @@ class InspecRspecCli < InspecRspecJson # rubocop:disable Metrics/ClassLength
|
|
|
776
776
|
examples[0][:message].to_s
|
|
777
777
|
else
|
|
778
778
|
[
|
|
779
|
-
!fails.empty? ? "#{fails.
|
|
780
|
-
!skips.empty? ? "#{skips.
|
|
779
|
+
!fails.empty? ? "#{fails.length} failed" : nil,
|
|
780
|
+
!skips.empty? ? "#{skips.length} skipped" : nil,
|
|
781
781
|
].compact.join(' ')
|
|
782
782
|
end
|
|
783
783
|
|
data/lib/inspec/rule.rb
CHANGED
|
@@ -29,7 +29,7 @@ module Inspec
|
|
|
29
29
|
@resource_dsl
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
-
def initialize(id, profile_id,
|
|
32
|
+
def initialize(id, profile_id, opts, &block)
|
|
33
33
|
@impact = nil
|
|
34
34
|
@title = nil
|
|
35
35
|
@desc = nil
|
|
@@ -44,6 +44,7 @@ module Inspec
|
|
|
44
44
|
@__checks = []
|
|
45
45
|
@__skip_rule = nil
|
|
46
46
|
@__merge_count = 0
|
|
47
|
+
@__skip_only_if_eval = opts[:skip_only_if_eval]
|
|
47
48
|
|
|
48
49
|
# evaluate the given definition
|
|
49
50
|
instance_eval(&block) if block_given?
|
|
@@ -104,6 +105,8 @@ module Inspec
|
|
|
104
105
|
# @return [nil]
|
|
105
106
|
def only_if
|
|
106
107
|
return unless block_given?
|
|
108
|
+
return if @__skip_only_if_eval == true
|
|
109
|
+
|
|
107
110
|
@__skip_rule ||= !yield
|
|
108
111
|
end
|
|
109
112
|
|
data/lib/inspec/version.rb
CHANGED
data/lib/resources/command.rb
CHANGED
|
@@ -45,9 +45,9 @@ module Inspec::Resources
|
|
|
45
45
|
result.exit_status.to_i
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
-
def exist?
|
|
48
|
+
def exist? # rubocop:disable Metrics/AbcSize
|
|
49
49
|
# silent for mock resources
|
|
50
|
-
return false if inspec.os.name.nil?
|
|
50
|
+
return false if inspec.os.name.nil? || inspec.os.name == 'mock'
|
|
51
51
|
|
|
52
52
|
if inspec.os.linux?
|
|
53
53
|
res = inspec.backend.run_command("bash -c 'type \"#{@command}\"'")
|
|
@@ -56,7 +56,7 @@ module Inspec::Resources
|
|
|
56
56
|
elsif inspec.os.unix?
|
|
57
57
|
res = inspec.backend.run_command("type \"#{@command}\"")
|
|
58
58
|
else
|
|
59
|
-
warn "`command(#{@command}).exist?` is not
|
|
59
|
+
warn "`command(#{@command}).exist?` is not supported on your OS: #{inspec.os[:name]}"
|
|
60
60
|
return false
|
|
61
61
|
end
|
|
62
62
|
res.exit_status.to_i == 0
|
data/lib/resources/crontab.rb
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
|
-
# author: Adam Leff
|
|
3
2
|
|
|
4
3
|
require 'utils/parser'
|
|
5
4
|
require 'utils/filter'
|
|
6
5
|
|
|
7
6
|
module Inspec::Resources
|
|
8
|
-
class Crontab < Inspec.resource(1)
|
|
7
|
+
class Crontab < Inspec.resource(1) # rubocop:disable Metrics/ClassLength
|
|
9
8
|
name 'crontab'
|
|
10
9
|
desc 'Use the crontab InSpec audit resource to test the contents of the crontab for a given user which contains information about scheduled tasks owned by that user.'
|
|
11
10
|
example "
|
|
12
|
-
describe crontab('root') do
|
|
11
|
+
describe crontab(user: 'root') do
|
|
13
12
|
its('commands') { should include '/path/to/some/script' }
|
|
14
13
|
end
|
|
15
14
|
|
|
@@ -25,51 +24,40 @@ module Inspec::Resources
|
|
|
25
24
|
describe crontab.where { command =~ /a partial command string/ } do
|
|
26
25
|
its('entries.length') { should cmp 1 }
|
|
27
26
|
end
|
|
27
|
+
|
|
28
|
+
describe crontab(path: '/etc/cron.d/some_crontab') do
|
|
29
|
+
its('commands') { should include '/path/to/some/script' }
|
|
30
|
+
end
|
|
28
31
|
"
|
|
29
32
|
|
|
30
33
|
attr_reader :params
|
|
31
34
|
|
|
32
35
|
include CommentParser
|
|
33
36
|
|
|
34
|
-
def initialize(
|
|
35
|
-
|
|
37
|
+
def initialize(opts = nil)
|
|
38
|
+
if opts.respond_to?(:fetch)
|
|
39
|
+
Hash[opts.map { |k, v| [k.to_sym, v] }]
|
|
40
|
+
@user = opts.fetch(:user, nil)
|
|
41
|
+
@path = opts.fetch(:path, nil)
|
|
42
|
+
raise Inspec::Exceptions::ResourceFailed, 'A user or path must be supplied.' if @user.nil? && @path.nil?
|
|
43
|
+
else
|
|
44
|
+
@user = opts
|
|
45
|
+
@path = nil
|
|
46
|
+
end
|
|
47
|
+
raise Inspec::Exceptions::ResourceSkipped, 'The `crontab` resource is not supported on your OS.' unless inspec.os.unix?
|
|
36
48
|
@params = read_crontab
|
|
37
|
-
|
|
38
|
-
return skip_resource 'The `crontab` resource is not supported on your OS.' unless inspec.os.unix?
|
|
39
49
|
end
|
|
40
50
|
|
|
41
51
|
def read_crontab
|
|
42
|
-
inspec.
|
|
52
|
+
ct = is_system_crontab? ? inspec.file(@path).content : inspec.command(crontab_cmd).stdout
|
|
53
|
+
ct.lines.map { |l| parse_crontab_line(l) }.compact
|
|
43
54
|
end
|
|
44
55
|
|
|
45
56
|
def parse_crontab_line(l)
|
|
46
57
|
data, = parse_comment_line(l, comment_char: '#', standalone_comments: false)
|
|
47
58
|
return nil if data.nil? || data.empty?
|
|
48
59
|
|
|
49
|
-
|
|
50
|
-
when /@hourly .*/
|
|
51
|
-
{ 'minute' => '0', 'hour' => '*', 'day' => '*', 'month' => '*', 'weekday' => '*', 'command' => data.split(/\s+/, 2).at(1) }
|
|
52
|
-
when /@(midnight|daily) .*/
|
|
53
|
-
{ 'minute' => '0', 'hour' => '0', 'day' => '*', 'month' => '*', 'weekday' => '*', 'command' => data.split(/\s+/, 2).at(1) }
|
|
54
|
-
when /@weekly .*/
|
|
55
|
-
{ 'minute' => '0', 'hour' => '0', 'day' => '*', 'month' => '*', 'weekday' => '0', 'command' => data.split(/\s+/, 2).at(1) }
|
|
56
|
-
when /@monthly ./
|
|
57
|
-
{ 'minute' => '0', 'hour' => '0', 'day' => '1', 'month' => '*', 'weekday' => '*', 'command' => data.split(/\s+/, 2).at(1) }
|
|
58
|
-
when /@(annually|yearly) .*/
|
|
59
|
-
{ 'minute' => '0', 'hour' => '0', 'day' => '1', 'month' => '1', 'weekday' => '*', 'command' => data.split(/\s+/, 2).at(1) }
|
|
60
|
-
when /@reboot .*/
|
|
61
|
-
{ 'minute' => '-1', 'hour' => '-1', 'day' => '-1', 'month' => '-1', 'weekday' => '-1', 'command' => data.split(/\s+/, 2).at(1) }
|
|
62
|
-
else
|
|
63
|
-
elements = data.split(/\s+/, 6)
|
|
64
|
-
{
|
|
65
|
-
'minute' => elements.at(0),
|
|
66
|
-
'hour' => elements.at(1),
|
|
67
|
-
'day' => elements.at(2),
|
|
68
|
-
'month' => elements.at(3),
|
|
69
|
-
'weekday' => elements.at(4),
|
|
70
|
-
'command' => elements.at(5),
|
|
71
|
-
}
|
|
72
|
-
end
|
|
60
|
+
is_system_crontab? ? parse_system_crontab(data) : parse_user_crontab(data)
|
|
73
61
|
end
|
|
74
62
|
|
|
75
63
|
def crontab_cmd
|
|
@@ -84,19 +72,98 @@ module Inspec::Resources
|
|
|
84
72
|
.add(:days, field: 'day')
|
|
85
73
|
.add(:months, field: 'month')
|
|
86
74
|
.add(:weekdays, field: 'weekday')
|
|
75
|
+
.add(:user, field: 'user')
|
|
87
76
|
.add(:commands, field: 'command')
|
|
88
77
|
|
|
89
78
|
# rebuild the crontab line from raw content
|
|
90
79
|
filter.add(:content) { |t, _|
|
|
91
80
|
t.entries.map do |e|
|
|
92
|
-
[e.minute, e.hour, e.day, e.month, e.weekday, e.command].join(' ')
|
|
81
|
+
[e.minute, e.hour, e.day, e.month, e.weekday, e.user, e.command].compact.join(' ')
|
|
93
82
|
end.join("\n")
|
|
94
83
|
}
|
|
95
84
|
|
|
96
85
|
filter.connect(self, :params)
|
|
97
86
|
|
|
98
87
|
def to_s
|
|
99
|
-
|
|
88
|
+
if is_system_crontab?
|
|
89
|
+
"crontab for path #{@path}"
|
|
90
|
+
elsif is_user_crontab?
|
|
91
|
+
"crontab for user #{@user}"
|
|
92
|
+
else
|
|
93
|
+
'crontab for current user'
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
private
|
|
98
|
+
|
|
99
|
+
def is_system_crontab?
|
|
100
|
+
!@path.nil?
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def is_user_crontab?
|
|
104
|
+
!@user.nil?
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def parse_system_crontab(data)
|
|
108
|
+
case data
|
|
109
|
+
when /@hourly .*/
|
|
110
|
+
elements = data.split(/\s+/, 3)
|
|
111
|
+
{ 'minute' => '0', 'hour' => '*', 'day' => '*', 'month' => '*', 'weekday' => '*', 'user' => elements.at(1), 'command' => elements.at(2) }
|
|
112
|
+
when /@(midnight|daily) .*/
|
|
113
|
+
elements = data.split(/\s+/, 3)
|
|
114
|
+
{ 'minute' => '0', 'hour' => '0', 'day' => '*', 'month' => '*', 'weekday' => '*', 'user' => elements.at(1), 'command' => elements.at(2) }
|
|
115
|
+
when /@weekly .*/
|
|
116
|
+
elements = data.split(/\s+/, 3)
|
|
117
|
+
{ 'minute' => '0', 'hour' => '0', 'day' => '*', 'month' => '*', 'weekday' => '0', 'user' => elements.at(1), 'command' => elements.at(2) }
|
|
118
|
+
when /@monthly ./
|
|
119
|
+
elements = data.split(/\s+/, 3)
|
|
120
|
+
{ 'minute' => '0', 'hour' => '0', 'day' => '1', 'month' => '*', 'weekday' => '*', 'user' => elements.at(1), 'command' => elements.at(2) }
|
|
121
|
+
when /@(annually|yearly) .*/
|
|
122
|
+
elements = data.split(/\s+/, 3)
|
|
123
|
+
{ 'minute' => '0', 'hour' => '0', 'day' => '1', 'month' => '1', 'weekday' => '*', 'user' => elements.at(1), 'command' => elements.at(2) }
|
|
124
|
+
when /@reboot .*/
|
|
125
|
+
elements = data.split(/\s+/, 3)
|
|
126
|
+
{ 'minute' => '-1', 'hour' => '-1', 'day' => '-1', 'month' => '-1', 'weekday' => '-1', 'user' => elements.at(1), 'command' => elements.at(2) }
|
|
127
|
+
else
|
|
128
|
+
elements = data.split(/\s+/, 7)
|
|
129
|
+
{
|
|
130
|
+
'minute' => elements.at(0),
|
|
131
|
+
'hour' => elements.at(1),
|
|
132
|
+
'day' => elements.at(2),
|
|
133
|
+
'month' => elements.at(3),
|
|
134
|
+
'weekday' => elements.at(4),
|
|
135
|
+
'user' => elements.at(5),
|
|
136
|
+
'command' => elements.at(6),
|
|
137
|
+
}
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def parse_user_crontab(data)
|
|
142
|
+
case data
|
|
143
|
+
when /@hourly .*/
|
|
144
|
+
{ 'minute' => '0', 'hour' => '*', 'day' => '*', 'month' => '*', 'weekday' => '*', 'user' => @user, 'command' => data.split(/\s+/, 2).at(1) }
|
|
145
|
+
when /@(midnight|daily) .*/
|
|
146
|
+
{ 'minute' => '0', 'hour' => '0', 'day' => '*', 'month' => '*', 'weekday' => '*', 'user' => @user, 'command' => data.split(/\s+/, 2).at(1) }
|
|
147
|
+
when /@weekly .*/
|
|
148
|
+
{ 'minute' => '0', 'hour' => '0', 'day' => '*', 'month' => '*', 'weekday' => '0', 'user' => @user, 'command' => data.split(/\s+/, 2).at(1) }
|
|
149
|
+
when /@monthly ./
|
|
150
|
+
{ 'minute' => '0', 'hour' => '0', 'day' => '1', 'month' => '*', 'weekday' => '*', 'user' => @user, 'command' => data.split(/\s+/, 2).at(1) }
|
|
151
|
+
when /@(annually|yearly) .*/
|
|
152
|
+
{ 'minute' => '0', 'hour' => '0', 'day' => '1', 'month' => '1', 'weekday' => '*', 'user' => @user, 'command' => data.split(/\s+/, 2).at(1) }
|
|
153
|
+
when /@reboot .*/
|
|
154
|
+
{ 'minute' => '-1', 'hour' => '-1', 'day' => '-1', 'month' => '-1', 'weekday' => '-1', 'user' => @user, 'command' => data.split(/\s+/, 2).at(1) }
|
|
155
|
+
else
|
|
156
|
+
elements = data.split(/\s+/, 6)
|
|
157
|
+
{
|
|
158
|
+
'minute' => elements.at(0),
|
|
159
|
+
'hour' => elements.at(1),
|
|
160
|
+
'day' => elements.at(2),
|
|
161
|
+
'month' => elements.at(3),
|
|
162
|
+
'weekday' => elements.at(4),
|
|
163
|
+
'user' => @user,
|
|
164
|
+
'command' => elements.at(5),
|
|
165
|
+
}
|
|
166
|
+
end
|
|
100
167
|
end
|
|
101
168
|
end
|
|
102
169
|
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.
|
|
4
|
+
version: 1.48.0
|
|
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-12-
|
|
11
|
+
date: 2017-12-07 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: train
|
|
@@ -16,14 +16,20 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - "~>"
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '0.
|
|
19
|
+
version: '0.31'
|
|
20
|
+
- - ">="
|
|
21
|
+
- !ruby/object:Gem::Version
|
|
22
|
+
version: 0.31.1
|
|
20
23
|
type: :runtime
|
|
21
24
|
prerelease: false
|
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
26
|
requirements:
|
|
24
27
|
- - "~>"
|
|
25
28
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '0.
|
|
29
|
+
version: '0.31'
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: 0.31.1
|
|
27
33
|
- !ruby/object:Gem::Dependency
|
|
28
34
|
name: thor
|
|
29
35
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -58,20 +64,6 @@ dependencies:
|
|
|
58
64
|
- - "<"
|
|
59
65
|
- !ruby/object:Gem::Version
|
|
60
66
|
version: '3.0'
|
|
61
|
-
- !ruby/object:Gem::Dependency
|
|
62
|
-
name: rainbow
|
|
63
|
-
requirement: !ruby/object:Gem::Requirement
|
|
64
|
-
requirements:
|
|
65
|
-
- - "~>"
|
|
66
|
-
- !ruby/object:Gem::Version
|
|
67
|
-
version: '2'
|
|
68
|
-
type: :runtime
|
|
69
|
-
prerelease: false
|
|
70
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
71
|
-
requirements:
|
|
72
|
-
- - "~>"
|
|
73
|
-
- !ruby/object:Gem::Version
|
|
74
|
-
version: '2'
|
|
75
67
|
- !ruby/object:Gem::Dependency
|
|
76
68
|
name: method_source
|
|
77
69
|
requirement: !ruby/object:Gem::Requirement
|