inspec 2.2.102 → 2.2.112
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -0
- data/CHANGELOG.md +25 -7
- data/Rakefile +8 -2
- data/docs/profiles.md +9 -0
- data/docs/resources/aws_security_group.md.erb +19 -2
- data/docs/resources/gem.md.erb +24 -5
- data/docs/resources/mssql_session.md.erb +8 -0
- data/lib/inspec/plugin/v2/loader.rb +33 -7
- data/lib/inspec/reporters/json_automate.rb +1 -1
- data/lib/inspec/version.rb +1 -1
- data/lib/plugins/README.md +16 -0
- data/lib/plugins/inspec-artifact/lib/inspec-artifact.rb +12 -0
- data/lib/plugins/inspec-artifact/lib/inspec-artifact/base.rb +162 -0
- data/lib/plugins/inspec-artifact/lib/inspec-artifact/cli.rb +114 -0
- data/lib/plugins/inspec-artifact/test/functional/inspec_artifact_test.rb +46 -0
- data/lib/plugins/inspec-habitat/lib/inspec-habitat.rb +11 -0
- data/lib/plugins/inspec-habitat/lib/inspec-habitat/cli.rb +39 -0
- data/lib/plugins/inspec-habitat/lib/inspec-habitat/profile.rb +394 -0
- data/lib/plugins/inspec-habitat/test/unit/profile_test.rb +184 -0
- data/lib/{bundles → plugins}/inspec-init/README.md +0 -0
- data/lib/plugins/inspec-init/lib/inspec-init.rb +12 -0
- data/lib/plugins/inspec-init/lib/inspec-init/cli.rb +28 -0
- data/lib/plugins/inspec-init/lib/inspec-init/renderer.rb +81 -0
- data/lib/{bundles → plugins/inspec-init/lib}/inspec-init/templates/profile/README.md +0 -0
- data/lib/{bundles → plugins/inspec-init/lib}/inspec-init/templates/profile/controls/example.rb +0 -0
- data/lib/{bundles → plugins/inspec-init/lib}/inspec-init/templates/profile/inspec.yml +0 -0
- data/lib/{bundles → plugins/inspec-init/lib}/inspec-init/templates/profile/libraries/.gitkeep +0 -0
- data/lib/plugins/inspec-init/test/functional/inspec_init_test.rb +30 -0
- data/lib/plugins/shared/core_plugin_test_helper.rb +50 -0
- data/lib/resources/aws/aws_security_group.rb +38 -6
- data/lib/resources/gem.rb +7 -1
- data/lib/resources/mssql_session.rb +4 -2
- metadata +21 -17
- data/lib/bundles/inspec-artifact.rb +0 -7
- data/lib/bundles/inspec-artifact/README.md +0 -1
- data/lib/bundles/inspec-artifact/cli.rb +0 -278
- data/lib/bundles/inspec-habitat.rb +0 -12
- data/lib/bundles/inspec-habitat/cli.rb +0 -37
- data/lib/bundles/inspec-habitat/log.rb +0 -10
- data/lib/bundles/inspec-habitat/profile.rb +0 -391
- data/lib/bundles/inspec-init.rb +0 -12
- data/lib/bundles/inspec-init/cli.rb +0 -39
- data/lib/bundles/inspec-init/renderer.rb +0 -79
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ed479c2bc17fad9ab4aefa69f119d6448332b4e2f5befac16f427fa589a8cef8
|
4
|
+
data.tar.gz: 6e055c297017f08684d15780060e2a9bf528f1f1579e0f8224a35202aad73c66
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b3be7a2eb3219f1ceabad6ce163ae24f644475a67a3825f9163c7a572be3a54db5dad11dc5765d28f5330fa5fea5ce7b535e887e56aa86749dcf3c6453c8b9e2
|
7
|
+
data.tar.gz: bab90ce890a5973fc24d8d02be94c88673553a0164dd0d6f5675247223244d232fd6f6a253ff0d3141549fb0f5f4857bdd984ab60ab03d2a5620f5325927f818
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,20 +1,39 @@
|
|
1
1
|
# Change Log
|
2
2
|
<!-- usage documentation: http://expeditor-docs.es.chef.io/configuration/changelog/ -->
|
3
|
-
<!-- latest_release 2.2.
|
4
|
-
## [v2.2.
|
3
|
+
<!-- latest_release 2.2.112 -->
|
4
|
+
## [v2.2.112](https://github.com/inspec/inspec/tree/v2.2.112) (2018-09-19)
|
5
5
|
|
6
6
|
#### Merged Pull Requests
|
7
|
-
-
|
7
|
+
- Move artifact to v2 plugin [#3406](https://github.com/inspec/inspec/pull/3406) ([jquick](https://github.com/jquick))
|
8
8
|
<!-- latest_release -->
|
9
9
|
|
10
|
-
<!-- release_rollup since=2.2.
|
11
|
-
### Changes since 2.2.
|
10
|
+
<!-- release_rollup since=2.2.102 -->
|
11
|
+
### Changes since 2.2.102 release
|
12
|
+
|
13
|
+
#### Enhancements
|
14
|
+
- adding `versions` to the `gem` resource [#3398](https://github.com/inspec/inspec/pull/3398) ([majormoses](https://github.com/majormoses)) <!-- 2.2.107 -->
|
15
|
+
- Plugins: Add support for 'bundles' migration [#3384](https://github.com/inspec/inspec/pull/3384) ([clintoncwolfe](https://github.com/clintoncwolfe)) <!-- 2.2.105 -->
|
16
|
+
|
17
|
+
#### New Features
|
18
|
+
- Update AWS Security Group to work with IPV6 rules. [#3394](https://github.com/inspec/inspec/pull/3394) ([MartinLogan](https://github.com/MartinLogan)) <!-- 2.2.111 -->
|
19
|
+
- Added db_name flag [#3383](https://github.com/inspec/inspec/pull/3383) ([kdoores](https://github.com/kdoores)) <!-- 2.2.104 -->
|
12
20
|
|
13
21
|
#### Merged Pull Requests
|
14
|
-
-
|
22
|
+
- Move artifact to v2 plugin [#3406](https://github.com/inspec/inspec/pull/3406) ([jquick](https://github.com/jquick)) <!-- 2.2.112 -->
|
23
|
+
- Move inspec init to v2 plugins [#3407](https://github.com/inspec/inspec/pull/3407) ([jquick](https://github.com/jquick)) <!-- 2.2.110 -->
|
24
|
+
- Fix gem tests from recent merge [#3409](https://github.com/inspec/inspec/pull/3409) ([jquick](https://github.com/jquick)) <!-- 2.2.109 -->
|
25
|
+
- Fix json automate tests and render call [#3408](https://github.com/inspec/inspec/pull/3408) ([jquick](https://github.com/jquick)) <!-- 2.2.108 -->
|
26
|
+
- Move habitat to v2 plugin [#3404](https://github.com/inspec/inspec/pull/3404) ([jquick](https://github.com/jquick)) <!-- 2.2.106 -->
|
27
|
+
- Fix rendering of profiles docs [#3393](https://github.com/inspec/inspec/pull/3393) ([jquick](https://github.com/jquick)) <!-- 2.2.103 -->
|
15
28
|
<!-- release_rollup -->
|
16
29
|
|
17
30
|
<!-- latest_stable_release -->
|
31
|
+
## [v2.2.102](https://github.com/inspec/inspec/tree/v2.2.102) (2018-09-17)
|
32
|
+
|
33
|
+
#### Merged Pull Requests
|
34
|
+
- Add json-automate to the report method [#3401](https://github.com/inspec/inspec/pull/3401) ([jquick](https://github.com/jquick))
|
35
|
+
<!-- latest_stable_release -->
|
36
|
+
|
18
37
|
## [v2.2.101](https://github.com/inspec/inspec/tree/v2.2.101) (2018-09-14)
|
19
38
|
|
20
39
|
#### New Features
|
@@ -44,7 +63,6 @@
|
|
44
63
|
- Bump omnibus ruby to 2.5.1 [#3390](https://github.com/inspec/inspec/pull/3390) ([jquick](https://github.com/jquick))
|
45
64
|
- Add platforms schema command [#3346](https://github.com/inspec/inspec/pull/3346) ([jquick](https://github.com/jquick))
|
46
65
|
- Fix profile vendoring on Windows [#3378](https://github.com/inspec/inspec/pull/3378) ([jerryaldrichiii](https://github.com/jerryaldrichiii))
|
47
|
-
<!-- latest_stable_release -->
|
48
66
|
|
49
67
|
## [v2.2.78](https://github.com/inspec/inspec/tree/v2.2.78) (2018-08-30)
|
50
68
|
|
data/Rakefile
CHANGED
@@ -54,7 +54,10 @@ task default: [:lint, :test]
|
|
54
54
|
|
55
55
|
Rake::TestTask.new do |t|
|
56
56
|
t.libs << 'test'
|
57
|
-
t.
|
57
|
+
t.test_files = Dir.glob([
|
58
|
+
'test/unit/**/*_test.rb',
|
59
|
+
'lib/plugins/inspec-*/test/unit/**/*_test.rb',
|
60
|
+
])
|
58
61
|
t.warning = true
|
59
62
|
t.verbose = true
|
60
63
|
t.ruby_opts = ['--dev'] if defined?(JRUBY_VERSION)
|
@@ -69,7 +72,10 @@ namespace :test do
|
|
69
72
|
|
70
73
|
Rake::TestTask.new(:functional) do |t|
|
71
74
|
t.libs << 'test'
|
72
|
-
t.
|
75
|
+
t.test_files = Dir.glob([
|
76
|
+
'test/functional/**/*_test.rb',
|
77
|
+
'lib/plugins/inspec-*/test/functional/**/*_test.rb',
|
78
|
+
])
|
73
79
|
t.warning = true
|
74
80
|
t.verbose = true
|
75
81
|
t.ruby_opts = ['--dev'] if defined?(JRUBY_VERSION)
|
data/docs/profiles.md
CHANGED
@@ -348,6 +348,7 @@ Attributes may contain the following options:
|
|
348
348
|
|
349
349
|
|
350
350
|
You can specify attributes in your `inspec.yml` using the `attributes` setting. For example, to add a `user` attribute for your profile:
|
351
|
+
|
351
352
|
```YAML
|
352
353
|
attributes:
|
353
354
|
- name: user
|
@@ -356,6 +357,7 @@ attributes:
|
|
356
357
|
```
|
357
358
|
|
358
359
|
Example of adding a array object of servers:
|
360
|
+
|
359
361
|
```YAML
|
360
362
|
attributes:
|
361
363
|
- name: servers
|
@@ -369,6 +371,7 @@ attributes:
|
|
369
371
|
To access an attribute you will use the `attribute` keyword. You can use this anywhere in your control code.
|
370
372
|
|
371
373
|
For example:
|
374
|
+
|
372
375
|
```Ruby
|
373
376
|
current_user = attribute('user')
|
374
377
|
|
@@ -386,6 +389,7 @@ end
|
|
386
389
|
For sensitive data it is recomended to use a secrets YAML file located on the local machine to populate the values of attributes. A secrets file will always overwrite a attributes default value. To use the secrets file run `inspec exec` and specify the path to that Yaml file using the `--attrs` attribute.
|
387
390
|
|
388
391
|
For example, a inspec.yml:
|
392
|
+
|
389
393
|
```YAML
|
390
394
|
attributes:
|
391
395
|
- name: username
|
@@ -432,6 +436,7 @@ $ inspec exec examples/profile-attribute --attrs examples/profile-attribute.yml
|
|
432
436
|
To change your attributes for platform specific cases you can setup multiple `--attrs` files.
|
433
437
|
|
434
438
|
For example, a inspec.yml:
|
439
|
+
|
435
440
|
```YAML
|
436
441
|
attributes:
|
437
442
|
- name: users
|
@@ -440,6 +445,7 @@ attributes:
|
|
440
445
|
```
|
441
446
|
|
442
447
|
A YAML file named `windows.yml`
|
448
|
+
|
443
449
|
```YAML
|
444
450
|
users:
|
445
451
|
- Administrator
|
@@ -448,6 +454,7 @@ users:
|
|
448
454
|
```
|
449
455
|
|
450
456
|
A YAML file named `linux.yml`
|
457
|
+
|
451
458
|
```YAML
|
452
459
|
users:
|
453
460
|
- root
|
@@ -456,6 +463,7 @@ users:
|
|
456
463
|
```
|
457
464
|
|
458
465
|
The control file:
|
466
|
+
|
459
467
|
```RUBY
|
460
468
|
control 'system-users' do
|
461
469
|
impact 0.8
|
@@ -468,6 +476,7 @@ end
|
|
468
476
|
```
|
469
477
|
|
470
478
|
The following command runs the tests and applies the attributes specified:
|
479
|
+
|
471
480
|
```bash
|
472
481
|
$ inspec exec examples/profile-attribute --attrs examples/windows.yml
|
473
482
|
$ inspec exec examples/profile-attribute --attrs examples/linux.yml
|
@@ -12,7 +12,6 @@ SGs are a networking construct which contain ingress and egress rules for networ
|
|
12
12
|
|
13
13
|
While this resource provides facilities for searching inbound and outbound rules on a variety of criteria, there is currently no support for performing matches based on:
|
14
14
|
|
15
|
-
* IPv6 ranges
|
16
15
|
* References to other Security Groups
|
17
16
|
* References to VPC peers or other AWS services (that is, no support for searches based on 'prefix lists').
|
18
17
|
|
@@ -143,7 +142,7 @@ A string identifying the VPC that contains the Security Group. Since VPCs common
|
|
143
142
|
<br>
|
144
143
|
## Properties
|
145
144
|
|
146
|
-
* [`description`](#description), [`group_id`](#group_id), [`group_name`](#group_name), [`inbound_rules`](#inbound_rules), [`outbound_rules`](#outbound_rules), [`vpc_id`](#vpc_id)
|
145
|
+
* [`description`](#description), [`group_id`](#group_id), [`group_name`](#group_name), [`inbound_rules`](#inbound_rules), [`inbound_rules_count`](#inbound_rules_count), [`outbound_rules`](#outbound_rules), [`outbound_rules_count`](#outbound_rules_count), [`vpc_id`](#vpc_id)
|
147
146
|
|
148
147
|
<br>
|
149
148
|
|
@@ -191,6 +190,14 @@ If the Security Group could not be found (that is, `exists` is false), `inbound_
|
|
191
190
|
its('inbound_rules.first') { should include(from_port: '22', ip_ranges: ['10.2.17.0/24']) }
|
192
191
|
end
|
193
192
|
|
193
|
+
### inbound\_rules\_count
|
194
|
+
|
195
|
+
A Number totalling the number of individual rules defined - It is a sum of the combinations of port, protocol, ipv4 rules, ipv6 rules and security group rules.
|
196
|
+
|
197
|
+
describe aws_security_group(group_name: linux_servers) do
|
198
|
+
its('inbound_rules_count'){ should eq 10 }
|
199
|
+
end
|
200
|
+
|
194
201
|
### outbound\_rules
|
195
202
|
|
196
203
|
A list of the rules that the Security Group applies to outgoing network traffic initiated by the AWS resource in the Security Group. This is a low-level property that is used by the [`allow_out`](#allow_out) matcher; see it for detailed examples. `outbound_rules` is provided here for those wishing to use Ruby code to inspect the rules directly, instead of using higher-level matchers.
|
@@ -203,6 +210,14 @@ If the Security Group could not be found (that is, `exists` is false), `outbound
|
|
203
210
|
its('outbound_rules.last') { should_not include(ip_ranges:['0.0.0.0/0']) }
|
204
211
|
end
|
205
212
|
|
213
|
+
### outbound\_rules\_count
|
214
|
+
|
215
|
+
A Number totalling the number of individual rules defined - It is a sum of the combinations of port, protocol, ipv4 rules, ipv6 rules and security group rules.
|
216
|
+
|
217
|
+
describe aws_security_group(group_name: linux_servers) do
|
218
|
+
its('outbound_rules_count'){ should eq 2 }
|
219
|
+
end
|
220
|
+
|
206
221
|
### vpc\_id
|
207
222
|
|
208
223
|
A String in the format 'vpc-' followed by 8 hexadecimal characters reflecting VPC that contains the Security Group.
|
@@ -240,6 +255,7 @@ The matchers accept a key-value list of search criteria. For a rule to match, i
|
|
240
255
|
|
241
256
|
* from_port - Determines if a rule exists whose port range begins at the specified number. The word 'from_' does *not* relate to inbound/outbound directionality; it relates to the port range ("counting _from_"). `from_port` is an exact criterion; so if the rule allows 1000-2000 and you specify a `from_port` of 1001, it does not match.
|
242
257
|
* ipv4_range - Specifies an IPv4 address or subnet as a CIDR, or a list of them, to be checked as a permissible origin (for `allow_in`) or destination (for `allow_out`) for traffic. Each AWS Security Group rule may have multiple allowed source IP ranges.
|
258
|
+
* ipv6_range - Specifies an IPv6 address or subnet as a CIDR, or a list of them, to be checked as a permissible origin (for `allow_in`) or destination (for `allow_out`) for traffic. Each AWS Security Group rule may have multiple allowed source IP ranges.
|
243
259
|
* port - Determines if a particular TCP/IP port is reachable. allow_in and allow_out examine whether the specified port is included in the port range of a rule, while allow_in. You may specify the port as a string (`'22'`) or as a number.
|
244
260
|
* position - A one-based index into the list of rules. If provided, this restricts the evaluation to the rule at that position. You may also use the special values `:first` and `:last`. `position` may also be used to enable `allow_in_only` and `allow_out_only` to work with multi-rule Security Groups.
|
245
261
|
* protocol - Specifies the IP protocol. 'tcp', 'udp', and 'icmp' are some typical values. The string "-1" or 'any' is used to indicate any protocol.
|
@@ -248,6 +264,7 @@ The matchers accept a key-value list of search criteria. For a rule to match, i
|
|
248
264
|
describe aws_security_group(group_name: 'mixed-functionality-group') do
|
249
265
|
# Allow RDP from defined range
|
250
266
|
it { should allow_in(port: 3389, ipv4_range: '10.5.0.0/16') }
|
267
|
+
it { should allow_in(port: 3389, ipv6_range: '2001:db8::/122') }
|
251
268
|
|
252
269
|
# Allow SSH from two ranges
|
253
270
|
it { should allow_in(port: 22, ipv4_range: ['10.5.0.0/16', '10.2.3.0/24']) }
|
data/docs/resources/gem.md.erb
CHANGED
@@ -46,6 +46,15 @@ The following examples show how to use this InSpec audit resource.
|
|
46
46
|
its('version') { should eq '0.33.0' }
|
47
47
|
end
|
48
48
|
|
49
|
+
### Verify that a particular version is installed when there are multiple versions installed
|
50
|
+
|
51
|
+
describe gem('rubocop') do
|
52
|
+
it { should be_installed }
|
53
|
+
its('versions') { should include /0.51.0/ }
|
54
|
+
its('versions.count') { should_not be > 3 }
|
55
|
+
end
|
56
|
+
|
57
|
+
|
49
58
|
### Verify that a gem package is not installed
|
50
59
|
|
51
60
|
describe gem('rubocop') do
|
@@ -72,6 +81,21 @@ The following examples show how to use this InSpec audit resource.
|
|
72
81
|
|
73
82
|
<br>
|
74
83
|
|
84
|
+
## Properties
|
85
|
+
|
86
|
+
### version (String)
|
87
|
+
|
88
|
+
The `version` property returns a string of the default version on the system:
|
89
|
+
|
90
|
+
its('version') { should eq '0.33.0' }
|
91
|
+
|
92
|
+
### versions
|
93
|
+
|
94
|
+
The `versions` property returns an array of strings of all the versions of the gem installed on the system:
|
95
|
+
|
96
|
+
its('versions') { should include /0.33/ }
|
97
|
+
|
98
|
+
|
75
99
|
## Matchers
|
76
100
|
|
77
101
|
For a full list of available matchers, please visit our [matchers page](https://www.inspec.io/docs/reference/matchers/).
|
@@ -82,8 +106,3 @@ The `be_installed` matcher tests if the named Gem package is installed:
|
|
82
106
|
|
83
107
|
it { should be_installed }
|
84
108
|
|
85
|
-
### version
|
86
|
-
|
87
|
-
The `version` matcher tests if the named package version is on the system:
|
88
|
-
|
89
|
-
its('version') { should eq '0.33.0' }
|
@@ -62,6 +62,14 @@ The following examples show how to use this InSpec audit resource.
|
|
62
62
|
describe sql.query("SELECT SERVERPROPERTY('ProductVersion') as result").row(0).column('result') do
|
63
63
|
its("value") { should cmp > '12.00.4457' }
|
64
64
|
end
|
65
|
+
|
66
|
+
### Test a specific database
|
67
|
+
|
68
|
+
sql = mssql_session(user: 'my_user', password: 'password', db_name: 'test')
|
69
|
+
|
70
|
+
describe sql.query("SELECT Name AS result FROM Product WHERE ProductID == 1").row(0).column('result') do
|
71
|
+
its("value") { should eq 'foo' }
|
72
|
+
end
|
65
73
|
|
66
74
|
<br>
|
67
75
|
|
@@ -17,7 +17,14 @@ module Inspec::Plugin::V2
|
|
17
17
|
determine_plugin_conf_file
|
18
18
|
read_conf_file
|
19
19
|
unpack_conf_file
|
20
|
+
|
21
|
+
# Old-style (v0, v1) co-distributed plugins were called 'bundles'
|
22
|
+
# and were located in lib/bundles
|
20
23
|
detect_bundled_plugins unless options[:omit_bundles]
|
24
|
+
|
25
|
+
# New-style (v2) co-distributed plugins are in lib/plugins,
|
26
|
+
# and may be safely loaded
|
27
|
+
detect_core_plugins unless options[:omit_core_plugins]
|
21
28
|
end
|
22
29
|
|
23
30
|
def load_all
|
@@ -26,17 +33,20 @@ module Inspec::Plugin::V2
|
|
26
33
|
# rubocop: disable Lint/RescueException
|
27
34
|
begin
|
28
35
|
# We could use require, but under testing, we need to repeatedly reload the same
|
29
|
-
# plugin.
|
30
|
-
if plugin_details.
|
31
|
-
|
32
|
-
else
|
36
|
+
# plugin. However, gems only work with require (rubygems dooes not overload `load`)
|
37
|
+
if plugin_details.installation_type == :gem
|
38
|
+
activate_managed_gems_for_plugin(plugin_name)
|
33
39
|
require plugin_details.entry_point
|
40
|
+
else
|
41
|
+
load_path = plugin_details.entry_point
|
42
|
+
load_path += '.rb' unless plugin_details.entry_point.end_with?('.rb')
|
43
|
+
load load_path
|
34
44
|
end
|
35
45
|
plugin_details.loaded = true
|
36
46
|
annotate_status_after_loading(plugin_name)
|
37
47
|
rescue ::Exception => ex
|
38
48
|
plugin_details.load_exception = ex
|
39
|
-
Inspec::Log.error "Could not load plugin #{plugin_name}"
|
49
|
+
Inspec::Log.error "Could not load plugin #{plugin_name}: #{ex.message}"
|
40
50
|
end
|
41
51
|
# rubocop: enable Lint/RescueException
|
42
52
|
end
|
@@ -60,7 +70,7 @@ module Inspec::Plugin::V2
|
|
60
70
|
end
|
61
71
|
|
62
72
|
def activate(plugin_type, hook_name)
|
63
|
-
activator = registry.find_activators(plugin_type: plugin_type,
|
73
|
+
activator = registry.find_activators(plugin_type: plugin_type, activator_name: hook_name).first
|
64
74
|
# We want to capture literally any possible exception here, since we are storing them.
|
65
75
|
# rubocop: disable Lint/RescueException
|
66
76
|
begin
|
@@ -80,7 +90,7 @@ module Inspec::Plugin::V2
|
|
80
90
|
next if act.activated
|
81
91
|
# If there is anything in the CLI args with the same name, activate it
|
82
92
|
# If the word 'help' appears in the first position, load all CLI plugins
|
83
|
-
if cli_args.include?(act.activator_name.to_s) || cli_args[0] == 'help'
|
93
|
+
if cli_args.include?(act.activator_name.to_s) || cli_args[0] == 'help' || cli_args.size.zero?
|
84
94
|
activate(:cli_command, act.activator_name)
|
85
95
|
act.implementation_class.register_with_thor
|
86
96
|
end
|
@@ -138,6 +148,22 @@ module Inspec::Plugin::V2
|
|
138
148
|
@plugin_conf_file_path = File.join(@plugin_conf_file_path, 'plugins.json')
|
139
149
|
end
|
140
150
|
|
151
|
+
def detect_core_plugins
|
152
|
+
core_plugins_dir = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'plugins'))
|
153
|
+
# These are expected to be organized as proper separate projects,
|
154
|
+
# with lib/ dirs, etc.
|
155
|
+
Dir.glob(File.join(core_plugins_dir, 'inspec-*')).each do |plugin_dir|
|
156
|
+
status = Inspec::Plugin::V2::Status.new
|
157
|
+
status.name = File.basename(plugin_dir)
|
158
|
+
status.entry_point = File.join(plugin_dir, 'lib', status.name + '.rb')
|
159
|
+
status.installation_type = :path
|
160
|
+
status.loaded = false
|
161
|
+
registry[status.name.to_sym] = status
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# TODO: DRY up re: Installer read_or_init_config_file
|
166
|
+
# TODO: refactor the plugin.json file to have its own class, which Loader consumes
|
141
167
|
def read_conf_file
|
142
168
|
if File.exist?(@plugin_conf_file_path)
|
143
169
|
@plugin_file_contents = JSON.parse(File.read(@plugin_conf_file_path))
|
data/lib/inspec/version.rb
CHANGED
@@ -0,0 +1,16 @@
|
|
1
|
+
# Core Plugins of InSpec
|
2
|
+
|
3
|
+
This area contains the plugins that ship with InSpec. They are automatically detected by the plugin loader.
|
4
|
+
|
5
|
+
## inspec-* directories
|
6
|
+
|
7
|
+
Each subdirectory here that begins with `inspec-` is intended to be a self-contained plugin project,
|
8
|
+
with code, docs, and tests.
|
9
|
+
|
10
|
+
## shared directory
|
11
|
+
|
12
|
+
This directory contains material that is reusable for core plugins, such as a test helper tuned to assisting
|
13
|
+
core plugin testing.
|
14
|
+
|
15
|
+
|
16
|
+
|
@@ -0,0 +1,162 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'openssl'
|
3
|
+
require 'pathname'
|
4
|
+
require 'set'
|
5
|
+
require 'tempfile'
|
6
|
+
require 'yaml'
|
7
|
+
|
8
|
+
module InspecPlugins
|
9
|
+
module Artifact
|
10
|
+
class Base
|
11
|
+
KEY_BITS=2048
|
12
|
+
KEY_ALG=OpenSSL::PKey::RSA
|
13
|
+
|
14
|
+
INSPEC_PROFILE_VERSION_1='INSPEC-PROFILE-1'.freeze
|
15
|
+
INSPEC_REPORT_VERSION_1='INSPEC-REPORT-1'.freeze
|
16
|
+
|
17
|
+
ARTIFACT_DIGEST=OpenSSL::Digest::SHA512
|
18
|
+
ARTIFACT_DIGEST_NAME='SHA512'.freeze
|
19
|
+
|
20
|
+
VALID_PROFILE_VERSIONS=Set.new [INSPEC_PROFILE_VERSION_1]
|
21
|
+
VALID_PROFILE_DIGESTS=Set.new [ARTIFACT_DIGEST_NAME]
|
22
|
+
|
23
|
+
SIGNED_PROFILE_SUFFIX='iaf'.freeze
|
24
|
+
SIGNED_REPORT_SUFFIX='iar'.freeze
|
25
|
+
|
26
|
+
def self.keygen(options)
|
27
|
+
key = KEY_ALG.new KEY_BITS
|
28
|
+
puts 'Generating private key'
|
29
|
+
open "#{options['keyname']}.pem.key", 'w' do |io| io.write key.to_pem end
|
30
|
+
puts 'Generating public key'
|
31
|
+
open "#{options['keyname']}.pem.pub", 'w' do |io| io.write key.public_key.to_pem end
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.profile_sign(options)
|
35
|
+
artifact = new
|
36
|
+
Dir.mktmpdir do |workdir|
|
37
|
+
puts "Signing #{options['profile']} with key #{options['keyname']}"
|
38
|
+
path_to_profile = options['profile']
|
39
|
+
profile_md = artifact.read_profile_metadata(path_to_profile)
|
40
|
+
artifact_filename = "#{profile_md['name']}-#{profile_md['version']}.#{SIGNED_PROFILE_SUFFIX}"
|
41
|
+
tarfile = artifact.profile_compress(path_to_profile, profile_md, workdir)
|
42
|
+
content = IO.binread(tarfile)
|
43
|
+
signing_key = KEY_ALG.new File.read "#{options['keyname']}.pem.key"
|
44
|
+
sha = ARTIFACT_DIGEST.new
|
45
|
+
signature = signing_key.sign sha, content
|
46
|
+
# convert the signature to Base64
|
47
|
+
signature_base64 = Base64.encode64(signature)
|
48
|
+
tar_content = IO.binread(tarfile)
|
49
|
+
File.open(artifact_filename, 'wb') do |f|
|
50
|
+
f.puts(INSPEC_PROFILE_VERSION_1)
|
51
|
+
f.puts(options['keyname'])
|
52
|
+
f.puts(ARTIFACT_DIGEST_NAME)
|
53
|
+
f.puts(signature_base64)
|
54
|
+
f.puts('') # newline separates artifact header with body
|
55
|
+
f.write(tar_content)
|
56
|
+
end
|
57
|
+
puts "Successfully generated #{artifact_filename}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.profile_verify(options)
|
62
|
+
artifact = new
|
63
|
+
file_to_verifiy = options['infile']
|
64
|
+
puts "Verifying #{file_to_verifiy}"
|
65
|
+
artifact.verify(file_to_verifiy) do ||
|
66
|
+
puts 'Artifact is valid'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.profile_install(options)
|
71
|
+
artifact = new
|
72
|
+
puts 'Installing profile'
|
73
|
+
file_to_verifiy = options['infile']
|
74
|
+
dest_dir = options['destdir']
|
75
|
+
artifact.verify(file_to_verifiy) do |content|
|
76
|
+
Dir.mktmpdir do |workdir|
|
77
|
+
tmpfile = Pathname.new(workdir).join('artifact_to_install.tar.gz')
|
78
|
+
File.write(tmpfile, content)
|
79
|
+
puts "Installing to #{dest_dir}"
|
80
|
+
`tar xzf #{tmpfile} -C #{dest_dir}`
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def read_profile_metadata(path_to_profile)
|
86
|
+
begin
|
87
|
+
p = Pathname.new(path_to_profile)
|
88
|
+
p = p.join('inspec.yml')
|
89
|
+
if not p.exist?
|
90
|
+
raise "#{path_to_profile} doesn't appear to be a valid Inspec profile"
|
91
|
+
end
|
92
|
+
yaml = YAML.load_file(p.to_s)
|
93
|
+
yaml = yaml.to_hash
|
94
|
+
|
95
|
+
if not yaml.key? 'name'
|
96
|
+
raise 'Profile is invalid, name is not defined'
|
97
|
+
end
|
98
|
+
|
99
|
+
if not yaml.key? 'version'
|
100
|
+
raise 'Profile is invalid, version is not defined'
|
101
|
+
end
|
102
|
+
rescue => e
|
103
|
+
# rewrap it and pass it up to the CLI
|
104
|
+
raise "Error reading Inspec profile metadata: #{e}"
|
105
|
+
end
|
106
|
+
|
107
|
+
yaml
|
108
|
+
end
|
109
|
+
|
110
|
+
def profile_compress(path_to_profile, profile_md, workdir)
|
111
|
+
profile_name = profile_md['name']
|
112
|
+
profile_version = profile_md['version']
|
113
|
+
outfile_name = "#{workdir}/#{profile_name}-#{profile_version}.tar.gz"
|
114
|
+
`tar czf #{outfile_name} -C #{path_to_profile} .`
|
115
|
+
outfile_name
|
116
|
+
end
|
117
|
+
|
118
|
+
def valid_header?(file_alg, file_version, file_keyname)
|
119
|
+
public_keyfile = "#{file_keyname}.pem.pub"
|
120
|
+
puts "Looking for #{public_keyfile} to verify artifact"
|
121
|
+
if !File.exist? public_keyfile
|
122
|
+
raise "Can't find #{public_keyfile}"
|
123
|
+
end
|
124
|
+
|
125
|
+
raise 'Invalid artifact digest algorithm detected' if !VALID_PROFILE_DIGESTS.member?(file_alg)
|
126
|
+
raise 'Invalid artifact version detected' if !VALID_PROFILE_VERSIONS.member?(file_version)
|
127
|
+
end
|
128
|
+
|
129
|
+
def verify(file_to_verifiy, &content_block)
|
130
|
+
f = File.open(file_to_verifiy, 'r')
|
131
|
+
file_version = f.readline.strip!
|
132
|
+
file_keyname = f.readline.strip!
|
133
|
+
file_alg = f.readline.strip!
|
134
|
+
|
135
|
+
file_sig = ''
|
136
|
+
# the signature is multi-line
|
137
|
+
while (line = f.readline) != "\n"
|
138
|
+
file_sig += line
|
139
|
+
end
|
140
|
+
file_sig.strip!
|
141
|
+
f.close
|
142
|
+
|
143
|
+
valid_header?(file_alg, file_version, file_keyname)
|
144
|
+
|
145
|
+
public_keyfile = "#{file_keyname}.pem.pub"
|
146
|
+
verification_key = KEY_ALG.new File.read public_keyfile
|
147
|
+
|
148
|
+
f = File.open(file_to_verifiy, 'r')
|
149
|
+
while f.readline != "\n" do end
|
150
|
+
content = f.read
|
151
|
+
|
152
|
+
signature = Base64.decode64(file_sig)
|
153
|
+
digest = ARTIFACT_DIGEST.new
|
154
|
+
if verification_key.verify digest, signature, content
|
155
|
+
content_block.yield(content)
|
156
|
+
else
|
157
|
+
puts 'Artifact is invalid'
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|