kitchen-inspec 0.25.0 → 0.26.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/CODEOWNERS +3 -0
- data/.gitignore +11 -0
- data/.kitchen.yml +82 -0
- data/.rspec +2 -0
- data/.travis.yml +41 -0
- data/Berksfile +8 -0
- data/CHANGELOG.md +469 -0
- data/Gemfile +37 -0
- data/Guardfile +23 -0
- data/MAINTAINERS.md +13 -0
- data/README.md +275 -0
- data/Rakefile +129 -0
- data/kitchen-inspec.gemspec +24 -0
- data/lib/kitchen/verifier/inspec_version.rb +1 -1
- data/spec/kitchen/verifier/inspec_spec.rb +607 -0
- data/spec/spec_helper.rb +33 -0
- data/test/cookbooks/os_prepare/metadata.rb +8 -0
- data/test/cookbooks/os_prepare/recipes/default.rb +5 -0
- data/test/integration/attributes/controls/example.rb +11 -0
- data/test/integration/attributes/inspec.yml +8 -0
- data/test/integration/contains_inspec/inspec/_debug_spec.rb +1 -0
- data/test/integration/contains_inspec/inspec/os_spec.rb +7 -0
- data/test/integration/duplicates/dup.rb +13 -0
- data/test/integration/profile-attribute.yml +2 -0
- data/test/integration/profile/controls/example.rb +15 -0
- data/test/integration/profile/controls/gordon.rb +14 -0
- data/test/integration/profile/inspec.yml +10 -0
- data/test/integration/profile/libraries/gordon_config.rb +6 -0
- data/test/recipes/default/_debug_test.rb +1 -0
- data/test/recipes/default/os_test.rb +7 -0
- metadata +35 -6
data/Gemfile
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
source "https://rubygems.org"
|
3
|
+
gemspec
|
4
|
+
|
5
|
+
if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("2.2.2")
|
6
|
+
gem "json", "< 2.0"
|
7
|
+
gem "rack", "< 2.0"
|
8
|
+
gem "ruby_dep", "< 1.4.0"
|
9
|
+
gem "listen", "< 3.0.0"
|
10
|
+
end
|
11
|
+
|
12
|
+
group :guard do
|
13
|
+
gem "guard-rspec", :require => nil
|
14
|
+
gem "guard-rubocop", :require => nil
|
15
|
+
end
|
16
|
+
|
17
|
+
group :test do
|
18
|
+
gem "bundler", "~> 1.10"
|
19
|
+
gem "minitest", "~> 5.5"
|
20
|
+
gem "rake", "~> 11.0"
|
21
|
+
gem "chefstyle", "0.4.0"
|
22
|
+
gem "concurrent-ruby", "~> 1.0"
|
23
|
+
gem "codeclimate-test-reporter", :require => nil
|
24
|
+
gem "rspec"
|
25
|
+
gem "simplecov", "~> 0.12"
|
26
|
+
gem "countloc", "~> 0.4"
|
27
|
+
end
|
28
|
+
|
29
|
+
group :integration do
|
30
|
+
gem "berkshelf", ">= 4.3.5"
|
31
|
+
gem "kitchen-dokken"
|
32
|
+
end
|
33
|
+
|
34
|
+
group :tools do
|
35
|
+
gem "pry", "~> 0.10"
|
36
|
+
gem "github_changelog_generator", "1.13.1"
|
37
|
+
end
|
data/Guardfile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
ignore %r{^\.gem/}
|
3
|
+
|
4
|
+
def rspec_opts
|
5
|
+
{ cmd: "bundle exec rspec" }
|
6
|
+
end
|
7
|
+
|
8
|
+
def rubocop_opts
|
9
|
+
{ all_on_start: false, keep_failed: false, cli: "-r chefstyle" }
|
10
|
+
end
|
11
|
+
|
12
|
+
group :red_green_refactor, halt_on_fail: true do
|
13
|
+
guard :rspec, rspec_opts do
|
14
|
+
watch(%r{^spec/(.*)_spec\.rb})
|
15
|
+
watch(%r{^lib/(.*)([^/]+)\.rb}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
|
16
|
+
watch(%r{^spec/spec_helper\.rb}) { "spec" }
|
17
|
+
end
|
18
|
+
|
19
|
+
guard :rubocop, rubocop_opts do
|
20
|
+
watch(/.+\.rb$/)
|
21
|
+
watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) }
|
22
|
+
end
|
23
|
+
end
|
data/MAINTAINERS.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# Maintainers
|
2
|
+
|
3
|
+
This file lists how the kitchen-inspec project is maintained. When making changes to the
|
4
|
+
project, this file tells you who needs to review your patch - you need at least
|
5
|
+
two maintainers to provide a :+1: on your pull request. Additionally, you need
|
6
|
+
to not receive a veto from a Lieutenant or the Project Lead.
|
7
|
+
Check out [How Chef is Maintained](https://github.com/chef/chef-rfc/blob/master/rfc030-maintenance-policy.md#how-the-project-is-maintained)
|
8
|
+
for details on the process, how to become a maintainer, lieutenant, or the
|
9
|
+
project lead.
|
10
|
+
|
11
|
+
## List of Maintainers
|
12
|
+
|
13
|
+
The [Maintainers of the InSpec project](https://github.com/chef/inspec/blob/master/MAINTAINERS.md) serve as maintainers of the kitchen-inspec project.
|
data/README.md
ADDED
@@ -0,0 +1,275 @@
|
|
1
|
+
# Kitchen::InSpec - A Test Kitchen Verifier for InSpec
|
2
|
+
|
3
|
+
[![Build Status Master](https://travis-ci.org/inspec/kitchen-inspec.svg?branch=master)](https://travis-ci.org/inspec/kitchen-inspec) [![Gem Version](https://badge.fury.io/rb/kitchen-inspec.svg)](https://badge.fury.io/rb/kitchen-inspec)
|
4
|
+
|
5
|
+
This is the kitchen driver for [InSpec](https://github.com/chef/inspec). To see the project in action, we have the following test-kitchen examples available:
|
6
|
+
|
7
|
+
- [Chef and InSpec](https://github.com/inspec/inspec/tree/master/examples/kitchen-chef)
|
8
|
+
- [Puppet and InSpec](https://github.com/inspec/inspec/tree/master/examples/kitchen-puppet)
|
9
|
+
- [Ansible and InSpec](https://github.com/inspec/inspec/tree/master/examples/kitchen-ansible)
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
`Note:` kitchen-inspec ships as part of ChefDK. Installation is not necessary for DK users.
|
14
|
+
|
15
|
+
Add this line to your application's Gemfile:
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
gem 'kitchen-inspec'
|
19
|
+
```
|
20
|
+
|
21
|
+
And then execute:
|
22
|
+
|
23
|
+
```shell
|
24
|
+
$ bundle
|
25
|
+
```
|
26
|
+
|
27
|
+
Or install it yourself as:
|
28
|
+
|
29
|
+
```shell
|
30
|
+
$ gem install kitchen-inspec
|
31
|
+
```
|
32
|
+
|
33
|
+
## Usage
|
34
|
+
|
35
|
+
In your .kitchen.yml include
|
36
|
+
|
37
|
+
```yaml
|
38
|
+
verifier:
|
39
|
+
name: inspec
|
40
|
+
```
|
41
|
+
|
42
|
+
Optionally specify sudo and sudo_command
|
43
|
+
|
44
|
+
```yaml
|
45
|
+
verifier:
|
46
|
+
name: inspec
|
47
|
+
sudo: true
|
48
|
+
sudo_command: 'skittles'
|
49
|
+
```
|
50
|
+
|
51
|
+
You can also specify the host and port to be used by InSpec when targeting the node. Otherwise, it defaults to the hostname and port used by kitchen for converging.
|
52
|
+
|
53
|
+
```yaml
|
54
|
+
verifier:
|
55
|
+
name: inspec
|
56
|
+
host: 192.168.56.40
|
57
|
+
port: 22
|
58
|
+
```
|
59
|
+
|
60
|
+
### Expected Directory Structure
|
61
|
+
|
62
|
+
By default `kitchen-inspec` expects test to be in `test/integration/%suite%` directory structure (we use Chef as provisioner here):
|
63
|
+
|
64
|
+
```
|
65
|
+
.
|
66
|
+
├── Berksfile
|
67
|
+
├── Gemfile
|
68
|
+
├── README.md
|
69
|
+
├── metadata.rb
|
70
|
+
├── recipes
|
71
|
+
│ ├── default.rb
|
72
|
+
│ └── nginx.rb
|
73
|
+
└── test
|
74
|
+
└── integration
|
75
|
+
└── default
|
76
|
+
└── web_spec.rb
|
77
|
+
```
|
78
|
+
|
79
|
+
#### Directory Structure with complete profile
|
80
|
+
|
81
|
+
A complete profile is used here, including a custom InSpec resource named `gordon_config`:
|
82
|
+
|
83
|
+
```
|
84
|
+
.
|
85
|
+
├── Berksfile
|
86
|
+
├── Gemfile
|
87
|
+
├── README.md
|
88
|
+
├── metadata.rb
|
89
|
+
├── recipes
|
90
|
+
│ ├── default.rb
|
91
|
+
│ └── nginx.rb
|
92
|
+
└── test
|
93
|
+
└── integration
|
94
|
+
└── default
|
95
|
+
├── controls
|
96
|
+
│ └── gordon.rb
|
97
|
+
├── inspec.yml
|
98
|
+
└── libraries
|
99
|
+
└── gordon_config.rb
|
100
|
+
```
|
101
|
+
|
102
|
+
#### Combination with other testing frameworks
|
103
|
+
|
104
|
+
If you need support with other testing frameworks, we recommend to place the tests in `test/integration/%suite%/inspec`:
|
105
|
+
|
106
|
+
```
|
107
|
+
.
|
108
|
+
├── Berksfile
|
109
|
+
├── Gemfile
|
110
|
+
├── README.md
|
111
|
+
├── metadata.rb
|
112
|
+
├── recipes
|
113
|
+
│ ├── default.rb
|
114
|
+
│ └── nginx.rb
|
115
|
+
└── test
|
116
|
+
└── integration
|
117
|
+
└── default
|
118
|
+
└── inspec
|
119
|
+
└── web_spec.rb
|
120
|
+
```
|
121
|
+
|
122
|
+
### Specifying the Sudo Command
|
123
|
+
|
124
|
+
You can enable/disable sudo and set your own custom sudo command.
|
125
|
+
|
126
|
+
```yaml
|
127
|
+
verifier:
|
128
|
+
name: inspec
|
129
|
+
sudo: true
|
130
|
+
sudo_command: 'skittles'
|
131
|
+
```
|
132
|
+
|
133
|
+
### Custom Host Settings
|
134
|
+
|
135
|
+
You can also specify the host, port, and proxy settings to be used by InSpec when targeting the node. Otherwise, it defaults to the hostname and port used by kitchen for converging.
|
136
|
+
|
137
|
+
```yaml
|
138
|
+
verifier:
|
139
|
+
name: inspec
|
140
|
+
host: 192.168.56.40
|
141
|
+
port: 22
|
142
|
+
proxy_command: ssh user@1.2.3.4 -W %h:%p
|
143
|
+
```
|
144
|
+
|
145
|
+
### Custom Outputs
|
146
|
+
|
147
|
+
If you want to customize the output file per platform or test suite you can use template format for your output variable. Current flags supported:
|
148
|
+
|
149
|
+
- _%{platform}_
|
150
|
+
- _%{suite}_
|
151
|
+
|
152
|
+
```yaml
|
153
|
+
verifier:
|
154
|
+
name: inspec
|
155
|
+
reporter:
|
156
|
+
- cli
|
157
|
+
- junit:path/to/results/%{platform}_%{suite}_inspec.xml
|
158
|
+
```
|
159
|
+
|
160
|
+
You can also decide to only run specific controls, instead of a full profile. This is done by specifying a list of controls:
|
161
|
+
|
162
|
+
```yaml
|
163
|
+
suites:
|
164
|
+
- name: supermarket
|
165
|
+
run_list:
|
166
|
+
- recipe[apt]
|
167
|
+
- recipe[ssh-hardening]
|
168
|
+
verifier:
|
169
|
+
inspec_tests:
|
170
|
+
- name: dev-sec/ssh-baseline
|
171
|
+
controls:
|
172
|
+
- sshd-46
|
173
|
+
...
|
174
|
+
```
|
175
|
+
|
176
|
+
### Use remote InSpec profiles
|
177
|
+
|
178
|
+
In case you want to reuse tests across multiple cookbooks, they should become an extra artifact independent of a Chef cookbook, called [InSpec profiles](https://github.com/inspec/inspec/blob/master/docs/profiles.md). Those can be easily added to existing local tests as demonstrated in previous sections. To include remote profiles, adapt the `verifier` attributes in `.kitchen.yml`
|
179
|
+
|
180
|
+
```yaml
|
181
|
+
suites:
|
182
|
+
- name: default
|
183
|
+
verifier:
|
184
|
+
inspec_tests:
|
185
|
+
- name: ssh-hardening
|
186
|
+
url: https://github.com/dev-sec/tests-ssh-hardening
|
187
|
+
```
|
188
|
+
|
189
|
+
`inspec_tests` accepts all values that `inspec exec profile` would expect. We support:
|
190
|
+
|
191
|
+
- local directory eg. `path: /path/to/profile`
|
192
|
+
- github url `git: https://github.com/dev-sec/tests-ssh-hardening.git`
|
193
|
+
- Chef Supermarket `name: hardening/ssh-hardening` # defaults to supermarket (list all available profiles with `inspec supermarket profiles`)
|
194
|
+
- Chef Compliance `name: ssh` `compliance: base/ssh`
|
195
|
+
|
196
|
+
The following example illustrates the usage in a `.kitchen.yml`
|
197
|
+
|
198
|
+
```yaml
|
199
|
+
suites:
|
200
|
+
- name: contains_inspec
|
201
|
+
run_list:
|
202
|
+
- recipe[apt]
|
203
|
+
- recipe[yum]
|
204
|
+
- recipe[ssh-hardening]
|
205
|
+
- recipe[os-hardening]
|
206
|
+
verifier:
|
207
|
+
inspec_tests:
|
208
|
+
- path: path/to/some/local/tests
|
209
|
+
- name: ssh-hardening
|
210
|
+
url: https://github.com/dev-sec/tests-ssh-hardening/archive/master.zip
|
211
|
+
- name: os-hardening
|
212
|
+
git: https://github.com/dev-sec/tests-os-hardening.git
|
213
|
+
- name: supermarket
|
214
|
+
run_list:
|
215
|
+
- recipe[apt]
|
216
|
+
- recipe[yum]
|
217
|
+
- recipe[ssh-hardening]
|
218
|
+
verifier:
|
219
|
+
inspec_tests:
|
220
|
+
- name: hardening/ssh-hardening # name only defaults to supermarket
|
221
|
+
- name: ssh-supermarket # alternatively, you can explicitly specify that the profile is from supermarket in this way
|
222
|
+
supermarket: hardening/ssh-hardening
|
223
|
+
supermarket_url: http://supermarket.example.com
|
224
|
+
# before you are able to use the compliance plugin, you need to run
|
225
|
+
# insecure is only required if you use self-signed certificates
|
226
|
+
# $ inspec compliance login https://compliance.test --user admin --insecure --token ''
|
227
|
+
- name: compliance
|
228
|
+
run_list:
|
229
|
+
- recipe[apt]
|
230
|
+
- recipe[yum]
|
231
|
+
- recipe[ssh-hardening]
|
232
|
+
verifier:
|
233
|
+
inspec_tests:
|
234
|
+
- name: ssh
|
235
|
+
compliance: base/ssh
|
236
|
+
```
|
237
|
+
|
238
|
+
### Use attributes with your inspec profiles
|
239
|
+
|
240
|
+
To run a profile with attributes defined inline, you can adapt your `.kitchen.yml`:
|
241
|
+
|
242
|
+
```yaml
|
243
|
+
verifier:
|
244
|
+
inspec_tests:
|
245
|
+
- path: test/integration/attributes
|
246
|
+
attributes:
|
247
|
+
user: bob
|
248
|
+
password: secret
|
249
|
+
```
|
250
|
+
|
251
|
+
You can also define your attributes in an external file. Adapt your `.kitchen.yml` to point to that file:
|
252
|
+
|
253
|
+
```yaml
|
254
|
+
verifier:
|
255
|
+
inspec_tests:
|
256
|
+
- path: test/integration/attributes
|
257
|
+
attrs:
|
258
|
+
- test/integration/profile-attribute.yml
|
259
|
+
```
|
260
|
+
|
261
|
+
## Development
|
262
|
+
|
263
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
264
|
+
|
265
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
266
|
+
|
267
|
+
## Contributing
|
268
|
+
|
269
|
+
Bug reports and pull requests are welcome on GitHub at <https://github.com/inspec/kitchen-inspec>.
|
270
|
+
|
271
|
+
## License
|
272
|
+
|
273
|
+
Apache 2.0 (see [LICENSE])
|
274
|
+
|
275
|
+
[license]: https://github.com/inspec/kitchen-inspec/blob/master/LICENSE
|
data/Rakefile
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require "bundler/gem_tasks"
|
4
|
+
require "rspec/core/rake_task"
|
5
|
+
require "chefstyle"
|
6
|
+
require "rubocop/rake_task"
|
7
|
+
|
8
|
+
# Specs
|
9
|
+
RSpec::Core::RakeTask.new(:spec)
|
10
|
+
|
11
|
+
desc "Run all test suites"
|
12
|
+
task :test => [:spec]
|
13
|
+
|
14
|
+
# Rubocop
|
15
|
+
desc "Run Rubocop lint checks"
|
16
|
+
task :rubocop do
|
17
|
+
RuboCop::RakeTask.new
|
18
|
+
end
|
19
|
+
|
20
|
+
# lint the project
|
21
|
+
desc "Run robocop linter"
|
22
|
+
task lint: [:rubocop]
|
23
|
+
|
24
|
+
desc "Display LOC stats"
|
25
|
+
task :stats do
|
26
|
+
puts "\n## Production Code Stats"
|
27
|
+
sh "countloc -r lib/kitchen"
|
28
|
+
puts "\n## Test Code Stats"
|
29
|
+
sh "countloc -r spec"
|
30
|
+
end
|
31
|
+
|
32
|
+
desc "Run all quality tasks"
|
33
|
+
task :quality => [:lint, :stats]
|
34
|
+
|
35
|
+
task :default => [:test, :quality]
|
36
|
+
|
37
|
+
# Automatically generate a changelog for this project. Only loaded if
|
38
|
+
# the necessary gem is installed.
|
39
|
+
begin
|
40
|
+
require "github_changelog_generator/task"
|
41
|
+
GitHubChangelogGenerator::RakeTask.new :changelog
|
42
|
+
rescue LoadError
|
43
|
+
puts ">>>>> GitHub Changelog Generator not loaded, omitting tasks"
|
44
|
+
end
|
45
|
+
|
46
|
+
# Print the current version of this gem or update it.
|
47
|
+
#
|
48
|
+
# @param [Type] target the new version you want to set, or nil if you only want to show
|
49
|
+
def kitchen_inspec_version(target = nil)
|
50
|
+
path = "lib/kitchen/verifier/inspec_version.rb"
|
51
|
+
require_relative path.sub(/.rb$/, "")
|
52
|
+
|
53
|
+
nu_version = target.nil? ? "" : " -> #{target}"
|
54
|
+
puts "Kitchen-inspec: #{Kitchen::Verifier::INSPEC_VERSION}#{nu_version}"
|
55
|
+
|
56
|
+
unless target.nil?
|
57
|
+
raw = File.read(path)
|
58
|
+
nu = raw.sub(/INSPEC_VERSION.*/, "INSPEC_VERSION = \"#{target}\"")
|
59
|
+
File.write(path, nu)
|
60
|
+
load(path)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Check if a command is available
|
65
|
+
#
|
66
|
+
# @param [Type] x the command you are interested in
|
67
|
+
# @param [Type] msg the message to display if the command is missing
|
68
|
+
def require_command(x, msg = nil)
|
69
|
+
return if system("command -v #{x} || exit 1")
|
70
|
+
msg ||= "Please install it first!"
|
71
|
+
puts "\033[31;1mCan't find command #{x.inspect}. #{msg}\033[0m"
|
72
|
+
exit 1
|
73
|
+
end
|
74
|
+
|
75
|
+
# Check if a required environment variable has been set
|
76
|
+
#
|
77
|
+
# @param [String] x the variable you are interested in
|
78
|
+
# @param [String] msg the message you want to display if the variable is missing
|
79
|
+
def require_env(x, msg = nil)
|
80
|
+
exists = `env | grep "^#{x}="`
|
81
|
+
return unless exists.empty?
|
82
|
+
puts "\033[31;1mCan't find environment variable #{x.inspect}. #{msg}\033[0m"
|
83
|
+
exit 1
|
84
|
+
end
|
85
|
+
|
86
|
+
# Check the requirements for running an update of this repository.
|
87
|
+
def check_update_requirements
|
88
|
+
require_command "git"
|
89
|
+
require_command "github_changelog_generator", "\n"\
|
90
|
+
"For more information on how to install it see:\n"\
|
91
|
+
" https://github.com/skywinder/github-changelog-generator\n"
|
92
|
+
require_env "CHANGELOG_GITHUB_TOKEN", "\n"\
|
93
|
+
"Please configure this token to make sure you can run all commands\n"\
|
94
|
+
"against GitHub.\n\n"\
|
95
|
+
"See github_changelog_generator homepage for more information:\n"\
|
96
|
+
" https://github.com/skywinder/github-changelog-generator\n"
|
97
|
+
end
|
98
|
+
|
99
|
+
# Show the current version of this gem.
|
100
|
+
desc "Show the version of this gem"
|
101
|
+
task :version do
|
102
|
+
kitchen_inspec_version
|
103
|
+
end
|
104
|
+
|
105
|
+
desc "Generate the changelog"
|
106
|
+
task :changelog do
|
107
|
+
require_relative "lib/kitchen/verifier/inspec_version"
|
108
|
+
system "github_changelog_generator -u chef -p kitchen-inspec --future-release #{Kitchen::Verifier::INSPEC_VERSION}"
|
109
|
+
end
|
110
|
+
|
111
|
+
# Update the version of this gem and create an updated
|
112
|
+
# changelog. It covers everything short of actually releasing
|
113
|
+
# the gem.
|
114
|
+
desc "Bump the version of this gem"
|
115
|
+
task :bump_version, [:version] do |_, args|
|
116
|
+
v = args[:version] || ENV["to"]
|
117
|
+
raise "You must specify a target version! rake release[1.2.3]" if v.empty?
|
118
|
+
check_update_requirements
|
119
|
+
kitchen_inspec_version(v)
|
120
|
+
Rake::Task["changelog"].invoke
|
121
|
+
end
|
122
|
+
|
123
|
+
namespace :test do
|
124
|
+
task :integration do
|
125
|
+
concurrency = ENV["CONCURRENCY"] || 1
|
126
|
+
os = ENV["OS"] || ""
|
127
|
+
sh("sh", "-c", "bundle exec kitchen test -c #{concurrency} #{os}")
|
128
|
+
end
|
129
|
+
end
|