inspec 1.14.1 → 1.15.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +38 -2
- data/docs/resources/crontab.md.erb +62 -0
- data/examples/inheritance/inspec.lock +2 -2
- data/examples/meta-profile/inspec.lock +1 -1
- data/examples/meta-profile/vendor/9ad48391d4e6efff0a13d06736c5b075fb021410e0a629e087bc21e9617d957c.tar.gz +0 -0
- data/inspec.gemspec +1 -0
- data/lib/bundles/inspec-habitat.rb +12 -0
- data/lib/bundles/inspec-habitat/cli.rb +32 -0
- data/lib/bundles/inspec-habitat/log.rb +10 -0
- data/lib/bundles/inspec-habitat/profile.rb +334 -0
- data/lib/inspec/metadata.rb +22 -4
- data/lib/inspec/profile.rb +10 -4
- data/lib/inspec/resource.rb +1 -0
- data/lib/inspec/rspec_json_formatter.rb +66 -23
- data/lib/inspec/shell.rb +15 -8
- data/lib/inspec/version.rb +1 -1
- data/lib/resources/crontab.rb +83 -0
- data/lib/resources/package.rb +1 -1
- data/lib/resources/packages.rb +42 -18
- data/lib/source_readers/inspec.rb +1 -1
- metadata +24 -6
- data/examples/meta-profile/vendor/793adcbb91cfc2da0044bb9cbf0863773ae2cf89ce9b8343b4295b137f70897b.tar.gz +0 -0
- data/examples/profile/inspec.lock +0 -3
- data/lib/resources/.ssh_conf.rb.swp +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6d6a9596b5e8f107982bbf0772679d92bd903b24
|
4
|
+
data.tar.gz: 87f6fd87e179535f8d78512cc6a35798076cb51f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 73b6a1520ce732b59972ab69a1de54febd1512d06cf3102d81ad678ad7bedf85755a214d1ddc803fe7deda9cf2b1f26c0abc49716281f2690f3c4514dea15f3f
|
7
|
+
data.tar.gz: 1333f99c255ff0853315186c023fa22d419a3a9ec1e770bc2e6983eed371a15d5f91f3d65ff889deead3cef15d7eec0641fb4b33dc72abaaa1f2c3346de0a173
|
data/CHANGELOG.md
CHANGED
@@ -1,7 +1,43 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
-
## [
|
4
|
-
[Full Changelog](https://github.com/chef/inspec/compare/v1.14.
|
3
|
+
## [v1.15.0](https://github.com/chef/inspec/tree/v1.15.0) (2017-02-27)
|
4
|
+
[Full Changelog](https://github.com/chef/inspec/compare/v1.14.1...v1.15.0)
|
5
|
+
|
6
|
+
**Implemented enhancements:**
|
7
|
+
|
8
|
+
- Wrong rendering of InSpec.io header [\#1421](https://github.com/chef/inspec/issues/1421)
|
9
|
+
|
10
|
+
**Fixed bugs:**
|
11
|
+
|
12
|
+
- New Inspec.io is crashing on Edge if window is resized to a smaller window [\#1420](https://github.com/chef/inspec/issues/1420)
|
13
|
+
|
14
|
+
**Closed issues:**
|
15
|
+
|
16
|
+
- Colours and symbols broken on Windows [\#1508](https://github.com/chef/inspec/issues/1508)
|
17
|
+
- be\_reacheable matcher for host resource should not always use ping on linux [\#1504](https://github.com/chef/inspec/issues/1504)
|
18
|
+
- Inspec login fails [\#1503](https://github.com/chef/inspec/issues/1503)
|
19
|
+
- Develop an inspec test for selinux [\#1496](https://github.com/chef/inspec/issues/1496)
|
20
|
+
- Inspec.io: Add webinar/notifications bar in index.html [\#1495](https://github.com/chef/inspec/issues/1495)
|
21
|
+
- Inspec.io: Try Demo Button Bug [\#1494](https://github.com/chef/inspec/issues/1494)
|
22
|
+
- \[chef-compliance\] Scan Report Calculations [\#1491](https://github.com/chef/inspec/issues/1491)
|
23
|
+
- Create url for demo that can be pointed to from outbound campaigns [\#1485](https://github.com/chef/inspec/issues/1485)
|
24
|
+
- After inspec update from 1.5 to 1.10 it breaks with \[undefined method `\[\]=' for nil:NilClass\] [\#1456](https://github.com/chef/inspec/issues/1456)
|
25
|
+
- Inspec.io and IE11 [\#1437](https://github.com/chef/inspec/issues/1437)
|
26
|
+
- Link to robert\_config.rb is broken on inspec.io [\#1226](https://github.com/chef/inspec/issues/1226)
|
27
|
+
|
28
|
+
**Merged pull requests:**
|
29
|
+
|
30
|
+
- Fix formatting and colors on Windows [\#1510](https://github.com/chef/inspec/pull/1510) ([trickyearlobe](https://github.com/trickyearlobe))
|
31
|
+
- Adding a Habitat profile artifact creator [\#1505](https://github.com/chef/inspec/pull/1505) ([adamleff](https://github.com/adamleff))
|
32
|
+
- create inspec.io/tutorial.html [\#1490](https://github.com/chef/inspec/pull/1490) ([arlimus](https://github.com/arlimus))
|
33
|
+
- Doc fix for SourceReaders::InspecReader [\#1489](https://github.com/chef/inspec/pull/1489) ([adamleff](https://github.com/adamleff))
|
34
|
+
- Generate default profile names, fix bug when using multiple flat profiles [\#1488](https://github.com/chef/inspec/pull/1488) ([adamleff](https://github.com/adamleff))
|
35
|
+
- Packages resource support for RedHat [\#1487](https://github.com/chef/inspec/pull/1487) ([alexpop](https://github.com/alexpop))
|
36
|
+
- Adding new crontab resource [\#1482](https://github.com/chef/inspec/pull/1482) ([adamleff](https://github.com/adamleff))
|
37
|
+
- Provide target info on shell invocation [\#1475](https://github.com/chef/inspec/pull/1475) ([adamleff](https://github.com/adamleff))
|
38
|
+
|
39
|
+
## [v1.14.1](https://github.com/chef/inspec/tree/v1.14.1) (2017-02-10)
|
40
|
+
[Full Changelog](https://github.com/chef/inspec/compare/v1.14.0...v1.14.1)
|
5
41
|
|
6
42
|
**Closed issues:**
|
7
43
|
|
@@ -0,0 +1,62 @@
|
|
1
|
+
---
|
2
|
+
title: About the crontab Resource
|
3
|
+
---
|
4
|
+
|
5
|
+
# crontab
|
6
|
+
|
7
|
+
Use the `crontab` InSpec audit resource to test the crontab entries for a particular user on the system.
|
8
|
+
|
9
|
+
## Syntax
|
10
|
+
|
11
|
+
A `crontab` resource block declares a user (which defaults to the current user, if not specified), and then the details to be tested, such as the schedule elements for each crontab entry or the commands itself:
|
12
|
+
|
13
|
+
describe crontab do
|
14
|
+
its('commands') { should include '/some/scheduled/task.sh' }
|
15
|
+
end
|
16
|
+
|
17
|
+
## Matchers
|
18
|
+
|
19
|
+
This InSpec audit resource has the following matchers:
|
20
|
+
|
21
|
+
### be
|
22
|
+
|
23
|
+
<%= partial "/shared/matcher_be" %>
|
24
|
+
|
25
|
+
### cmp
|
26
|
+
|
27
|
+
<%= partial "/shared/matcher_cmp" %>
|
28
|
+
|
29
|
+
### eq
|
30
|
+
|
31
|
+
<%= partial "/shared/matcher_eq" %>
|
32
|
+
|
33
|
+
### include
|
34
|
+
|
35
|
+
<%= partial "/shared/matcher_include" %>
|
36
|
+
|
37
|
+
### match
|
38
|
+
|
39
|
+
<%= partial "/shared/matcher_match" %>
|
40
|
+
|
41
|
+
## Examples
|
42
|
+
|
43
|
+
The following examples show how to use this InSpec audit resource.
|
44
|
+
|
45
|
+
### Test that root's crontab has a particular command
|
46
|
+
|
47
|
+
describe crontab('root') do
|
48
|
+
its('commands') { should include '/path/to/some/script' }
|
49
|
+
end
|
50
|
+
|
51
|
+
### Test that myuser's crontab entry for command '/home/myuser/build.sh' runs every minute
|
52
|
+
|
53
|
+
describe crontab('myuser').commands('/home/myuser/build.sh') do
|
54
|
+
its('hours') { should cmp '*' }
|
55
|
+
its('minutes') { should cmp '*' }
|
56
|
+
end
|
57
|
+
|
58
|
+
### Test that the logged-in user's crontab has no tasks set to run on every hour and every minute
|
59
|
+
|
60
|
+
describe crontab.where({'hour' => '*', 'minute' => '*'}) do
|
61
|
+
its('entries.length') { should cmp '0' }
|
62
|
+
end
|
@@ -3,9 +3,9 @@ lockfile_version: 1
|
|
3
3
|
depends:
|
4
4
|
- name: profile
|
5
5
|
resolved_source:
|
6
|
-
path: "/
|
6
|
+
path: "/Users/aleff/projects/inspec/examples/profile"
|
7
7
|
version_constraints: ">= 0"
|
8
8
|
- name: profile-attribute
|
9
9
|
resolved_source:
|
10
|
-
path: "/
|
10
|
+
path: "/Users/aleff/projects/inspec/examples/profile-attribute"
|
11
11
|
version_constraints: ">= 0"
|
@@ -9,7 +9,7 @@ depends:
|
|
9
9
|
- name: ssl-benchmark
|
10
10
|
resolved_source:
|
11
11
|
url: https://github.com/dev-sec/ssl-benchmark/archive/master.tar.gz
|
12
|
-
sha256:
|
12
|
+
sha256: 9ad48391d4e6efff0a13d06736c5b075fb021410e0a629e087bc21e9617d957c
|
13
13
|
version_constraints: ">= 0"
|
14
14
|
- name: windows-patch-benchmark
|
15
15
|
resolved_source:
|
Binary file
|
data/inspec.gemspec
CHANGED
@@ -0,0 +1,12 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# author: Adam Leff
|
3
|
+
|
4
|
+
libdir = File.dirname(__FILE__)
|
5
|
+
$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
|
6
|
+
|
7
|
+
module Habitat
|
8
|
+
autoload :Log, 'inspec-habitat/log'
|
9
|
+
autoload :Profile, 'inspec-habitat/profile'
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'inspec-habitat/cli'
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# author: Adam Leff
|
3
|
+
|
4
|
+
require 'thor'
|
5
|
+
|
6
|
+
module Habitat
|
7
|
+
class HabitatProfileCLI < Thor
|
8
|
+
namespace 'habitat profile'
|
9
|
+
|
10
|
+
desc 'create PATH', 'Create a Habitat artifact for the profile found at PATH'
|
11
|
+
option :output_dir, type: :string, required: false,
|
12
|
+
desc: 'Directory in which to save the generated Habitat artifact. Default: current directory'
|
13
|
+
def create(path)
|
14
|
+
puts options
|
15
|
+
Habitat::Profile.create(path, options)
|
16
|
+
end
|
17
|
+
|
18
|
+
desc 'upload PATH', 'Create a Habitat artifact for the profile found at PATH, and upload it to a Habitat Depot'
|
19
|
+
def upload(path)
|
20
|
+
Habitat::Profile.upload(path, options)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class HabitatCLI < Inspec::BaseCLI
|
25
|
+
namespace 'habitat'
|
26
|
+
|
27
|
+
desc 'profile', 'Manage InSpec profiles as Habitat artifacts'
|
28
|
+
subcommand 'profile', HabitatProfileCLI
|
29
|
+
end
|
30
|
+
|
31
|
+
Inspec::Plugins::CLI.add_subcommand(HabitatCLI, 'habitat', 'habitat SUBCOMMAND ...', 'Commands for InSpec + Habitat Integration', {})
|
32
|
+
end
|
@@ -0,0 +1,334 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# author: Adam Leff
|
3
|
+
|
4
|
+
require 'mixlib/shellout'
|
5
|
+
require 'toml'
|
6
|
+
|
7
|
+
module Habitat
|
8
|
+
class Profile # rubocop:disable Metrics/ClassLength
|
9
|
+
attr_reader :options, :path, :profile
|
10
|
+
|
11
|
+
def self.create(path, options = {})
|
12
|
+
creator = new(path, options)
|
13
|
+
hart_file = creator.create
|
14
|
+
creator.copy(hart_file)
|
15
|
+
ensure
|
16
|
+
creator.delete_work_dir
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.upload(path, options = {})
|
20
|
+
uploader = new(path, options)
|
21
|
+
uploader.upload
|
22
|
+
ensure
|
23
|
+
uploader.delete_work_dir
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(path, options = {})
|
27
|
+
@path = path
|
28
|
+
@options = options
|
29
|
+
|
30
|
+
log_level = options.fetch('log_level', 'info')
|
31
|
+
Habitat::Log.level(log_level.to_sym)
|
32
|
+
end
|
33
|
+
|
34
|
+
def create
|
35
|
+
Habitat::Log.info("Creating a Habitat artifact for profile: #{path}")
|
36
|
+
|
37
|
+
validate_habitat_installed
|
38
|
+
validate_habitat_origin
|
39
|
+
create_profile_object
|
40
|
+
copy_profile_to_work_dir
|
41
|
+
create_plan
|
42
|
+
create_run_hook
|
43
|
+
create_default_config
|
44
|
+
|
45
|
+
# returns the path to the .hart file in the work directory
|
46
|
+
build_hart
|
47
|
+
rescue => e
|
48
|
+
Habitat::Log.debug(e.backtrace.join("\n"))
|
49
|
+
exit_with_error(
|
50
|
+
'Unable to generate Habitat artifact.',
|
51
|
+
"#{e.class} -- #{e.message}",
|
52
|
+
)
|
53
|
+
end
|
54
|
+
|
55
|
+
def copy(hart_file)
|
56
|
+
validate_output_dir
|
57
|
+
|
58
|
+
Habitat::Log.info("Copying artifact to #{output_dir}...")
|
59
|
+
copy_hart(hart_file)
|
60
|
+
end
|
61
|
+
|
62
|
+
def upload
|
63
|
+
validate_habitat_auth_token
|
64
|
+
hart_file = create
|
65
|
+
upload_hart(hart_file)
|
66
|
+
rescue => e
|
67
|
+
Habitat::Log.debug(e.backtrace.join("\n"))
|
68
|
+
exit_with_error(
|
69
|
+
'Unable to upload Habitat artifact.',
|
70
|
+
"#{e.class} -- #{e.message}",
|
71
|
+
)
|
72
|
+
end
|
73
|
+
|
74
|
+
def delete_work_dir
|
75
|
+
Habitat::Log.debug("Deleting work directory #{work_dir}")
|
76
|
+
FileUtils.rm_rf(work_dir) if Dir.exist?(work_dir)
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def create_profile_object
|
82
|
+
@profile = Inspec::Profile.for_target(path, {})
|
83
|
+
end
|
84
|
+
|
85
|
+
def verify_profile
|
86
|
+
Habitat::Log.info('Checking to see if the profile is valid...')
|
87
|
+
|
88
|
+
unless profile.check[:summary][:valid]
|
89
|
+
exit_with_error('Profile check failed. Please fix the profile before creating a Habitat artifact.')
|
90
|
+
end
|
91
|
+
|
92
|
+
Habitat::Log.info('Profile is valid.')
|
93
|
+
end
|
94
|
+
|
95
|
+
def validate_habitat_installed
|
96
|
+
Habitat::Log.info('Checking to see if Habitat is installed...')
|
97
|
+
cmd = Mixlib::ShellOut.new('hab --version')
|
98
|
+
cmd.run_command
|
99
|
+
if cmd.error?
|
100
|
+
exit_with_error('Unable to run Habitat commands.', cmd.stderr)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def validate_habitat_origin
|
105
|
+
if habitat_origin.nil?
|
106
|
+
exit_with_error(
|
107
|
+
'Unable to determine Habitat origin name.',
|
108
|
+
'Run `hab setup` or set the HAB_ORIGIN environment variable.',
|
109
|
+
)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def validate_habitat_auth_token
|
114
|
+
if habitat_auth_token.nil?
|
115
|
+
exit_with_error(
|
116
|
+
'Unable to determine Habitat auth token for publishing.',
|
117
|
+
'Run `hab setup` or set the HAB_AUTH_TOKEN environment variable.',
|
118
|
+
)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def validate_output_dir
|
123
|
+
exit_with_error("Output directory #{output_dir} is not a directory or does not exist.") unless
|
124
|
+
File.directory?(output_dir)
|
125
|
+
end
|
126
|
+
|
127
|
+
def work_dir
|
128
|
+
return @work_dir if @work_dir
|
129
|
+
|
130
|
+
@work_dir ||= Dir.mktmpdir('inspec-habitat-exporter')
|
131
|
+
Dir.mkdir(File.join(@work_dir, 'src'))
|
132
|
+
Dir.mkdir(File.join(@work_dir, 'habitat'))
|
133
|
+
Dir.mkdir(File.join(@work_dir, 'habitat', 'hooks'))
|
134
|
+
Habitat::Log.debug("Generated work directory #{@work_dir}")
|
135
|
+
|
136
|
+
@work_dir
|
137
|
+
end
|
138
|
+
|
139
|
+
def copy_profile_to_work_dir
|
140
|
+
Habitat::Log.info('Copying profile contents to the work directory...')
|
141
|
+
profile.files.each do |f|
|
142
|
+
src = File.join(profile.root_path, f)
|
143
|
+
dst = File.join(work_dir, 'src', f)
|
144
|
+
if File.directory?(f)
|
145
|
+
Habitat::Log.debug("Creating directory #{dst}")
|
146
|
+
FileUtils.mkdir_p(dst)
|
147
|
+
else
|
148
|
+
Habitat::Log.debug("Copying file #{src} to #{dst}")
|
149
|
+
FileUtils.cp_r(src, dst)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def create_plan
|
155
|
+
plan_file = File.join(work_dir, 'habitat', 'plan.sh')
|
156
|
+
Habitat::Log.info("Generating Habitat plan at #{plan_file}...")
|
157
|
+
File.write(plan_file, plan_contents)
|
158
|
+
end
|
159
|
+
|
160
|
+
def create_run_hook
|
161
|
+
run_hook_file = File.join(work_dir, 'habitat', 'hooks', 'run')
|
162
|
+
Habitat::Log.info("Generating a Habitat run hook at #{run_hook_file}...")
|
163
|
+
File.write(run_hook_file, run_hook_contents)
|
164
|
+
end
|
165
|
+
|
166
|
+
def create_default_config
|
167
|
+
default_toml = File.join(work_dir, 'habitat', 'default.toml')
|
168
|
+
Habitat::Log.info("Generating Habitat's default.toml configuration...")
|
169
|
+
File.write(default_toml, 'sleep_time = 300')
|
170
|
+
end
|
171
|
+
|
172
|
+
def build_hart
|
173
|
+
Habitat::Log.info('Building our Habitat artifact...')
|
174
|
+
|
175
|
+
env = {
|
176
|
+
'TERM' => 'vt100',
|
177
|
+
'HAB_ORIGIN' => habitat_origin,
|
178
|
+
'HAB_NONINTERACTIVE' => 'true',
|
179
|
+
}
|
180
|
+
|
181
|
+
env['RUST_LOG'] = 'debug' if Habitat::Log.level == :debug
|
182
|
+
|
183
|
+
# TODO: Would love to use Mixlib::ShellOut here, but it doesn't
|
184
|
+
# seem to preserve the STDIN tty, and docker gets angry.
|
185
|
+
Dir.chdir(work_dir) do
|
186
|
+
unless system(env, 'hab studio build .')
|
187
|
+
exit_with_error('Unable to build the Habitat artifact.')
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
hart_files = Dir.glob(File.join(work_dir, 'results', '*.hart'))
|
192
|
+
|
193
|
+
if hart_files.length > 1
|
194
|
+
exit_with_error('More than one Habitat artifact was created which was not expected.')
|
195
|
+
elsif hart_files.empty?
|
196
|
+
exit_with_error('No Habitat artifact was created.')
|
197
|
+
end
|
198
|
+
|
199
|
+
hart_files.first
|
200
|
+
end
|
201
|
+
|
202
|
+
def copy_hart(working_dir_hart)
|
203
|
+
hart_basename = File.basename(working_dir_hart)
|
204
|
+
dst = File.join(output_dir, hart_basename)
|
205
|
+
FileUtils.cp(working_dir_hart, dst)
|
206
|
+
|
207
|
+
dst
|
208
|
+
end
|
209
|
+
|
210
|
+
def upload_hart(hart_file)
|
211
|
+
Habitat::Log.info('Uploading the Habitat artifact to our Depot...')
|
212
|
+
|
213
|
+
env = {
|
214
|
+
'TERM' => 'vt100',
|
215
|
+
'HAB_AUTH_TOKEN' => habitat_auth_token,
|
216
|
+
'HAB_NONINTERACTIVE' => 'true',
|
217
|
+
}
|
218
|
+
|
219
|
+
env['HAB_DEPOT_URL'] = ENV['HAB_DEPOT_URL'] if ENV['HAB_DEPOT_URL']
|
220
|
+
|
221
|
+
cmd = Mixlib::ShellOut.new("hab pkg upload #{hart_file}", env: env)
|
222
|
+
cmd.run_command
|
223
|
+
if cmd.error?
|
224
|
+
exit_with_error(
|
225
|
+
'Unable to upload Habitat artifact to the Depot.',
|
226
|
+
cmd.stdout,
|
227
|
+
cmd.stderr,
|
228
|
+
)
|
229
|
+
end
|
230
|
+
|
231
|
+
Habitat::Log.info('Upload complete!')
|
232
|
+
end
|
233
|
+
|
234
|
+
def habitat_origin
|
235
|
+
ENV['HAB_ORIGIN'] || habitat_cli_config['origin']
|
236
|
+
end
|
237
|
+
|
238
|
+
def habitat_auth_token
|
239
|
+
ENV['HAB_AUTH_TOKEN'] || habitat_cli_config['auth_token']
|
240
|
+
end
|
241
|
+
|
242
|
+
def habitat_cli_config
|
243
|
+
return @cli_config if @cli_config
|
244
|
+
|
245
|
+
config_file = File.join(ENV['HOME'], '.hab', 'etc', 'cli.toml')
|
246
|
+
return {} unless File.exist?(config_file)
|
247
|
+
|
248
|
+
@cli_config = TOML.load_file(config_file)
|
249
|
+
end
|
250
|
+
|
251
|
+
def output_dir
|
252
|
+
options[:output_dir] || Dir.pwd
|
253
|
+
end
|
254
|
+
|
255
|
+
def exit_with_error(*errors)
|
256
|
+
errors.each do |error_msg|
|
257
|
+
Habitat::Log.error(error_msg)
|
258
|
+
end
|
259
|
+
|
260
|
+
exit 1
|
261
|
+
end
|
262
|
+
|
263
|
+
def package_name
|
264
|
+
"inspec-profile-#{profile.name}"
|
265
|
+
end
|
266
|
+
|
267
|
+
def plan_contents
|
268
|
+
plan = <<-EOL
|
269
|
+
pkg_name=#{package_name}
|
270
|
+
pkg_version=#{profile.version}
|
271
|
+
pkg_origin=#{habitat_origin}
|
272
|
+
pkg_source="nosuchfile.tar.gz"
|
273
|
+
pkg_deps=(chef/inspec)
|
274
|
+
pkg_build_deps=()
|
275
|
+
EOL
|
276
|
+
|
277
|
+
plan += "pkg_license='#{profile.metadata.params[:license]}'\n\n" if profile.metadata.params[:license]
|
278
|
+
|
279
|
+
plan += <<-EOL
|
280
|
+
do_download() {
|
281
|
+
return 0
|
282
|
+
}
|
283
|
+
|
284
|
+
do_verify() {
|
285
|
+
return 0
|
286
|
+
}
|
287
|
+
|
288
|
+
do_unpack() {
|
289
|
+
return 0
|
290
|
+
}
|
291
|
+
|
292
|
+
do_build() {
|
293
|
+
cp -vr $PLAN_CONTEXT/../src/* $HAB_CACHE_SRC_PATH/$pkg_dirname
|
294
|
+
}
|
295
|
+
|
296
|
+
do_install() {
|
297
|
+
cp -R . ${pkg_prefix}/dist
|
298
|
+
}
|
299
|
+
EOL
|
300
|
+
|
301
|
+
plan
|
302
|
+
end
|
303
|
+
|
304
|
+
def run_hook_contents
|
305
|
+
<<-EOL
|
306
|
+
#!/bin/sh
|
307
|
+
|
308
|
+
export PATH=${PATH}:$(hab pkg path core/ruby)/bin
|
309
|
+
|
310
|
+
PROFILE_IDENT="#{habitat_origin}/#{package_name}"
|
311
|
+
SLEEP_TIME={{cfg.sleep_time}}
|
312
|
+
|
313
|
+
# InSpec will try to create a .inspec directory, so this needs to be somewhere writable by the hab user
|
314
|
+
cd {{pkg.svc_var_path}}
|
315
|
+
|
316
|
+
while true; do
|
317
|
+
echo "Executing InSpec for ${PROFILE_IDENT}"
|
318
|
+
hab pkg exec chef/inspec inspec exec $(hab pkg path ${PROFILE_IDENT})/dist --format=cli 2>&1
|
319
|
+
RC=$?
|
320
|
+
|
321
|
+
echo ""
|
322
|
+
if [ "x${RC}" == "x0" ]; then
|
323
|
+
echo "InSpec run completed successfully."
|
324
|
+
else
|
325
|
+
echo "InSpec run did NOT complete successfully."
|
326
|
+
fi
|
327
|
+
|
328
|
+
echo "sleeping for ${SLEEP_TIME} seconds"
|
329
|
+
sleep ${SLEEP_TIME}
|
330
|
+
done
|
331
|
+
EOL
|
332
|
+
end
|
333
|
+
end
|
334
|
+
end
|
data/lib/inspec/metadata.rb
CHANGED
@@ -177,13 +177,31 @@ module Inspec
|
|
177
177
|
end
|
178
178
|
end
|
179
179
|
|
180
|
-
def self.
|
180
|
+
def self.finalize_name(metadata, profile_id, original_target)
|
181
|
+
# profile_id always overwrites whatever already exists as the name
|
182
|
+
unless profile_id.to_s.empty?
|
183
|
+
metadata.params[:name] = profile_id.to_s
|
184
|
+
return
|
185
|
+
end
|
186
|
+
|
187
|
+
# don't overwrite an existing name
|
188
|
+
return unless metadata.params[:name].nil?
|
189
|
+
|
190
|
+
# if there's a title, there is no need to set a name too
|
191
|
+
return unless metadata.params[:title].nil?
|
192
|
+
|
193
|
+
# create a new name based on the original target if it exists
|
194
|
+
metadata.params[:name] = "tests from #{original_target}" unless original_target.to_s.empty?
|
195
|
+
end
|
196
|
+
|
197
|
+
def self.finalize(metadata, profile_id, options, logger = nil)
|
181
198
|
return nil if metadata.nil?
|
182
199
|
param = metadata.params || {}
|
183
|
-
|
200
|
+
options ||= {}
|
184
201
|
param['version'] = param['version'].to_s unless param['version'].nil?
|
185
202
|
metadata.params = symbolize_keys(param)
|
186
203
|
metadata.params[:supports] = finalize_supports(metadata.params[:supports], logger)
|
204
|
+
finalize_name(metadata, profile_id, options[:target])
|
187
205
|
|
188
206
|
metadata
|
189
207
|
end
|
@@ -191,13 +209,13 @@ module Inspec
|
|
191
209
|
def self.from_yaml(ref, contents, profile_id, logger = nil)
|
192
210
|
res = Metadata.new(ref, logger)
|
193
211
|
res.params = YAML.load(contents)
|
194
|
-
finalize(res, profile_id, logger)
|
212
|
+
finalize(res, profile_id, {}, logger)
|
195
213
|
end
|
196
214
|
|
197
215
|
def self.from_ruby(ref, contents, profile_id, logger = nil)
|
198
216
|
res = Metadata.new(ref, logger)
|
199
217
|
res.instance_eval(contents, ref, 1)
|
200
|
-
finalize(res, profile_id, logger)
|
218
|
+
finalize(res, profile_id, {}, logger)
|
201
219
|
end
|
202
220
|
|
203
221
|
def self.from_ref(ref, contents, profile_id, logger = nil)
|
data/lib/inspec/profile.rb
CHANGED
@@ -82,7 +82,7 @@ module Inspec
|
|
82
82
|
|
83
83
|
# rubocop:disable Metrics/AbcSize
|
84
84
|
def initialize(source_reader, options = {})
|
85
|
-
@target = options
|
85
|
+
@target = options[:target]
|
86
86
|
@logger = options[:logger] || Logger.new(nil)
|
87
87
|
@locked_dependencies = options[:dependencies]
|
88
88
|
@controls = options[:controls] || []
|
@@ -94,7 +94,7 @@ module Inspec
|
|
94
94
|
@source_reader = source_reader
|
95
95
|
@tests_collected = false
|
96
96
|
@libraries_loaded = false
|
97
|
-
Metadata.finalize(@source_reader.metadata, @profile_id)
|
97
|
+
Metadata.finalize(@source_reader.metadata, @profile_id, options)
|
98
98
|
@runner_context =
|
99
99
|
options[:profile_context] ||
|
100
100
|
Inspec::ProfileContext.for_profile(self, @backend, @attr_values)
|
@@ -318,8 +318,6 @@ module Inspec
|
|
318
318
|
|
319
319
|
# display all files that will be part of the archive
|
320
320
|
@logger.debug 'Add the following files to archive:'
|
321
|
-
root_path = @source_reader.target.prefix
|
322
|
-
files = @source_reader.target.files
|
323
321
|
files.each { |f| @logger.debug ' ' + f }
|
324
322
|
|
325
323
|
if opts[:zip]
|
@@ -350,6 +348,14 @@ module Inspec
|
|
350
348
|
File.join(cwd, 'inspec.lock')
|
351
349
|
end
|
352
350
|
|
351
|
+
def root_path
|
352
|
+
@source_reader.target.prefix
|
353
|
+
end
|
354
|
+
|
355
|
+
def files
|
356
|
+
@source_reader.target.files
|
357
|
+
end
|
358
|
+
|
353
359
|
#
|
354
360
|
# TODO(ssd): Relative path handling really needs to be carefully
|
355
361
|
# thought through, especially with respect to relative paths in
|
data/lib/inspec/resource.rb
CHANGED
@@ -217,7 +217,17 @@ class InspecRspecJson < InspecRspecMiniJson # rubocop:disable Metrics/ClassLengt
|
|
217
217
|
end
|
218
218
|
|
219
219
|
def profile_contains_example?(profile, example)
|
220
|
-
profile[:name]
|
220
|
+
profile_name = profile[:name]
|
221
|
+
example_profile_id = example[:profile_id]
|
222
|
+
|
223
|
+
# if either the profile name is nil or the profile in the given example
|
224
|
+
# is nil, assume the profile doesn't contain the example and default
|
225
|
+
# to creating a new profile. Otherwise, for profiles that have no
|
226
|
+
# metadata, this may incorrectly match a profile that does not contain
|
227
|
+
# this example, leading to Ruby exceptions.
|
228
|
+
return false if profile_name.nil? || example_profile_id.nil?
|
229
|
+
|
230
|
+
profile_name == example_profile_id
|
221
231
|
end
|
222
232
|
|
223
233
|
def move_example_into_control(example, control)
|
@@ -238,27 +248,60 @@ end
|
|
238
248
|
class InspecRspecCli < InspecRspecJson # rubocop:disable Metrics/ClassLength
|
239
249
|
RSpec::Core::Formatters.register self, :close
|
240
250
|
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
251
|
+
case RUBY_PLATFORM
|
252
|
+
when /windows|mswin|msys|mingw|cygwin/
|
253
|
+
|
254
|
+
# Most currently available Windows terminals have poor support
|
255
|
+
# for ANSI extended colors
|
256
|
+
COLORS = {
|
257
|
+
'critical' => "\033[0;1;31m",
|
258
|
+
'major' => "\033[0;1;31m",
|
259
|
+
'minor' => "\033[0;36m",
|
260
|
+
'failed' => "\033[0;1;31m",
|
261
|
+
'passed' => "\033[0;1;32m",
|
262
|
+
'skipped' => "\033[0;37m",
|
263
|
+
'reset' => "\033[0m",
|
264
|
+
}.freeze
|
265
|
+
|
266
|
+
# Most currently available Windows terminals have poor support
|
267
|
+
# for UTF-8 characters so use these boring indicators
|
268
|
+
INDICATORS = {
|
269
|
+
'critical' => ' [CRIT] ',
|
270
|
+
'major' => ' [MAJR] ',
|
271
|
+
'minor' => ' [MINR] ',
|
272
|
+
'failed' => ' [FAIL] ',
|
273
|
+
'skipped' => ' [SKIP] ',
|
274
|
+
'passed' => ' [PASS] ',
|
275
|
+
'unknown' => ' [UNKN] ',
|
276
|
+
'empty' => ' ',
|
277
|
+
'small' => ' ',
|
278
|
+
}.freeze
|
279
|
+
else
|
280
|
+
# Extended colors for everyone else
|
281
|
+
COLORS = {
|
282
|
+
'critical' => "\033[38;5;9m",
|
283
|
+
'major' => "\033[38;5;208m",
|
284
|
+
'minor' => "\033[0;36m",
|
285
|
+
'failed' => "\033[38;5;9m",
|
286
|
+
'passed' => "\033[38;5;41m",
|
287
|
+
'skipped' => "\033[38;5;247m",
|
288
|
+
'reset' => "\033[0m",
|
289
|
+
}.freeze
|
290
|
+
|
291
|
+
# Groovy UTF-8 characters for everyone else...
|
292
|
+
# ...even though they probably only work on Mac
|
293
|
+
INDICATORS = {
|
294
|
+
'critical' => ' × ',
|
295
|
+
'major' => ' ∅ ',
|
296
|
+
'minor' => ' ⊚ ',
|
297
|
+
'failed' => ' × ',
|
298
|
+
'skipped' => ' ↺ ',
|
299
|
+
'passed' => ' ✔ ',
|
300
|
+
'unknown' => ' ? ',
|
301
|
+
'empty' => ' ',
|
302
|
+
'small' => ' ',
|
303
|
+
}.freeze
|
304
|
+
end
|
262
305
|
|
263
306
|
MULTI_TEST_CONTROL_SUMMARY_MAX_LEN = 60
|
264
307
|
|
@@ -458,7 +501,7 @@ class InspecRspecCli < InspecRspecJson # rubocop:disable Metrics/ClassLength
|
|
458
501
|
output.puts "Profile: #{profile[:title]} (#{profile[:name] || 'unknown'})"
|
459
502
|
end
|
460
503
|
|
461
|
-
output.puts 'Version: ' + (profile[:version] || '
|
504
|
+
output.puts 'Version: ' + (profile[:version] || '(not specified)')
|
462
505
|
print_target
|
463
506
|
profile[:already_printed] = true
|
464
507
|
end
|
data/lib/inspec/shell.rb
CHANGED
@@ -42,6 +42,8 @@ module Inspec
|
|
42
42
|
# Add a help menu as the default intro
|
43
43
|
Pry.hooks.add_hook(:before_session, 'inspec_intro') do
|
44
44
|
intro
|
45
|
+
print_target_info
|
46
|
+
puts
|
45
47
|
end
|
46
48
|
|
47
49
|
# Track the rules currently registered and what their merge count is.
|
@@ -94,10 +96,20 @@ module Inspec
|
|
94
96
|
puts
|
95
97
|
end
|
96
98
|
|
99
|
+
def print_target_info
|
100
|
+
ctx = @runner.backend
|
101
|
+
puts <<EOF
|
102
|
+
You are currently running on:
|
103
|
+
|
104
|
+
OS platform: #{mark ctx.os[:name] || 'unknown'}
|
105
|
+
OS family: #{mark ctx.os[:family] || 'unknown'}
|
106
|
+
OS release: #{mark ctx.os[:release] || 'unknown'}
|
107
|
+
EOF
|
108
|
+
end
|
109
|
+
|
97
110
|
def help(resource = nil)
|
98
111
|
if resource.nil?
|
99
112
|
|
100
|
-
ctx = @runner.backend
|
101
113
|
puts <<EOF
|
102
114
|
|
103
115
|
Available commands:
|
@@ -110,14 +122,9 @@ Available commands:
|
|
110
122
|
You can use resources in this environment to test the target machine. For example:
|
111
123
|
|
112
124
|
command('uname -a').stdout
|
113
|
-
file('/proc/cpuinfo').content => "value"
|
114
|
-
|
115
|
-
You are currently running on:
|
116
|
-
|
117
|
-
OS platform: #{mark ctx.os[:name] || 'unknown'}
|
118
|
-
OS family: #{mark ctx.os[:family] || 'unknown'}
|
119
|
-
OS release: #{mark ctx.os[:release] || 'unknown'}
|
125
|
+
file('/proc/cpuinfo').content => "value"
|
120
126
|
|
127
|
+
#{print_target_info}
|
121
128
|
EOF
|
122
129
|
elsif resource == 'resources'
|
123
130
|
resources
|
data/lib/inspec/version.rb
CHANGED
@@ -0,0 +1,83 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# author: Adam Leff
|
3
|
+
|
4
|
+
require 'utils/parser'
|
5
|
+
require 'utils/filter'
|
6
|
+
|
7
|
+
module Inspec::Resources
|
8
|
+
class Crontab < Inspec.resource(1)
|
9
|
+
name 'crontab'
|
10
|
+
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
|
+
example "
|
12
|
+
describe crontab('root') do
|
13
|
+
its('commands') { should include '/path/to/some/script' }
|
14
|
+
end
|
15
|
+
|
16
|
+
describe crontab('myuser').commands('/home/myuser/build.sh') do
|
17
|
+
its('hours') { should cmp '*' }
|
18
|
+
its('minutes') { should cmp '*' }
|
19
|
+
end
|
20
|
+
|
21
|
+
describe crontab.where({'hour' => '*', 'minute' => '*'}) do
|
22
|
+
its('entries.length') { should cmp '0' }
|
23
|
+
end
|
24
|
+
"
|
25
|
+
|
26
|
+
attr_reader :params
|
27
|
+
|
28
|
+
include CommentParser
|
29
|
+
|
30
|
+
def initialize(user = nil)
|
31
|
+
@user = user
|
32
|
+
@params = read_crontab
|
33
|
+
|
34
|
+
return skip_resource 'The `crontab` resource is not supported on your OS.' unless inspec.os.unix?
|
35
|
+
end
|
36
|
+
|
37
|
+
def read_crontab
|
38
|
+
inspec.command(crontab_cmd).stdout.lines.map { |l| parse_crontab_line(l) }.compact
|
39
|
+
end
|
40
|
+
|
41
|
+
def parse_crontab_line(l)
|
42
|
+
data, = parse_comment_line(l, comment_char: '#', standalone_comments: false)
|
43
|
+
return nil if data.nil? || data.empty?
|
44
|
+
|
45
|
+
elements = data.split(/\s+/, 6)
|
46
|
+
{
|
47
|
+
'minute' => elements.at(0),
|
48
|
+
'hour' => elements.at(1),
|
49
|
+
'day' => elements.at(2),
|
50
|
+
'month' => elements.at(3),
|
51
|
+
'weekday' => elements.at(4),
|
52
|
+
'command' => elements.at(5),
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
def crontab_cmd
|
57
|
+
@user.nil? ? 'crontab -l' : "crontab -l -u #{@user}"
|
58
|
+
end
|
59
|
+
|
60
|
+
filter = FilterTable.create
|
61
|
+
filter.add_accessor(:where)
|
62
|
+
.add_accessor(:entries)
|
63
|
+
.add(:minutes, field: 'minute')
|
64
|
+
.add(:hours, field: 'hour')
|
65
|
+
.add(:days, field: 'day')
|
66
|
+
.add(:months, field: 'month')
|
67
|
+
.add(:weekdays, field: 'weekday')
|
68
|
+
.add(:commands, field: 'command')
|
69
|
+
|
70
|
+
# rebuild the crontab line from raw content
|
71
|
+
filter.add(:content) { |t, _|
|
72
|
+
t.entries.map do |e|
|
73
|
+
[e.minute, e.hour, e.day, e.month, e.weekday, e.command].join(' ')
|
74
|
+
end.join("\n")
|
75
|
+
}
|
76
|
+
|
77
|
+
filter.connect(self, :params)
|
78
|
+
|
79
|
+
def to_s
|
80
|
+
@user.nil? ? 'crontab for current user' : "crontab for user #{@user}"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/lib/resources/package.rb
CHANGED
@@ -29,7 +29,7 @@ module Inspec::Resources
|
|
29
29
|
os = inspec.os
|
30
30
|
if os.debian?
|
31
31
|
@pkgman = Deb.new(inspec)
|
32
|
-
elsif %w{
|
32
|
+
elsif os.redhat? || %w{suse amazon fedora}.include?(os[:family])
|
33
33
|
@pkgman = Rpm.new(inspec)
|
34
34
|
elsif ['arch'].include?(os[:family])
|
35
35
|
@pkgman = Pacman.new(inspec)
|
data/lib/resources/packages.rb
CHANGED
@@ -23,12 +23,17 @@ module Inspec::Resources
|
|
23
23
|
"
|
24
24
|
|
25
25
|
def initialize(pattern)
|
26
|
-
|
27
|
-
|
28
|
-
|
26
|
+
os = inspec.os
|
27
|
+
if os.debian?
|
28
|
+
@pkgs = Debs.new(inspec)
|
29
|
+
elsif os.redhat? || %w{suse amazon fedora}.include?(os[:family])
|
30
|
+
@pkgs = Rpms.new(inspec)
|
31
|
+
else
|
32
|
+
return skip_resource "The packages resource is not yet supported on OS #{inspec.os.name}"
|
33
|
+
end
|
29
34
|
|
30
35
|
@pattern = pattern_regexp(pattern)
|
31
|
-
all_pkgs = build_package_list
|
36
|
+
all_pkgs = @pkgs.build_package_list
|
32
37
|
@list = all_pkgs.find_all do |hm|
|
33
38
|
hm[:name] =~ @pattern
|
34
39
|
end
|
@@ -48,14 +53,6 @@ module Inspec::Resources
|
|
48
53
|
|
49
54
|
private
|
50
55
|
|
51
|
-
def packages_command
|
52
|
-
os = inspec.os
|
53
|
-
if os.debian?
|
54
|
-
command = "dpkg-query -W -f='${db:Status-Abbrev} ${Package} ${Version}\\n'"
|
55
|
-
end
|
56
|
-
command
|
57
|
-
end
|
58
|
-
|
59
56
|
def pattern_regexp(p)
|
60
57
|
if p.class == String
|
61
58
|
Regexp.new(Regexp.escape(p))
|
@@ -67,21 +64,48 @@ module Inspec::Resources
|
|
67
64
|
end
|
68
65
|
|
69
66
|
def filtered_packages
|
70
|
-
warn "The packages resource is not yet supported on OS #{inspec.os.name}"
|
67
|
+
warn "The packages resource is not yet supported on OS #{inspec.os.name}" if resource_skipped
|
71
68
|
@list
|
72
69
|
end
|
70
|
+
end
|
73
71
|
|
74
|
-
|
72
|
+
class PkgsManagement
|
73
|
+
PackageStruct = Struct.new(:status, :name, :version)
|
74
|
+
attr_reader :inspec
|
75
|
+
def initialize(inspec)
|
76
|
+
@inspec = inspec
|
77
|
+
end
|
78
|
+
end
|
75
79
|
|
76
|
-
|
80
|
+
# Debian / Ubuntu
|
81
|
+
class Debs < PkgsManagement
|
82
|
+
def build_package_list
|
83
|
+
# use two spaces as delimiter in case any of the fields has a space in it
|
84
|
+
command = "dpkg-query -W -f='${db:Status-Abbrev} ${Package} ${Version}\\n'"
|
77
85
|
cmd = inspec.command(command)
|
78
|
-
all = cmd.stdout.split("\n")
|
86
|
+
all = cmd.stdout.split("\n")
|
79
87
|
return [] if all.nil?
|
80
88
|
all.map do |m|
|
81
|
-
a = m.split
|
89
|
+
a = m.split(/ {2,}/)
|
82
90
|
a[0] = 'installed' if a[0] =~ /^.i/
|
83
91
|
a[2] = a[2].split(':').last
|
84
|
-
|
92
|
+
PackageStruct.new(*a)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# RedHat family
|
98
|
+
class Rpms < PkgsManagement
|
99
|
+
def build_package_list
|
100
|
+
# use two spaces as delimiter in case any of the fields has a space in it
|
101
|
+
command = "rpm -qa --queryformat '%{NAME} %{VERSION}-%{RELEASE}\\n'"
|
102
|
+
cmd = inspec.command(command)
|
103
|
+
all = cmd.stdout.split("\n")
|
104
|
+
return [] if all.nil?
|
105
|
+
all.map do |m|
|
106
|
+
a = m.split(' ')
|
107
|
+
a.unshift('installed')
|
108
|
+
PackageStruct.new(*a)
|
85
109
|
end
|
86
110
|
end
|
87
111
|
end
|
@@ -27,7 +27,7 @@ module SourceReaders
|
|
27
27
|
|
28
28
|
# This create a new instance of an InSpec profile source reader
|
29
29
|
#
|
30
|
-
# @param [
|
30
|
+
# @param [FileProvider] target An instance of a FileProvider object that can list files and read them
|
31
31
|
# @param [String] metadata_source eg. inspec.yml or metadata.rb
|
32
32
|
def initialize(target, metadata_source)
|
33
33
|
@target = target
|
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.15.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-02-
|
11
|
+
date: 2017-02-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: train
|
@@ -232,6 +232,20 @@ dependencies:
|
|
232
232
|
- - ">="
|
233
233
|
- !ruby/object:Gem::Version
|
234
234
|
version: 0.9.0
|
235
|
+
- !ruby/object:Gem::Dependency
|
236
|
+
name: toml
|
237
|
+
requirement: !ruby/object:Gem::Requirement
|
238
|
+
requirements:
|
239
|
+
- - "~>"
|
240
|
+
- !ruby/object:Gem::Version
|
241
|
+
version: '0.1'
|
242
|
+
type: :runtime
|
243
|
+
prerelease: false
|
244
|
+
version_requirements: !ruby/object:Gem::Requirement
|
245
|
+
requirements:
|
246
|
+
- - "~>"
|
247
|
+
- !ruby/object:Gem::Version
|
248
|
+
version: '0.1'
|
235
249
|
description: InSpec provides a framework for creating end-to-end infrastructure tests.
|
236
250
|
You can use it for integration or even compliance testing. Create fully portable
|
237
251
|
test profiles and use them in your workflow to ensure stability and security. Integrate
|
@@ -272,6 +286,7 @@ files:
|
|
272
286
|
- docs/resources/bridge.md.erb
|
273
287
|
- docs/resources/bsd_service.md.erb
|
274
288
|
- docs/resources/command.md.erb
|
289
|
+
- docs/resources/crontab.md.erb
|
275
290
|
- docs/resources/csv.md.erb
|
276
291
|
- docs/resources/directory.md.erb
|
277
292
|
- docs/resources/etc_group.md.erb
|
@@ -370,7 +385,7 @@ files:
|
|
370
385
|
- examples/meta-profile/inspec.lock
|
371
386
|
- examples/meta-profile/inspec.yml
|
372
387
|
- examples/meta-profile/vendor/3d473e72d8b70018386a53e0a105e92ccbb4115dc268cadc16ff53d550d2898e.tar.gz
|
373
|
-
- examples/meta-profile/vendor/
|
388
|
+
- examples/meta-profile/vendor/9ad48391d4e6efff0a13d06736c5b075fb021410e0a629e087bc21e9617d957c.tar.gz
|
374
389
|
- examples/meta-profile/vendor/e25d521fb1093b4c23b31a7dc8f41b5540236f4a433960b151bc427523662ab6.tar.gz
|
375
390
|
- examples/profile-attribute.yml
|
376
391
|
- examples/profile-attribute/README.md
|
@@ -380,7 +395,6 @@ files:
|
|
380
395
|
- examples/profile/controls/example.rb
|
381
396
|
- examples/profile/controls/gordon.rb
|
382
397
|
- examples/profile/controls/meta.rb
|
383
|
-
- examples/profile/inspec.lock
|
384
398
|
- examples/profile/inspec.yml
|
385
399
|
- examples/profile/libraries/gordon_config.rb
|
386
400
|
- inspec.gemspec
|
@@ -400,6 +414,10 @@ files:
|
|
400
414
|
- lib/bundles/inspec-compliance/support.rb
|
401
415
|
- lib/bundles/inspec-compliance/target.rb
|
402
416
|
- lib/bundles/inspec-compliance/test/integration/default/cli.rb
|
417
|
+
- lib/bundles/inspec-habitat.rb
|
418
|
+
- lib/bundles/inspec-habitat/cli.rb
|
419
|
+
- lib/bundles/inspec-habitat/log.rb
|
420
|
+
- lib/bundles/inspec-habitat/profile.rb
|
403
421
|
- lib/bundles/inspec-init.rb
|
404
422
|
- lib/bundles/inspec-init/README.md
|
405
423
|
- lib/bundles/inspec-init/cli.rb
|
@@ -474,7 +492,6 @@ files:
|
|
474
492
|
- lib/inspec/source_reader.rb
|
475
493
|
- lib/inspec/version.rb
|
476
494
|
- lib/matchers/matchers.rb
|
477
|
-
- lib/resources/.ssh_conf.rb.swp
|
478
495
|
- lib/resources/apache.rb
|
479
496
|
- lib/resources/apache_conf.rb
|
480
497
|
- lib/resources/apt.rb
|
@@ -485,6 +502,7 @@ files:
|
|
485
502
|
- lib/resources/bond.rb
|
486
503
|
- lib/resources/bridge.rb
|
487
504
|
- lib/resources/command.rb
|
505
|
+
- lib/resources/crontab.rb
|
488
506
|
- lib/resources/csv.rb
|
489
507
|
- lib/resources/directory.rb
|
490
508
|
- lib/resources/etc_group.rb
|
@@ -575,7 +593,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
575
593
|
version: '0'
|
576
594
|
requirements: []
|
577
595
|
rubyforge_project:
|
578
|
-
rubygems_version: 2.5.
|
596
|
+
rubygems_version: 2.5.1
|
579
597
|
signing_key:
|
580
598
|
specification_version: 4
|
581
599
|
summary: Infrastructure and compliance testing.
|
Binary file
|
Binary file
|