inspec 1.14.1 → 1.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.
- 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
|