inspec 2.2.102 → 2.2.112

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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -0
  3. data/CHANGELOG.md +25 -7
  4. data/Rakefile +8 -2
  5. data/docs/profiles.md +9 -0
  6. data/docs/resources/aws_security_group.md.erb +19 -2
  7. data/docs/resources/gem.md.erb +24 -5
  8. data/docs/resources/mssql_session.md.erb +8 -0
  9. data/lib/inspec/plugin/v2/loader.rb +33 -7
  10. data/lib/inspec/reporters/json_automate.rb +1 -1
  11. data/lib/inspec/version.rb +1 -1
  12. data/lib/plugins/README.md +16 -0
  13. data/lib/plugins/inspec-artifact/lib/inspec-artifact.rb +12 -0
  14. data/lib/plugins/inspec-artifact/lib/inspec-artifact/base.rb +162 -0
  15. data/lib/plugins/inspec-artifact/lib/inspec-artifact/cli.rb +114 -0
  16. data/lib/plugins/inspec-artifact/test/functional/inspec_artifact_test.rb +46 -0
  17. data/lib/plugins/inspec-habitat/lib/inspec-habitat.rb +11 -0
  18. data/lib/plugins/inspec-habitat/lib/inspec-habitat/cli.rb +39 -0
  19. data/lib/plugins/inspec-habitat/lib/inspec-habitat/profile.rb +394 -0
  20. data/lib/plugins/inspec-habitat/test/unit/profile_test.rb +184 -0
  21. data/lib/{bundles → plugins}/inspec-init/README.md +0 -0
  22. data/lib/plugins/inspec-init/lib/inspec-init.rb +12 -0
  23. data/lib/plugins/inspec-init/lib/inspec-init/cli.rb +28 -0
  24. data/lib/plugins/inspec-init/lib/inspec-init/renderer.rb +81 -0
  25. data/lib/{bundles → plugins/inspec-init/lib}/inspec-init/templates/profile/README.md +0 -0
  26. data/lib/{bundles → plugins/inspec-init/lib}/inspec-init/templates/profile/controls/example.rb +0 -0
  27. data/lib/{bundles → plugins/inspec-init/lib}/inspec-init/templates/profile/inspec.yml +0 -0
  28. data/lib/{bundles → plugins/inspec-init/lib}/inspec-init/templates/profile/libraries/.gitkeep +0 -0
  29. data/lib/plugins/inspec-init/test/functional/inspec_init_test.rb +30 -0
  30. data/lib/plugins/shared/core_plugin_test_helper.rb +50 -0
  31. data/lib/resources/aws/aws_security_group.rb +38 -6
  32. data/lib/resources/gem.rb +7 -1
  33. data/lib/resources/mssql_session.rb +4 -2
  34. metadata +21 -17
  35. data/lib/bundles/inspec-artifact.rb +0 -7
  36. data/lib/bundles/inspec-artifact/README.md +0 -1
  37. data/lib/bundles/inspec-artifact/cli.rb +0 -278
  38. data/lib/bundles/inspec-habitat.rb +0 -12
  39. data/lib/bundles/inspec-habitat/cli.rb +0 -37
  40. data/lib/bundles/inspec-habitat/log.rb +0 -10
  41. data/lib/bundles/inspec-habitat/profile.rb +0 -391
  42. data/lib/bundles/inspec-init.rb +0 -12
  43. data/lib/bundles/inspec-init/cli.rb +0 -39
  44. data/lib/bundles/inspec-init/renderer.rb +0 -79
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6a09a7de457b9f4594e294d9e4718f7f0e310af828ce5dde58204e44767160f7
4
- data.tar.gz: 42e21f6831ee20c1e133ba0d1113fb4cff14d9661d7232d03a5f48121f5bc481
3
+ metadata.gz: ed479c2bc17fad9ab4aefa69f119d6448332b4e2f5befac16f427fa589a8cef8
4
+ data.tar.gz: 6e055c297017f08684d15780060e2a9bf528f1f1579e0f8224a35202aad73c66
5
5
  SHA512:
6
- metadata.gz: 8912827bfa520e5d11a837541d51355804997eb1ef1898cf4605d69a8eaa65c02d20c8416865a47b8190661c9f4f445ab86e921ea8cae4ba7901ffaafc4ca0f1
7
- data.tar.gz: b6ca37fa419e180e2f6bb535f646af152618ac57a6a4d8c7c6e9ca353e337c456291834f05c3ff5dc51ffa2631af38f8802785244345aa336a5fefb1de87e052
6
+ metadata.gz: b3be7a2eb3219f1ceabad6ce163ae24f644475a67a3825f9163c7a572be3a54db5dad11dc5765d28f5330fa5fea5ce7b535e887e56aa86749dcf3c6453c8b9e2
7
+ data.tar.gz: bab90ce890a5973fc24d8d02be94c88673553a0164dd0d6f5675247223244d232fd6f6a253ff0d3141549fb0f5f4857bdd984ab60ab03d2a5620f5325927f818
data/.rubocop.yml CHANGED
@@ -7,6 +7,7 @@ AllCops:
7
7
  - 'test/**/*'
8
8
  - 'examples/**/*'
9
9
  - 'vendor/**/*'
10
+ - 'lib/plugins/inspec-*/test/**/*'
10
11
  - 'lib/bundles/inspec-init/templates/**/*'
11
12
  - 'www/demo/**/*'
12
13
  AlignParameters:
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.102 -->
4
- ## [v2.2.102](https://github.com/inspec/inspec/tree/v2.2.102) (2018-09-17)
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
- - Add json-automate to the report method [#3401](https://github.com/inspec/inspec/pull/3401) ([jquick](https://github.com/jquick))
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.101 -->
11
- ### Changes since 2.2.101 release
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 &#39;bundles&#39; 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
- - Add json-automate to the report method [#3401](https://github.com/inspec/inspec/pull/3401) ([jquick](https://github.com/jquick)) <!-- 2.2.102 -->
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.pattern = 'test/unit/**/*_test.rb'
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.pattern = 'test/functional/**/*_test.rb'
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']) }
@@ -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.entry_point.include?('test/unit/mock/plugins')
31
- load plugin_details.entry_point + '.rb'
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, activation_name: hook_name).first
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))
@@ -10,7 +10,7 @@ module Inspec::Reporters
10
10
  end
11
11
 
12
12
  def render
13
- output(report_merged.to_json, false)
13
+ output(report.to_json, false)
14
14
  end
15
15
 
16
16
  def report
@@ -4,5 +4,5 @@
4
4
  # author: Christoph Hartmann
5
5
 
6
6
  module Inspec
7
- VERSION = '2.2.102'
7
+ VERSION = '2.2.112'
8
8
  end
@@ -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,12 @@
1
+ module InspecPlugins
2
+ module Artifact
3
+ class Plugin < Inspec.plugin(2)
4
+ plugin_name :'inspec-artifact'
5
+
6
+ cli_command :artifact do
7
+ require_relative 'inspec-artifact/cli'
8
+ InspecPlugins::Artifact::CLI
9
+ end
10
+ end
11
+ end
12
+ end
@@ -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