inspec 2.2.102 → 2.2.112

Sign up to get free protection for your applications and to get access to all the features.
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