inspec 1.34.1 → 1.35.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f8652931e666396eaecf1bdfd94e9979cd8dea97
4
- data.tar.gz: 1769b0dea0a7fe11e89943ada4951b1b1d219545
3
+ metadata.gz: 75f7ef6bcd93aae1ea6bda13e5d50675fa234afa
4
+ data.tar.gz: a43bc69d1420af04b82860164873a42f5fc0ba4b
5
5
  SHA512:
6
- metadata.gz: c85ea367f1d2d196cae095cbc3e9479947bb1876718ff55d68db0d506226f5ea2ddccec00bf36e7d2fd296e49337d4c376889bf3aa88680845b51dd09f19b765
7
- data.tar.gz: ef7c008ff3915b2f80bf3fa60a4f302bb0a245cd50cfc6a293e3a788d64ff275b7f642f4dc21594b274c6e1c4aa033ad765c458751e4c2a1778ffffc1bcb48d0
6
+ metadata.gz: 0f7bffcdfa35005e4805026dd0028031713f1ecb30b7fae10d811c79bde5840599df4e35dc9631ffea18d637c768abed92dbe05392d1a7c77efaf1332629e445
7
+ data.tar.gz: b24fc841af39b05e38ee9537e76da3d1b68bcdd07349e59af1c6b140a5298cec578fef54e1167d7b48b348829d02a59054c785a4fb265fd7cce9767868d3f1b5
@@ -1,24 +1,40 @@
1
1
  # Change Log
2
2
 
3
- <!-- latest_release 1.33.15 -->
4
- ## [v1.33.15](https://github.com/chef/inspec/tree/v1.33.15) (2017-08-23)
3
+ <!-- latest_release 1.34.10 -->
4
+ ## [v1.34.10](https://github.com/chef/inspec/tree/v1.34.10) (2017-08-31)
5
5
 
6
- #### Enhancements
7
- - Refine the profile/test summary output of the CLI formatter [#2094](https://github.com/chef/inspec/pull/2094) ([adamleff](https://github.com/adamleff))
6
+ #### New Resources
7
+ - etc_hosts resource: test the contents of the /etc/hosts file [#2065](https://github.com/chef/inspec/pull/2065) ([dromazmj](https://github.com/dromazmj))
8
8
  <!-- latest_release -->
9
9
 
10
- <!-- release_rollup since=1.33.12 -->
11
- ### Changes since 1.33.12 release
10
+ <!-- release_rollup since=1.34.1 -->
11
+ ### Changes since 1.34.1 release
12
12
 
13
13
  #### Enhancements
14
- - Refine the profile/test summary output of the CLI formatter [#2094](https://github.com/chef/inspec/pull/2094) ([adamleff](https://github.com/adamleff)) <!-- 1.33.15 -->
14
+ - port resource: support ss instead of netstat [#2110](https://github.com/chef/inspec/pull/2110) ([adamleff](https://github.com/adamleff)) <!-- 1.34.8 -->
15
+ - pip resource: support non-default pip locations, such as virtualenvs [#2097](https://github.com/chef/inspec/pull/2097) ([tonybaloney](https://github.com/tonybaloney)) <!-- 1.34.7 -->
16
+
17
+ #### Bug Fixes
18
+ - Support mixed-case group entries [#2101](https://github.com/chef/inspec/pull/2101) ([adamleff](https://github.com/adamleff)) <!-- 1.34.6 -->
19
+ - http resource: prevent repeat calls during a control with multiple tests [#2108](https://github.com/chef/inspec/pull/2108) ([mivok](https://github.com/mivok)) <!-- 1.34.5 -->
20
+ - auditd_rules resource: fix get_keys error on lines that have no keys [#2103](https://github.com/chef/inspec/pull/2103) ([jburns12](https://github.com/jburns12)) <!-- 1.34.4 -->
15
21
 
16
22
  #### Merged Pull Requests
17
- - Add slack notifications for Travis CI builds to master [#2092](https://github.com/chef/inspec/pull/2092) ([adamleff](https://github.com/adamleff)) <!-- 1.33.14 -->
18
- - Update CHANGELOG (add fix author) [#2091](https://github.com/chef/inspec/pull/2091) ([n-rodriguez](https://github.com/n-rodriguez)) <!-- 1.33.13 -->
23
+ - Add sensitive flag to resources to restrict logging output [#2017](https://github.com/chef/inspec/pull/2017) ([arothian](https://github.com/arothian)) <!-- 1.34.3 -->
24
+
25
+ #### New Resources
26
+ - etc_hosts resource: test the contents of the /etc/hosts file [#2065](https://github.com/chef/inspec/pull/2065) ([dromazmj](https://github.com/dromazmj)) <!-- 1.34.10 -->
27
+ - Add support for XML files [#2107](https://github.com/chef/inspec/pull/2107) ([jonathanmorley](https://github.com/jonathanmorley)) <!-- 1.34.9 -->
28
+ - aide_conf resource: test configuration of the AIDE file integrity tool [#2063](https://github.com/chef/inspec/pull/2063) ([jburns12](https://github.com/jburns12)) <!-- 1.34.2 -->
19
29
  <!-- release_rollup -->
20
30
 
21
31
  <!-- latest_stable_release -->
32
+ ## [v1.34.1](https://github.com/chef/inspec/tree/v1.34.1) (2017-08-24)
33
+
34
+ #### Enhancements
35
+ - Refine the profile/test summary output of the CLI formatter [#2094](https://github.com/chef/inspec/pull/2094) ([adamleff](https://github.com/adamleff))
36
+ <!-- latest_stable_release -->
37
+
22
38
  ## [v1.33.12](https://github.com/chef/inspec/tree/v1.33.12) (2017-08-18)
23
39
 
24
40
  #### Bug Fixes
@@ -34,7 +50,6 @@
34
50
  #### Merged Pull Requests
35
51
  - add functional tests for inspec check [#2077](https://github.com/chef/inspec/pull/2077) ([chris-rock](https://github.com/chris-rock))
36
52
  - Move bug fixes in CHANGELOG to correct header [#2089](https://github.com/chef/inspec/pull/2089) ([adamleff](https://github.com/adamleff))
37
- <!-- latest_stable_release -->
38
53
 
39
54
  ## [v1.33.1](https://github.com/chef/inspec/tree/v1.33.1) (2017-08-10)
40
55
 
@@ -71,6 +71,16 @@ describe.one do
71
71
  end
72
72
  ```
73
73
 
74
+ #### Sensitive resources
75
+
76
+ In some scenarios, you may be writing checks involving resources with sensitive content (e.g. a file resource). In the case of failures, it may be desired to suppress output. This can be done by adding the `:sensitive` flag to the resource definition
77
+
78
+ ```ruby
79
+ describe file('/tmp/mysecretfile'), :sensitive do
80
+ its('content') { should contain 'secret_info' }
81
+ end
82
+ ```
83
+
74
84
  ## Examples
75
85
 
76
86
  The following examples show simple compliance tests using a single `control` block.
@@ -0,0 +1,81 @@
1
+ ---
2
+ title: About the aide_conf Resource
3
+ ---
4
+
5
+ # aide_conf
6
+
7
+ Use the `aide_conf` InSpec audit resource to test the rules established for the file integrity tool AIDE. Controlled by the aide.conf file typically at /etc/aide.conf.
8
+
9
+ ## Syntax
10
+
11
+ An `aide_conf` resource block can be used to determine if the selection lines contain one (or more) directories whose files should be added to the aide database:
12
+
13
+ describe aide_conf('path') do
14
+ its('selection_lines') { should include '/sbin' }
15
+ end
16
+
17
+ where
18
+
19
+ * `'selection_lines'` refers to all selection lines found in the aide.conf file
20
+ * `('path')` is the non-default path to the `aide.conf` file (optional)
21
+ * `should include 'value'` is the value that is expected
22
+
23
+ Use the where clause to match a selection_line to one rule or a particular set of rules found in the aide.conf file:
24
+
25
+ describe aide_conf.where { selection_line == '/bin' } do
26
+ its('rules.flatten') { should include 'r' }
27
+ end
28
+
29
+ describe aide_conf.where { selection_line == '/sbin' } do
30
+ its('rules') { should include ['p', 'i', 'l', 'n', 'u', 'g', 'sha512'] }
31
+ end
32
+
33
+ ## Matchers
34
+
35
+ This InSpec audit resource has the following matchers:
36
+
37
+ ### be
38
+
39
+ <%= partial "/shared/matcher_be" %>
40
+
41
+ ### cmp
42
+
43
+ <%= partial "/shared/matcher_cmp" %>
44
+
45
+ ### eq
46
+
47
+ <%= partial "/shared/matcher_eq" %>
48
+
49
+ ### include
50
+
51
+ <%= partial "/shared/matcher_include" %>
52
+
53
+ ### all_have_rule
54
+
55
+ The usage of all_have_rule will return whether or not all selection lines in audit.conf contain a particular rule:
56
+
57
+ describe aide_conf.all_have_rule('sha512') do
58
+ it { should eq true }
59
+ end
60
+
61
+ ## Examples
62
+
63
+ The following examples show how to use this InSpec audit resource.
64
+
65
+ ### Test if all selection lines contain the xattr rule
66
+
67
+ describe aide_conf.all_have_rule('xattr') do
68
+ it { should eq true }
69
+ end
70
+
71
+ ### Test whether selection line for /bin contains a particular rule
72
+
73
+ describe aide_conf.where { selection_line == '/bin' } do
74
+ its('rules.flatten') { should include 'r' }
75
+ end
76
+
77
+ ### Test whether selection line for /sbin consists of a particular set of rules
78
+
79
+ describe aide_conf.where { selection_line == '/sbin' } do
80
+ its('rules') { should include ['r', 'sha512'] }
81
+ end
@@ -0,0 +1,62 @@
1
+ ---
2
+ title: About the etc_hosts Resource
3
+ ---
4
+
5
+ # etc_hosts
6
+
7
+ Use the `etc_hosts` InSpec audit resource to test rules set to match IP addresses with hostnames.
8
+ ## Syntax
9
+
10
+ An etc/hosts rule specifies an IP address and what its hostname is along with optional aliases it can have.
11
+
12
+ ## Syntax
13
+
14
+ Use the where clause to match a property to one or more rules in the hosts file.
15
+
16
+ describe etc_hosts.where { ip_address == 'value' } do
17
+ its('primary_name') { should cmp 'hostname' }
18
+ its('all_host_names') { should cmp 'list' }
19
+ end
20
+
21
+ Use the optional constructor parameter to give an alternative path to hosts file
22
+
23
+ describe etc_hosts('path/to/hosts').where { ip_address == 'value' } do
24
+ its('primary_name') { should cmp 'hostname' }
25
+ its('all_host_names') { should cmp 'list' }
26
+ end
27
+
28
+ where
29
+
30
+ * `ip_address` is the ip address of the hostname in either ipv4 or ipv6 format.
31
+ * `primary_name` is the name associated with the ip address.
32
+ * `all_host_names` is a list including the primary_name as the first entry followed by any aliase names the host has.
33
+
34
+ ## Supported Properties
35
+
36
+ 'ip_address', 'primary_name', 'all_host_names'
37
+
38
+ ## Property Examples and Return Types
39
+
40
+ ### ip_address
41
+
42
+ `ip_address` returns a string array of ip addresses specified in the etc/hosts file.
43
+
44
+ describe etc_hosts.where { primary_name == 'localhost' } do
45
+ its('ip_address') { should cmp '127.0.1.154' }
46
+ end
47
+
48
+ ### primary_name
49
+
50
+ `primary_name` returns a string array of primary_names specified in the etc/hosts file.
51
+
52
+ describe etc_hosts.where { ip_address == '::1' } do
53
+ its('primary_name') { should cmp 'localhost' }
54
+ end
55
+
56
+ ### all_host_names
57
+
58
+ `all_host_names` returns a two dimensional string array where each entry has the primary_name first followed by any aliases.
59
+
60
+ describe etc_hosts.where { ip_address == '127.0.1.154' } do
61
+ its('all_host_names') { should eq [['localhost', 'localhost.localdomain', 'localhost4', 'localhost4.localdomain4'], ['localhost', 'localhost.localdomain', 'localhost6', 'localhost6.localdomain6']] }
62
+ end
@@ -0,0 +1,75 @@
1
+ ---
2
+ title: About the xml Resource
3
+ ---
4
+
5
+ # xml
6
+
7
+ Use the `xml` InSpec audit resource to test data in an XML file.
8
+
9
+ ## Syntax
10
+
11
+ An `xml` resource block declares the data to be tested. Assume the following XML file:
12
+
13
+ <root>
14
+ <name>hello</name>
15
+ <meta>
16
+ <creator>John Doe</creator>
17
+ </meta>
18
+ <array>
19
+ <element>one</element>
20
+ <element>two</element>
21
+ </array>
22
+ </root>
23
+
24
+ This file can be queried using:
25
+
26
+ describe xml('/path/to/name.xml') do
27
+ its('root/name') { should eq ['hello'] }
28
+ its('root/meta/creator') { should eq ['John Doe'] }
29
+ its('root/array[2]/element]) { should eq ['two'] }
30
+ end
31
+
32
+ where
33
+
34
+ * `root/name` is an XPath expression
35
+ * `should eq ['foo']` tests a value of `root/name` as read from an XML file versus the value declared in the test
36
+
37
+ ## Matchers
38
+
39
+ This InSpec audit resource has the following matchers:
40
+
41
+ ### be
42
+
43
+ <%= partial "/shared/matcher_be" %>
44
+
45
+ ### cmp
46
+
47
+ <%= partial "/shared/matcher_cmp" %>
48
+
49
+ ### eq
50
+
51
+ <%= partial "/shared/matcher_eq" %>
52
+
53
+ ### include
54
+
55
+ <%= partial "/shared/matcher_include" %>
56
+
57
+ ### match
58
+
59
+ <%= partial "/shared/matcher_match" %>
60
+
61
+ ### name
62
+
63
+ The `name` matcher tests the value of `name` as read from a JSON file versus the value declared in the test:
64
+
65
+ its('name') { should eq 'foo' }
66
+
67
+ ## Examples
68
+
69
+ The following examples show how to use this InSpec audit resource.
70
+
71
+ ### Test an AppPool's presence in an applicationHost.config file
72
+
73
+ describe xml('applicationHost.config') do
74
+ its('configuration/system.applicationHost/applicationPools/add@name') { should contain('my_pool') }
75
+ end
@@ -0,0 +1,29 @@
1
+ # Example InSpec Profile with Sensitive failures
2
+
3
+ This profile demostrates resources flagged as sensitive
4
+
5
+ ## Usage
6
+
7
+ ```
8
+ $ inspec exec examples/profile-sensitive
9
+ ....
10
+
11
+ bob should
12
+ ∅ eq "billy"
13
+
14
+ expected: "billy"
15
+ got: "bob"
16
+
17
+ (compared using ==)
18
+
19
+ sensitivepassword should
20
+ ∅ eq "secret"
21
+ *** sensitive output suppressed ***
22
+ bob should
23
+ ✔ eq "bob"
24
+ sensitivepassword should
25
+ ✔ eq "sensitivepassword"
26
+
27
+ Test Summary: 2 successful, 2 failures, 0 skipped
28
+
29
+ ```
@@ -0,0 +1,9 @@
1
+ # encoding: utf-8
2
+
3
+ describe 'bob' do
4
+ it { should eq 'billy' }
5
+ end
6
+
7
+ describe 'sensitivepassword', :sensitive do
8
+ it { should eq 'secret' }
9
+ end
@@ -0,0 +1,9 @@
1
+ # encoding: utf-8
2
+
3
+ describe 'bob' do
4
+ it { should eq 'bob' }
5
+ end
6
+
7
+ describe 'sensitivepassword', :sensitive do
8
+ it { should eq 'sensitivepassword' }
9
+ end
@@ -0,0 +1,8 @@
1
+ name: profile-sensitive
2
+ title: InSpec Sensitive Profile
3
+ maintainer: The Authors
4
+ copyright: The Authors
5
+ copyright_email: you@example.com
6
+ license: Apache-2.0
7
+ summary: An InSpec Compliance Profile
8
+ version: 0.1.0
@@ -72,6 +72,7 @@ module Inspec
72
72
  end
73
73
  end
74
74
 
75
+ require 'resources/aide_conf'
75
76
  require 'resources/apache'
76
77
  require 'resources/apache_conf'
77
78
  require 'resources/apt'
@@ -89,6 +90,7 @@ require 'resources/docker'
89
90
  require 'resources/docker_image'
90
91
  require 'resources/docker_container'
91
92
  require 'resources/etc_group'
93
+ require 'resources/etc_hosts'
92
94
  require 'resources/file'
93
95
  require 'resources/gem'
94
96
  require 'resources/groups'
@@ -157,3 +159,4 @@ require 'resources/json'
157
159
  require 'resources/yaml'
158
160
  require 'resources/csv'
159
161
  require 'resources/ini'
162
+ require 'resources/xml'
@@ -52,7 +52,12 @@ class InspecRspecMiniJson < RSpec::Core::Formatters::JsonFormatter
52
52
  format_example(example).tap do |hash|
53
53
  e = example.exception
54
54
  next unless e
55
- hash[:message] = exception_message(e)
55
+
56
+ if example.metadata[:sensitive]
57
+ hash[:message] = '*** sensitive output suppressed ***'
58
+ else
59
+ hash[:message] = exception_message(e)
60
+ end
56
61
 
57
62
  next if e.is_a? RSpec::Expectations::ExpectationNotMetError
58
63
  hash[:exception] = e.class.name
@@ -341,7 +346,7 @@ class InspecRspecCli < InspecRspecJson # rubocop:disable Metrics/ClassLength
341
346
  # This method is called through the RSpec Formatter interface for every
342
347
  # example found in the test suite.
343
348
  #
344
- # Within #format_example we are getting and example and:
349
+ # Within #format_example we are getting an example and:
345
350
  # * if this is an example, within a control, within a profile then we want
346
351
  # to display the profile header, display the control, and then display
347
352
  # the example.
@@ -4,5 +4,5 @@
4
4
  # author: Christoph Hartmann
5
5
 
6
6
  module Inspec
7
- VERSION = '1.34.1'.freeze
7
+ VERSION = '1.35.1'.freeze
8
8
  end
@@ -0,0 +1,162 @@
1
+ # encoding: utf-8
2
+ # author: Jen Burns, burnsjennifere@gmail.com
3
+
4
+ require 'utils/filter'
5
+ require 'utils/parser'
6
+
7
+ # rubocop:disable Metrics/ClassLength
8
+ module Inspec::Resources
9
+ class AideConf < Inspec.resource(1)
10
+ name 'aide_conf'
11
+ desc 'Use the aide_conf InSpec audit resource to test the rules established for
12
+ the file integrity tool AIDE. Controlled by the aide.conf file typically at /etc/aide.conf.'
13
+ example "
14
+ describe aide_conf do
15
+ its('selection_lines') { should include '/sbin' }
16
+ end
17
+
18
+ describe aide_conf.where { selection_line == '/bin' } do
19
+ its('rules.flatten') { should include 'r' }
20
+ end
21
+
22
+ describe aide_conf.all_have_rule('sha512') do
23
+ it { should eq true }
24
+ end
25
+ "
26
+
27
+ attr_reader :params
28
+
29
+ include CommentParser
30
+
31
+ def initialize(aide_conf_path = nil)
32
+ return skip_resource 'The `aide_conf` resource is not supported on your OS.' unless inspec.os.linux?
33
+ @conf_path = aide_conf_path || '/etc/aide.conf'
34
+ @content = nil
35
+ @rules = nil
36
+ read_content
37
+ end
38
+
39
+ def all_have_rule(rule)
40
+ # Case when file didn't exist or perms didn't allow an open
41
+ return false if @content.nil?
42
+
43
+ lines = @params.reject { |line| line['rules'].include? rule }
44
+ lines.empty?
45
+ end
46
+
47
+ filter = FilterTable.create
48
+ filter.add_accessor(:where)
49
+ .add_accessor(:entries)
50
+ .add(:selection_lines, field: 'selection_line')
51
+ .add(:rules, field: 'rules')
52
+
53
+ filter.connect(self, :params)
54
+
55
+ private
56
+
57
+ def read_content
58
+ return @content unless @content.nil?
59
+ @rules = {}
60
+
61
+ file = inspec.file(@conf_path)
62
+ if !file.file?
63
+ return skip_resource "Can't find file \"#{@conf_path}\""
64
+ end
65
+ raw_conf = file.content
66
+ if raw_conf.nil?
67
+ return skip_resource "File can't be opened or is empty \"#{@conf_path}\""
68
+ end
69
+ if raw_conf.empty? && !file.empty?
70
+ return skip_resource "Can't read file \"#{@conf_path}\""
71
+ end
72
+
73
+ # If there is a file and it contains content, continue
74
+ @content = filter_comments(inspec.file(@conf_path).content.lines)
75
+ @params = parse_conf(@content)
76
+ end
77
+
78
+ def filter_comments(data)
79
+ content = []
80
+ data.each do |line|
81
+ content_line, = parse_comment_line(line, comment_char: '#', standalone_comments: false)
82
+ content.push(content_line)
83
+ end
84
+ content
85
+ end
86
+
87
+ def parse_conf(content)
88
+ params = []
89
+ content.each do |line|
90
+ param = parse_line(line)
91
+ if !param['selection_line'].nil?
92
+ params.push(param)
93
+ end
94
+ end
95
+ params
96
+ end
97
+
98
+ def parse_line(line)
99
+ line_and_rules = {}
100
+ # Case when line is a rule line
101
+ if line.include?(' = ')
102
+ parse_rule_line(line)
103
+ # Case when line is a selection line
104
+ elsif line.start_with?('/', '!', '=')
105
+ line_and_rules = parse_selection_line(line)
106
+ end
107
+ line_and_rules
108
+ end
109
+
110
+ def parse_rule_line(line)
111
+ line.gsub!(/\s+/, '')
112
+ rule_line_arr = line.split('=')
113
+ rules_list = rule_line_arr.last.split('+')
114
+ rule_name = rule_line_arr.first
115
+ rules_list.each_index do |i|
116
+ # Cases where rule respresents one or more other rules
117
+ if @rules.key?(rules_list[i])
118
+ rules_list[i] = @rules[rules_list[i]]
119
+ end
120
+ rules_list[i] = handle_multi_rule(rules_list, i)
121
+ end
122
+ @rules[rule_name] = rules_list.flatten
123
+ end
124
+
125
+ def parse_selection_line(line)
126
+ selec_line_arr = line.split(' ')
127
+ selection_line = selec_line_arr.first
128
+ selection_line.chop! if selection_line.end_with?('/')
129
+ rule_list = selec_line_arr.last.split('+')
130
+ rule_list.each_index do |i|
131
+ hash_list = @rules[rule_list[i]]
132
+ # Cases where rule respresents one or more other rules
133
+ if !hash_list.nil?
134
+ rule_list[i] = hash_list
135
+ end
136
+ rule_list[i] = handle_multi_rule(rule_list, i)
137
+ end
138
+ rule_list.flatten!
139
+ {
140
+ 'selection_line' => selection_line,
141
+ 'rules' => rule_list,
142
+ }
143
+ end
144
+
145
+ def handle_multi_rule(rule_list, i)
146
+ # Rules that represent multiple rules (R,L,>)
147
+ r_rules = %w{p i l n u g s m c md5}
148
+ l_rules = %w{p i l n u g}
149
+ grow_log_rules = %w{p l u g i n S}
150
+
151
+ case rule_list[i]
152
+ when 'R'
153
+ return r_rules
154
+ when 'L'
155
+ return l_rules
156
+ when '>'
157
+ return grow_log_rules
158
+ end
159
+ rule_list[i]
160
+ end
161
+ end
162
+ end
@@ -177,7 +177,7 @@ module Inspec::Resources
177
177
 
178
178
  # NB only in file lines
179
179
  def get_key(line)
180
- line.match(/-k ([^ ]+)/)[1]
180
+ line.match(/-k ([^ ]+)/)[1] if line.include?('-k ')
181
181
  end
182
182
 
183
183
  # NOTE there are NO precautions wrt. filenames containing spaces in auditctl
@@ -0,0 +1,81 @@
1
+ # encoding: utf-8
2
+ # author: Matthew Dromazos
3
+
4
+ require 'utils/parser'
5
+
6
+ class EtcHosts < Inspec.resource(1)
7
+ name 'etc_hosts'
8
+ desc 'Use the etc_hosts InSpec audit resource to find an
9
+ ip_address and its associated hosts'
10
+ example "
11
+ describe etc_hosts.where { ip_address == '127.0.0.1' } do
12
+ its('ip_address') { should cmp '127.0.0.1' }
13
+ its('primary_name') { should cmp 'localhost' }
14
+ its('all_host_names') { should eq [['localhost', 'localhost.localdomain', 'localhost4', 'localhost4.localdomain4']] }
15
+ end
16
+ "
17
+
18
+ attr_reader :params
19
+
20
+ include CommentParser
21
+
22
+ def initialize(hosts_path = nil)
23
+ return skip_resource 'The `etc_hosts` resource is not supported on your OS.' unless inspec.os.linux? || inspec.os.windows?
24
+ @conf_path = hosts_path || default_hosts_file_path
25
+ @content = nil
26
+ @params = nil
27
+ read_content
28
+ end
29
+
30
+ filter = FilterTable.create
31
+ filter.add_accessor(:where)
32
+ .add_accessor(:entries)
33
+ .add(:ip_address, field: 'ip_address')
34
+ .add(:primary_name, field: 'primary_name')
35
+ .add(:all_host_names, field: 'all_host_names')
36
+
37
+ filter.connect(self, :params)
38
+
39
+ private
40
+
41
+ def default_hosts_file_path
42
+ inspec.os.windows? ? 'C:\windows\system32\drivers\etc\hosts' : '/etc/hosts'
43
+ end
44
+
45
+ def read_content
46
+ @content = ''
47
+ @params = {}
48
+ @content = read_file(@conf_path)
49
+ @params = parse_conf(@content)
50
+ end
51
+
52
+ def parse_conf(content)
53
+ content.map do |line|
54
+ data, = parse_comment_line(line, comment_char: '#', standalone_comments: false)
55
+ parse_line(data) unless data == ''
56
+ end.compact
57
+ end
58
+
59
+ def parse_line(line)
60
+ line_parts = line.split
61
+ return nil unless line_parts.length >= 2
62
+ {
63
+ 'ip_address' => line_parts[0],
64
+ 'primary_name' => line_parts[1],
65
+ 'all_host_names' => line_parts[1..-1],
66
+ }
67
+ end
68
+
69
+ def read_file(conf_path = @conf_path)
70
+ file = inspec.file(conf_path)
71
+ if !file.file?
72
+ return skip_resource "Can't find file. \"#{@conf_path}\""
73
+ end
74
+
75
+ raw_conf = file.content
76
+ if raw_conf.empty? && !file.empty?
77
+ return skip_resource("Could not read file contents\" #{@conf_path}\"")
78
+ end
79
+ raw_conf.lines
80
+ end
81
+ end
@@ -90,7 +90,6 @@ module Inspec::Resources
90
90
 
91
91
  def initialize(groupname)
92
92
  @group = groupname
93
- @group = @group.downcase unless inspec.os.windows?
94
93
 
95
94
  # select group manager
96
95
  @group_provider = select_group_manager(inspec.os)
@@ -55,6 +55,7 @@ module Inspec::Resources
55
55
  private
56
56
 
57
57
  def response
58
+ return @response if @response
58
59
  conn = Faraday.new url: @url, headers: @headers, params: @params, ssl: { verify: @ssl_verify }
59
60
 
60
61
  # set basic authentication
@@ -7,6 +7,7 @@
7
7
  # it { should be_installed }
8
8
  # end
9
9
  #
10
+
10
11
  module Inspec::Resources
11
12
  class PipPackage < Inspec.resource(1)
12
13
  name 'pip'
@@ -15,10 +16,17 @@ module Inspec::Resources
15
16
  describe pip('Jinja2') do
16
17
  it { should be_installed }
17
18
  end
19
+
20
+ describe pip('django', '/path/to/virtualenv/bin/pip') do
21
+ it { should be_installed }
22
+ its('version') { should eq('1.11.4')}
23
+ end
18
24
  "
19
25
 
20
- def initialize(package_name)
26
+ def initialize(package_name, pip_path = nil)
21
27
  @package_name = package_name
28
+ @pip_cmd = pip_path || default_pip_path
29
+ return skip_resource 'pip not found' unless inspec.command(@pip_cmd).exist?
22
30
  end
23
31
 
24
32
  def info
@@ -26,7 +34,7 @@ module Inspec::Resources
26
34
 
27
35
  @info = {}
28
36
  @info[:type] = 'pip'
29
- cmd = inspec.command("#{pip_cmd} show #{@package_name}")
37
+ cmd = inspec.command("#{@pip_cmd} show #{@package_name}")
30
38
  return @info if cmd.exit_status != 0
31
39
 
32
40
  params = SimpleConfig.new(
@@ -54,28 +62,28 @@ module Inspec::Resources
54
62
 
55
63
  private
56
64
 
57
- def pip_cmd
65
+ def default_pip_path
66
+ return 'pip' unless inspec.os.windows?
67
+
58
68
  # Pip is not on the default path for Windows, therefore we do some logic
59
69
  # to find the binary on Windows
60
- if inspec.os.windows?
61
- # we need to detect the pip command on Windows
62
- cmd = inspec.command('New-Object -Type PSObject | Add-Member -MemberType NoteProperty -Name Pip -Value (Invoke-Command -ScriptBlock {where.exe pip}) -PassThru | Add-Member -MemberType NoteProperty -Name Python -Value (Invoke-Command -ScriptBlock {where.exe python}) -PassThru | ConvertTo-Json')
63
- begin
64
- paths = JSON.parse(cmd.stdout)
65
- # use pip if it on system path
66
- pipcmd = paths['Pip']
67
- # calculate path on windows
68
- if defined?(paths['Python']) && pipcmd.nil?
69
- pipdir = paths['Python'].split('\\')
70
- # remove python.exe
71
- pipdir.pop
72
- pipcmd = pipdir.push('Scripts').push('pip.exe').join('/')
73
- end
74
- rescue JSON::ParserError => _e
75
- return nil
70
+ cmd = inspec.command('New-Object -Type PSObject | Add-Member -MemberType NoteProperty -Name Pip -Value (Invoke-Command -ScriptBlock {where.exe pip}) -PassThru | Add-Member -MemberType NoteProperty -Name Python -Value (Invoke-Command -ScriptBlock {where.exe python}) -PassThru | ConvertTo-Json')
71
+ begin
72
+ paths = JSON.parse(cmd.stdout)
73
+ # use pip if it on system path
74
+ pipcmd = paths['Pip']
75
+ # calculate path on windows
76
+ if defined?(paths['Python']) && pipcmd.nil?
77
+ pipdir = paths['Python'].split('\\')
78
+ # remove python.exe
79
+ pipdir.pop
80
+ pipcmd = pipdir.push('Scripts').push('pip.exe').join('/')
76
81
  end
82
+ rescue JSON::ParserError => _e
83
+ return nil
77
84
  end
78
- pipcmd || 'pip'
85
+
86
+ pipcmd
79
87
  end
80
88
  end
81
89
  end
@@ -264,10 +264,34 @@ module Inspec::Resources
264
264
  end
265
265
 
266
266
  # extract port information from netstat
267
- class LinuxPorts < PortsInfo
267
+ class LinuxPorts < PortsInfo # rubocop:disable Metrics/ClassLength
268
+ ALLOWED_PROTOCOLS = %w{tcp tcp6 udp udp6}.freeze
269
+
268
270
  def info
271
+ ports_via_ss || ports_via_netstat
272
+ end
273
+
274
+ def ports_via_ss
275
+ return nil unless inspec.command('ss').exist?
276
+
277
+ cmd = inspec.command('ss -tulpen')
278
+ return nil unless cmd.exit_status.to_i.zero?
279
+
280
+ ports = []
281
+
282
+ cmd.stdout.each_line do |line|
283
+ parsed_line = parse_ss_line(line)
284
+ ports << parsed_line unless parsed_line.nil?
285
+ end
286
+
287
+ ports
288
+ end
289
+
290
+ def ports_via_netstat
291
+ return nil unless inspec.command('netstat').exist?
292
+
269
293
  cmd = inspec.command('netstat -tulpen')
270
- return nil if cmd.exit_status.to_i != 0
294
+ return nil unless cmd.exit_status.to_i.zero?
271
295
 
272
296
  ports = []
273
297
  # parse all lines
@@ -362,6 +386,66 @@ module Inspec::Resources
362
386
  'pid' => pid,
363
387
  }
364
388
  end
389
+
390
+ def parse_ss_line(line)
391
+ parsed = line.split(/\s+/, 7)
392
+
393
+ # ss only returns "tcp" and "udp" as the protocol. However, netstat would return
394
+ # "tcp6" and "udp6" as necessary. In order to maintain backward compatibility, we
395
+ # will manually modify the protocol value if the line we're parsing is an IPv6
396
+ # entry.
397
+ process_info = parsed[6]
398
+ protocol = parsed[0]
399
+ protocol += '6' if process_info.include?('v6only:1')
400
+ return nil unless ALLOWED_PROTOCOLS.include?(protocol)
401
+
402
+ # parse the Local Address:Port
403
+ # examples:
404
+ # *:22
405
+ # :::22
406
+ # 10.0.2.15:1234
407
+ # ::ffff:10.0.2.15:9300
408
+ # fe80::a00:27ff:fe32:ed09%enp0s3:9200
409
+ parsed_net_address = parsed[4].match(/(\S+):(\*|\d+)$/)
410
+ return nil if parsed_net_address.nil?
411
+ host = parsed_net_address[1]
412
+ port = parsed_net_address[2]
413
+ return nil if host.nil? && port.nil?
414
+
415
+ # For backward compatibility with the netstat output, ensure the
416
+ # port is stored as an integer
417
+ port = port.to_i
418
+
419
+ # for those "v4-but-listed-in-v6" entries, strip off the
420
+ # leading IPv6 value at the beginning
421
+ # example: ::ffff:10.0.2.15:9200
422
+ host.delete!('::ffff:') if host.start_with?('::ffff:')
423
+
424
+ # if there's an interface name in the local address, which is common for
425
+ # IPv6 listeners, strip that out too.
426
+ # example: fe80::a00:27ff:fe32:ed09%enp0s3
427
+ host = host.split('%').first
428
+
429
+ # if host is "*", replace with "0.0.0.0" to maintain backward compatibility with
430
+ # the netstat-provided data
431
+ host = '0.0.0.0' if host == '*'
432
+
433
+ # parse the process name from the processes information
434
+ process_match = parsed[6].match(/users:\(\(\"(\S+)\"/)
435
+ process = process_match.nil? ? nil : process_match[1]
436
+
437
+ # parse the PID from the processes information
438
+ pid_match = parsed[6].match(/pid=(\d+)/)
439
+ pid = pid_match.nil? ? nil : pid_match[1].to_i
440
+
441
+ {
442
+ 'port' => port,
443
+ 'address' => host,
444
+ 'protocol' => protocol,
445
+ 'process' => process,
446
+ 'pid' => pid,
447
+ }
448
+ end
365
449
  end
366
450
 
367
451
  # extracts information from sockstat
@@ -0,0 +1,27 @@
1
+ # encoding: utf-8
2
+ # author: Jonathan Morley
3
+
4
+ module Inspec::Resources
5
+ class XmlConfig < JsonConfig
6
+ name 'xml'
7
+ desc 'Use the xml InSpec resource to test configuration data in an XML file'
8
+ example "
9
+ describe xml('default.xml') do
10
+ its('key/sub_key') { should eq(['value']) }
11
+ end
12
+ "
13
+
14
+ def parse(content)
15
+ require 'rexml/document'
16
+ REXML::Document.new(content)
17
+ end
18
+
19
+ def value(key)
20
+ REXML::XPath.each(@params, key.first.to_s).map(&:text)
21
+ end
22
+
23
+ def to_s
24
+ "XML #{@path}"
25
+ end
26
+ end
27
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: inspec
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.34.1
4
+ version: 1.35.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dominik Richter
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-08-23 00:00:00.000000000 Z
11
+ date: 2017-08-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: train
@@ -312,6 +312,7 @@ files:
312
312
  - docs/migration.md
313
313
  - docs/plugin_kitchen_inspec.md
314
314
  - docs/profiles.md
315
+ - docs/resources/aide_conf.md.erb
315
316
  - docs/resources/apache_conf.md.erb
316
317
  - docs/resources/apt.md.erb
317
318
  - docs/resources/audit_policy.md.erb
@@ -330,6 +331,7 @@ files:
330
331
  - docs/resources/docker_container.md.erb
331
332
  - docs/resources/docker_image.md.erb
332
333
  - docs/resources/etc_group.md.erb
334
+ - docs/resources/etc_hosts.md.erb
333
335
  - docs/resources/file.md.erb
334
336
  - docs/resources/gem.md.erb
335
337
  - docs/resources/group.md.erb
@@ -393,6 +395,7 @@ files:
393
395
  - docs/resources/wmi.md.erb
394
396
  - docs/resources/x509_certificate.md.erb
395
397
  - docs/resources/xinetd_conf.md.erb
398
+ - docs/resources/xml.md.erb
396
399
  - docs/resources/yaml.md.erb
397
400
  - docs/resources/yum.md.erb
398
401
  - docs/resources/zfs_dataset.md.erb
@@ -437,6 +440,10 @@ files:
437
440
  - examples/profile-attribute/README.md
438
441
  - examples/profile-attribute/controls/example.rb
439
442
  - examples/profile-attribute/inspec.yml
443
+ - examples/profile-sensitive/README.md
444
+ - examples/profile-sensitive/controls/sensitive-failures.rb
445
+ - examples/profile-sensitive/controls/sensitive.rb
446
+ - examples/profile-sensitive/inspec.yml
440
447
  - examples/profile/README.md
441
448
  - examples/profile/controls/example.rb
442
449
  - examples/profile/controls/gordon.rb
@@ -545,6 +552,7 @@ files:
545
552
  - lib/inspec/source_reader.rb
546
553
  - lib/inspec/version.rb
547
554
  - lib/matchers/matchers.rb
555
+ - lib/resources/aide_conf.rb
548
556
  - lib/resources/apache.rb
549
557
  - lib/resources/apache_conf.rb
550
558
  - lib/resources/apt.rb
@@ -563,6 +571,7 @@ files:
563
571
  - lib/resources/docker_container.rb
564
572
  - lib/resources/docker_image.rb
565
573
  - lib/resources/etc_group.rb
574
+ - lib/resources/etc_hosts.rb
566
575
  - lib/resources/file.rb
567
576
  - lib/resources/gem.rb
568
577
  - lib/resources/groups.rb
@@ -623,6 +632,7 @@ files:
623
632
  - lib/resources/wmi.rb
624
633
  - lib/resources/x509_certificate.rb
625
634
  - lib/resources/xinetd.rb
635
+ - lib/resources/xml.rb
626
636
  - lib/resources/yaml.rb
627
637
  - lib/resources/yum.rb
628
638
  - lib/resources/zfs_dataset.rb