inspec 1.50.1 → 1.51.0

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: 3e1a10fa109bd6acf6791160ec84a2b00541332f
4
- data.tar.gz: 0ca5fa62d228cc13b973f272fd9ac55635cafba7
3
+ metadata.gz: e4952aa70e173665e538c1e9a462da104c533ad1
4
+ data.tar.gz: a2b79c2109ade3f8f96afbb95104a71ea9d8b16c
5
5
  SHA512:
6
- metadata.gz: 47dec2f9f7653e27b31489524ccb93ab364a8683f66ce00e7eec849a0fcc1cc0b5cbf773cb673e6ac4a532c0c3ccabffa5446c9feb50674f4cd130e46d5ccfb6
7
- data.tar.gz: 385cbd5d676ef7f3bfb5905a23da6a2359abbdf5fc025e77ebb885bb20dde32172573df4b51176919edba5425bab9c95b6b8b02188b3941dc77f9f05940b2338
6
+ metadata.gz: e5444459f580693c6cce709ffb6cb99e47d817e1ddd35064a1636a299899165da235197640edb3cc2766d5b93d8fae7194996e731303c63df69f057527e02555
7
+ data.tar.gz: c866512ba5541fcb0b4dc2fb44c47f3ea22233b9d80590894e646e654f649160fbe0042dabb48941a7b500a709ee1c0d5f73c1725806083ce85713593d0b9939
@@ -1,33 +1,50 @@
1
1
  # Change Log
2
2
  <!-- usage documentation: http://expeditor-docs.es.chef.io/configuration/changelog/ -->
3
- <!-- latest_release unreleased -->
4
- ## Unreleased
3
+ <!-- latest_release 1.51.0 -->
4
+ ## [v1.51.0](https://github.com/chef/inspec/tree/v1.51.0) (2018-01-25)
5
5
 
6
- #### Merged Pull Requests
7
- - Bump version manually to trigger Habitat build [#2466](https://github.com/chef/inspec/pull/2466) ([adamleff](https://github.com/adamleff))
6
+ #### New Resources
7
+ - filesystem resource: inspect linux filesystems [#2441](https://github.com/chef/inspec/pull/2441) ([tarcinil](https://github.com/tarcinil))
8
8
  <!-- latest_release -->
9
9
 
10
- <!-- release_rollup since=1.49.2 -->
11
- ### Changes since 1.49.2 release
12
-
13
- #### Bug Fixes
14
- - http resource: make header keys case insensitive [#2457](https://github.com/chef/inspec/pull/2457) ([adamleff](https://github.com/adamleff)) <!-- 1.49.10 -->
15
- - package resource: fix NilClass errors on arch linux [#2437](https://github.com/chef/inspec/pull/2437) ([jerryaldrichiii](https://github.com/jerryaldrichiii)) <!-- 1.49.8 -->
16
- - firewalld resource: prepend rule string only when necessary [#2430](https://github.com/chef/inspec/pull/2430) ([tarcinil](https://github.com/tarcinil)) <!-- 1.49.6 -->
10
+ <!-- release_rollup since=1.50.1 -->
11
+ ### Changes since 1.50.1 release
17
12
 
18
13
  #### Enhancements
19
- - xml resource: support fetching attributes [#2423](https://github.com/chef/inspec/pull/2423) ([tarcinil](https://github.com/tarcinil)) <!-- 1.49.7 -->
20
- - mssql_session resource: add port parameter [#2429](https://github.com/chef/inspec/pull/2429) ([tarcinil](https://github.com/tarcinil)) <!-- 1.49.5 -->
14
+ - Update security_policy resource to return Names, not SIDs [#2462](https://github.com/chef/inspec/pull/2462) ([ViolentOr](https://github.com/ViolentOr)) <!-- 1.50.5 -->
15
+
16
+ #### New Resources
17
+ - filesystem resource: inspect linux filesystems [#2441](https://github.com/chef/inspec/pull/2441) ([tarcinil](https://github.com/tarcinil)) <!-- 1.51.0 -->
18
+ - new docker_service resource to inspect Docker Swarm services [#2456](https://github.com/chef/inspec/pull/2456) ([mattlqx](https://github.com/mattlqx)) <!-- 1.50.4 -->
21
19
 
22
20
  #### Merged Pull Requests
23
- - Bump version manually to trigger Habitat build [#2466](https://github.com/chef/inspec/pull/2466) ([adamleff](https://github.com/adamleff)) <!-- 1.50.1 -->
24
- - Bump minor version [#2465](https://github.com/chef/inspec/pull/2465) ([adamleff](https://github.com/adamleff)) <!-- 1.50.0 -->
25
- - Bump Omnibus Ruby (and Travis Rubies) to 2.4.3 [#2452](https://github.com/chef/inspec/pull/2452) ([adamleff](https://github.com/adamleff)) <!-- 1.49.9 -->
26
- - Update the inspec support check to warn to stderr. [#2446](https://github.com/chef/inspec/pull/2446) ([jquick](https://github.com/jquick)) <!-- 1.49.4 -->
27
- - Fix package manager detection on Arch Linux [#2436](https://github.com/chef/inspec/pull/2436) ([jerryaldrichiii](https://github.com/jerryaldrichiii)) <!-- 1.49.3 -->
21
+ - Sort library files before loading them so load order is predictable [#2475](https://github.com/chef/inspec/pull/2475) ([clintoncwolfe](https://github.com/clintoncwolfe)) <!-- 1.50.3 -->
22
+
23
+ #### Bug Fixes
24
+ - service resource: attempt a SysV fallback if SystemD unit file is not found [#2473](https://github.com/chef/inspec/pull/2473) ([jerryaldrichiii](https://github.com/jerryaldrichiii)) <!-- 1.50.6 -->
25
+ - grub_conf resource: fix menuentry detection [#2408](https://github.com/chef/inspec/pull/2408) ([jerryaldrichiii](https://github.com/jerryaldrichiii)) <!-- 1.50.2 -->
28
26
  <!-- release_rollup -->
29
27
 
30
28
  <!-- latest_stable_release -->
29
+ ## [v1.50.1](https://github.com/chef/inspec/tree/v1.50.1) (2018-01-17)
30
+
31
+ #### Enhancements
32
+ - mssql_session resource: add port parameter [#2429](https://github.com/chef/inspec/pull/2429) ([tarcinil](https://github.com/tarcinil))
33
+ - xml resource: support fetching attributes [#2423](https://github.com/chef/inspec/pull/2423) ([tarcinil](https://github.com/tarcinil))
34
+
35
+ #### Bug Fixes
36
+ - firewalld resource: prepend rule string only when necessary [#2430](https://github.com/chef/inspec/pull/2430) ([tarcinil](https://github.com/tarcinil))
37
+ - package resource: fix NilClass errors on arch linux [#2437](https://github.com/chef/inspec/pull/2437) ([jerryaldrichiii](https://github.com/jerryaldrichiii))
38
+ - http resource: make header keys case insensitive [#2457](https://github.com/chef/inspec/pull/2457) ([adamleff](https://github.com/adamleff))
39
+
40
+ #### Merged Pull Requests
41
+ - Fix package manager detection on Arch Linux [#2436](https://github.com/chef/inspec/pull/2436) ([jerryaldrichiii](https://github.com/jerryaldrichiii))
42
+ - Update the inspec support check to warn to stderr. [#2446](https://github.com/chef/inspec/pull/2446) ([jquick](https://github.com/jquick))
43
+ - Bump Omnibus Ruby (and Travis Rubies) to 2.4.3 [#2452](https://github.com/chef/inspec/pull/2452) ([adamleff](https://github.com/adamleff))
44
+ - Bump minor version [#2465](https://github.com/chef/inspec/pull/2465) ([adamleff](https://github.com/adamleff))
45
+ - Bump version manually to trigger Habitat build [#2466](https://github.com/chef/inspec/pull/2466) ([adamleff](https://github.com/adamleff))
46
+ <!-- latest_stable_release -->
47
+
31
48
  ## [v1.49.2](https://github.com/chef/inspec/tree/v1.49.2) (2018-01-04)
32
49
 
33
50
  #### Enhancements
@@ -51,7 +68,6 @@
51
68
  #### Merged Pull Requests
52
69
  - Split unit tests from functional [#2391](https://github.com/chef/inspec/pull/2391) ([adamleff](https://github.com/adamleff))
53
70
  - Bump minor version and cleanup changelog for release [#2440](https://github.com/chef/inspec/pull/2440) ([adamleff](https://github.com/adamleff))
54
- <!-- latest_stable_release -->
55
71
 
56
72
  ## [v1.48.0](https://github.com/chef/inspec/tree/v1.48.0) (2017-12-07)
57
73
 
@@ -0,0 +1,107 @@
1
+ ---
2
+ title: About the docker_service Resource
3
+ ---
4
+
5
+ # docker_service
6
+
7
+ Use the `docker_service` InSpec audit resource to verify a docker swarm service.
8
+
9
+ <br>
10
+
11
+ ## Syntax
12
+
13
+ A `docker_service` resource block declares the service by name:
14
+
15
+ describe docker_service('foo') do
16
+ it { should exist }
17
+ its('id') { should eq '2ghswegspre1' }
18
+ its('repo') { should eq 'alpine' }
19
+ its('tag') { should eq 'latest' }
20
+ end
21
+
22
+ The resource allows you to pass in a service id:
23
+
24
+ describe docker_service(id: '2ghswegspre1') do
25
+ ...
26
+ end
27
+
28
+ You can also pass in the fully-qualified image:
29
+
30
+ describe docker_service(image: 'localhost:5000/alpine:latest') do
31
+ ...
32
+ end
33
+
34
+ <br>
35
+
36
+ ## Examples
37
+
38
+ The following examples show how to use this InSpec `docker_service` resource.
39
+
40
+ ### Test a docker service
41
+
42
+ describe docker_service('foo') do
43
+ it { should exist }
44
+ its('id') { should eq '2ghswegspre1' }
45
+ its('repo') { should eq 'alpine' }
46
+ its('tag') { should eq 'latest' }
47
+ end
48
+
49
+ <br>
50
+
51
+ ## Matchers
52
+
53
+ This InSpec audit resource has the following matchers. For a full list of available matchers please visit our [matchers page](https://www.inspec.io/docs/reference/matchers/).
54
+
55
+ ### exist
56
+
57
+ The `exist` matcher tests if the image is available on the node:
58
+
59
+ it { should exist }
60
+
61
+ ### id
62
+
63
+ The `id` matcher returns the service id:
64
+
65
+ its('id') { should eq '2ghswegspre1' }
66
+
67
+ ### image
68
+
69
+ The `image` matcher tests the value of the image. It is a combination of `repository:tag`:
70
+
71
+ its('image') { should eq 'alpine:latest' }
72
+
73
+ ### mode
74
+
75
+ The `mode` matcher tests the value of the service mode:
76
+
77
+ its('mode') { should eq 'replicated' }
78
+
79
+ ### name
80
+
81
+ The `name` matcher tests the value of the service name:
82
+
83
+ its('name') { should eq 'foo' }
84
+
85
+ ### ports
86
+
87
+ The `ports` matcher tests the value of the service's published ports:
88
+
89
+ its('ports') { should include '*:8000->8000/tcp' }
90
+
91
+ ### repo
92
+
93
+ The `repo` matcher tests the value of the repository name:
94
+
95
+ its('repo') { should eq 'alpine' }
96
+
97
+ ### replicas
98
+
99
+ The `replicas` matcher tests the value of the service's replica count:
100
+
101
+ its('replicas') { should eq '3/3' }
102
+
103
+ ### tag
104
+
105
+ The `tag` matcher tests the value of image tag:
106
+
107
+ its('tag') { should eq 'latest' }
@@ -0,0 +1,39 @@
1
+ ---
2
+ title: About the filesystem Resource
3
+ ---
4
+
5
+ # filesystem
6
+
7
+ Use the `filesystem` InSpec resource to audit filesystem disk space usage
8
+ <br>
9
+
10
+ ## Syntax
11
+
12
+ A `filesystem` resource block declares tests for disk space in a partion:
13
+
14
+ describe filesystem('/') do
15
+ its('size') { should be >= 32000 }
16
+ end
17
+
18
+ where
19
+
20
+ * `filesystem('/')` states that it will be looking at the root (/) partition
21
+ * `size` is measured in megabytes (MB)
22
+
23
+ <br>
24
+
25
+ ## Examples
26
+
27
+ The following examples show how to use this InSpec audit resource.
28
+
29
+ ### Test if the root partition is greater thank 32000 MB
30
+
31
+ describe filesystem('/') do
32
+ its('size') { should be >= 32000 }
33
+ end
34
+
35
+ <br>
36
+
37
+ ## Matchers
38
+
39
+ For a full list of available matchers please visit our [matchers page](https://www.inspec.io/docs/reference/matchers/).
@@ -52,13 +52,14 @@ The following examples show how to use this InSpec audit resource.
52
52
 
53
53
  For example, a PHP INI file located at contains the following settings:
54
54
 
55
- ; SMTP = smtp.gmail.com
56
- ; smtp_port = 465
55
+ [mail function]
56
+ SMTP = smtp.gmail.com
57
+ smtp_port = 465
57
58
 
58
59
  and can be tested like this:
59
60
 
60
- describe ini(/etc/php5/apache2/php.ini) do
61
- its('smtp_port') { should eq('465') }
61
+ describe ini('/etc/php5/apache2/php.ini') do
62
+ its('mail function.smtp_port') { should eq('465') }
62
63
  end
63
64
 
64
65
  <br>
@@ -40,6 +40,13 @@ The following examples show how to use this InSpec audit resource.
40
40
  its('version') { should eq '2.8' }
41
41
  end
42
42
 
43
+ ### Test packages installed into a non-default location (e.g. virtualenv) by passing a custom path to pip executable
44
+
45
+ describe pip('Jinja2', '/path/to/bin/pip') do
46
+ it { should be_installed }
47
+ its('version') { should eq '2.8' }
48
+ end
49
+
43
50
  <br>
44
51
 
45
52
  ## Matchers
@@ -116,6 +116,7 @@ module Inspec
116
116
  lib_prefix = 'libraries' + File::SEPARATOR
117
117
  autoloads = []
118
118
 
119
+ libs.sort_by! { |l| l[1] } # Sort on source path so load order is deterministic
119
120
  libs.each do |content, source, line|
120
121
  path = source
121
122
  if source.start_with?(lib_prefix)
@@ -94,12 +94,14 @@ require 'resources/directory'
94
94
  require 'resources/docker'
95
95
  require 'resources/docker_container'
96
96
  require 'resources/docker_image'
97
+ require 'resources/docker_service'
97
98
  require 'resources/elasticsearch'
98
99
  require 'resources/etc_fstab'
99
100
  require 'resources/etc_group'
100
101
  require 'resources/etc_hosts_allow_deny'
101
102
  require 'resources/etc_hosts'
102
103
  require 'resources/file'
104
+ require 'resources/filesystem'
103
105
  require 'resources/firewalld'
104
106
  require 'resources/gem'
105
107
  require 'resources/groups'
@@ -4,5 +4,5 @@
4
4
  # author: Christoph Hartmann
5
5
 
6
6
  module Inspec
7
- VERSION = '1.50.1'
7
+ VERSION = '1.51.0'
8
8
  end
@@ -59,6 +59,25 @@ module Inspec::Resources
59
59
  end
60
60
  end
61
61
 
62
+ class DockerServiceFilter
63
+ filter = FilterTable.create
64
+ filter.add_accessor(:where)
65
+ .add_accessor(:entries)
66
+ .add(:ids, field: 'id')
67
+ .add(:names, field: 'name')
68
+ .add(:modes, field: 'mode')
69
+ .add(:replicas, field: 'replicas')
70
+ .add(:images, field: 'image')
71
+ .add(:ports, field: 'ports')
72
+ .add(:exists?) { |x| !x.entries.empty? }
73
+ filter.connect(self, :services)
74
+
75
+ attr_reader :services
76
+ def initialize(services)
77
+ @services = services
78
+ end
79
+ end
80
+
62
81
  # This resource helps to parse information from the docker host
63
82
  # For compatability with Serverspec we also offer the following resouses:
64
83
  # - docker_container
@@ -79,6 +98,10 @@ module Inspec::Resources
79
98
  its('repositories') { should_not include 'inssecure_image' }
80
99
  end
81
100
 
101
+ describe docker.services do
102
+ its('images') { should_not include 'inssecure_image' }
103
+ end
104
+
82
105
  describe docker.version do
83
106
  its('Server.Version') { should cmp >= '1.12'}
84
107
  its('Client.Version') { should cmp >= '1.12'}
@@ -105,6 +128,10 @@ module Inspec::Resources
105
128
  DockerImageFilter.new(parse_images)
106
129
  end
107
130
 
131
+ def services
132
+ DockerServiceFilter.new(parse_services)
133
+ end
134
+
108
135
  def version
109
136
  return @version if defined?(@version)
110
137
  data = {}
@@ -142,48 +169,55 @@ module Inspec::Resources
142
169
 
143
170
  private
144
171
 
145
- def parse_containers
146
- # @see https://github.com/moby/moby/issues/20625, works for docker 1.13+
147
- # raw_containers = inspec.command('docker ps -a --no-trunc --format \'{{ json . }}\'').stdout
148
- # therefore we stick with older approach
149
- labels = %w{Command CreatedAt ID Image Labels Mounts Names Ports RunningFor Size Status}
150
-
151
- # Networks LocalVolumes work with 1.13+ only
152
- if !version.empty? && Gem::Version.new(version['Client']['Version']) >= Gem::Version.new('1.13')
153
- labels.push('Networks')
154
- labels.push('LocalVolumes')
155
- end
172
+ def parse_json_command(labels, subcommand)
156
173
  # build command
157
174
  format = labels.map { |label| "\"#{label}\": {{json .#{label}}}" }
158
- raw_containers = inspec.command("docker ps -a --no-trunc --format '{#{format.join(', ')}}'").stdout
159
- ps = []
175
+ raw = inspec.command("docker #{subcommand} --format '{#{format.join(', ')}}'").stdout
176
+ output = []
160
177
  # since docker is not outputting valid json, we need to parse each row
161
- raw_containers.each_line { |entry|
162
- j = JSON.parse(entry)
178
+ raw.each_line { |entry|
163
179
  # convert all keys to lower_case to work well with ruby and filter table
164
- j = j.map { |k, v|
180
+ j = JSON.parse(entry).map { |k, v|
165
181
  [k.downcase, v]
166
182
  }.to_h
167
183
 
168
184
  # ensure all keys are there
169
- j = ensure_container_keys(j)
185
+ j = ensure_keys(j, labels)
170
186
 
171
187
  # strip off any linked container names
172
188
  # Depending on how it was linked, the actual container name may come before
173
189
  # or after the link information, so we'll just look for the first name that
174
190
  # does not include a slash since that is not a valid character in a container name
175
- j['names'] = j['names'].split(',').find { |c| !c.include?('/') }
191
+ j['names'] = j['names'].split(',').find { |c| !c.include?('/') } if j.key?('names')
176
192
 
177
- ps.push(j)
193
+ output.push(j)
178
194
  }
179
- ps
195
+ output
180
196
  rescue JSON::ParserError => _e
181
- warn 'Could not parse `docker ps` output'
197
+ warn "Could not parse `docker #{subcommand}` output"
182
198
  []
183
199
  end
184
200
 
185
- def ensure_container_keys(entry)
186
- %w{Command CreatedAt ID Image Labels Mounts Names Ports RunningFor Size Status Networks LocalVolumes}.each { |key|
201
+ def parse_containers
202
+ # @see https://github.com/moby/moby/issues/20625, works for docker 1.13+
203
+ # raw_containers = inspec.command('docker ps -a --no-trunc --format \'{{ json . }}\'').stdout
204
+ # therefore we stick with older approach
205
+ labels = %w{Command CreatedAt ID Image Labels Mounts Names Ports RunningFor Size Status}
206
+
207
+ # Networks LocalVolumes work with 1.13+ only
208
+ if !version.empty? && Gem::Version.new(version['Client']['Version']) >= Gem::Version.new('1.13')
209
+ labels.push('Networks')
210
+ labels.push('LocalVolumes')
211
+ end
212
+ parse_json_command(labels, 'ps -a --no-trunc')
213
+ end
214
+
215
+ def parse_services
216
+ parse_json_command(%w{ID Name Mode Replicas Image Ports}, 'service ls')
217
+ end
218
+
219
+ def ensure_keys(entry, labels)
220
+ labels.each { |key|
187
221
  entry[key.downcase] = nil if !entry.key?(key.downcase)
188
222
  }
189
223
  entry
@@ -6,8 +6,12 @@
6
6
  # author: Patrick Muench
7
7
  # author: Dominik Richter
8
8
 
9
+ require_relative 'docker_object'
10
+
9
11
  module Inspec::Resources
10
12
  class DockerContainer < Inspec.resource(1)
13
+ include Inspec::Resources::DockerObject
14
+
11
15
  name 'docker_container'
12
16
  desc ''
13
17
  example "
@@ -37,55 +41,39 @@ module Inspec::Resources
37
41
  end
38
42
  end
39
43
 
40
- def exist?
41
- container_info.exists?
42
- end
43
-
44
- # is allways returning the full id
45
- def id
46
- container_info.ids[0] if container_info.entries.length == 1
47
- end
48
-
49
44
  def running?
50
- status.downcase.start_with?('up') if container_info.entries.length == 1
45
+ status.downcase.start_with?('up') if object_info.entries.length == 1
51
46
  end
52
47
 
53
48
  def status
54
- container_info.status[0] if container_info.entries.length == 1
49
+ object_info.status[0] if object_info.entries.length == 1
55
50
  end
56
51
 
57
52
  def labels
58
- container_info.labels[0] if container_info.entries.length == 1
53
+ object_info.labels[0] if object_info.entries.length == 1
59
54
  end
60
55
 
61
56
  def ports
62
- container_info.ports[0] if container_info.entries.length == 1
57
+ object_info.ports[0] if object_info.entries.length == 1
63
58
  end
64
59
 
65
60
  def command
66
- return unless container_info.entries.length == 1
61
+ return unless object_info.entries.length == 1
67
62
 
68
- cmd = container_info.commands[0]
63
+ cmd = object_info.commands[0]
69
64
  cmd.slice(1, cmd.length - 2)
70
65
  end
71
66
 
72
67
  def image
73
- container_info.images[0] if container_info.entries.length == 1
68
+ object_info.images[0] if object_info.entries.length == 1
74
69
  end
75
70
 
76
71
  def repo
77
- return if image.nil? || image_name_from_image.nil?
78
- if image.include?('/') # host:port/ubuntu:latest
79
- repo_part, image_part = image.split('/') # host:port, ubuntu:latest
80
- repo_part + '/' + image_part.split(':')[0] # host:port + / + ubuntu
81
- else
82
- image_name_from_image.split(':')[0]
83
- end
72
+ parse_components_from_image(image)[:repo] if object_info.entries.size == 1
84
73
  end
85
74
 
86
75
  def tag
87
- return if image_name_from_image.nil?
88
- image_name_from_image.split(':')[1]
76
+ parse_components_from_image(image)[:tag] if object_info.entries.size == 1
89
77
  end
90
78
 
91
79
  def to_s
@@ -95,17 +83,7 @@ module Inspec::Resources
95
83
 
96
84
  private
97
85
 
98
- def image_name_from_image
99
- return if image.nil?
100
- # possible image names include:
101
- # alpine
102
- # ubuntu:14.04
103
- # repo.example.com:5000/ubuntu
104
- # repo.example.com:5000/ubuntu:1404
105
- image.include?('/') ? image.split('/')[1] : image
106
- end
107
-
108
- def container_info
86
+ def object_info
109
87
  return @info if defined?(@info)
110
88
  opts = @opts
111
89
  @info = inspec.docker.containers.where { names == opts[:name] || (!id.nil? && !opts[:id].nil? && (id == opts[:id] || id.start_with?(opts[:id]))) }
@@ -6,8 +6,12 @@
6
6
  # author: Patrick Muench
7
7
  # author: Dominik Richter
8
8
 
9
+ require_relative 'docker_object'
10
+
9
11
  module Inspec::Resources
10
12
  class DockerImage < Inspec.resource(1)
13
+ include Inspec::Resources::DockerObject
14
+
11
15
  name 'docker_image'
12
16
  desc ''
13
17
  example "
@@ -35,24 +39,16 @@ module Inspec::Resources
35
39
  @opts = sanitize_options(o)
36
40
  end
37
41
 
38
- def exist?
39
- image_info.exists?
40
- end
41
-
42
- def id
43
- image_info.ids[0] if image_info.entries.size == 1
44
- end
45
-
46
42
  def image
47
- "#{repo}:#{tag}" if image_info.entries.size == 1
43
+ "#{repo}:#{tag}" if object_info.entries.size == 1
48
44
  end
49
45
 
50
46
  def repo
51
- image_info.repositories[0] if image_info.entries.size == 1
47
+ object_info.repositories[0] if object_info.entries.size == 1
52
48
  end
53
49
 
54
50
  def tag
55
- image_info.tags[0] if image_info.entries.size == 1
51
+ object_info.tags[0] if object_info.entries.size == 1
56
52
  end
57
53
 
58
54
  def to_s
@@ -79,46 +75,12 @@ module Inspec::Resources
79
75
  opts
80
76
  end
81
77
 
82
- def image_info
78
+ def object_info
83
79
  return @info if defined?(@info)
84
80
  opts = @opts
85
81
  @info = inspec.docker.images.where {
86
82
  (repository == opts[:repo] && tag == opts[:tag]) || (!id.nil? && !opts[:id].nil? && (id == opts[:id] || id.start_with?(opts[:id])))
87
83
  }
88
84
  end
89
-
90
- def parse_components_from_image(image_string)
91
- # if the user did not supply an image string, they likely supplied individual
92
- # option parameters, such as repo and tag. Return empty data back to the caller.
93
- return {} if image_string.nil?
94
-
95
- first_colon = image_string.index(':') || -1
96
- first_slash = image_string.index('/') || -1
97
-
98
- if image_string.count(':') == 2
99
- # If there are two colons in the image string, it contains a repo-with-port and a tag.
100
- # example: localhost:5000/chef/inspec:1.46.3
101
- partitioned_string = image_string.rpartition(':')
102
- repo = partitioned_string.first
103
- tag = partitioned_string.last
104
- elsif image_string.count(':') == 1 && first_colon < first_slash
105
- # If there's one colon in the image string, and it comes before a forward-slash,
106
- # it contains a repo-with-port but no tag.
107
- # example: localhost:5000/ubuntu
108
- repo = image_string
109
- tag = nil
110
- else
111
- # If there's one colon in the image string and it doesn't preceed a slash, or if
112
- # there is no colon at all, then it separates the repo from the tag, if there is a tag.
113
- # example: chef/inspec:1.46.3
114
- # example: chef/inspec
115
- # example: ubuntu:14.04
116
- repo, tag = image_string.split(':')
117
- end
118
-
119
- # return the repo and tag parsed from the string, which can be merged into
120
- # the rest of the user-supplied options
121
- { repo: repo, tag: tag }
122
- end
123
85
  end
124
86
  end
@@ -0,0 +1,57 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Copyright 2017, Christoph Hartmann
4
+ #
5
+ # author: Christoph Hartmann
6
+ # author: Patrick Muench
7
+ # author: Dominik Richter
8
+ # author: Matt Kulka
9
+
10
+ module Inspec::Resources::DockerObject
11
+ def exist?
12
+ object_info.exists?
13
+ end
14
+
15
+ def id
16
+ object_info.ids[0] if object_info.entries.size == 1
17
+ end
18
+
19
+ private
20
+
21
+ def parse_components_from_image(image_string)
22
+ # if the user did not supply an image string, they likely supplied individual
23
+ # option parameters, such as repo and tag. Return empty data back to the caller.
24
+ return {} if image_string.nil?
25
+
26
+ first_colon = image_string.index(':') || -1
27
+ first_slash = image_string.index('/') || -1
28
+
29
+ if image_string.count(':') == 2
30
+ # If there are two colons in the image string, it contains a repo-with-port and a tag.
31
+ # example: localhost:5000/chef/inspec:1.46.3
32
+ partitioned_string = image_string.rpartition(':')
33
+ repo = partitioned_string.first
34
+ tag = partitioned_string.last
35
+ image_name = repo.split('/')[1..-1].join
36
+ elsif image_string.count(':') == 1 && first_colon < first_slash
37
+ # If there's one colon in the image string, and it comes before a forward-slash,
38
+ # it contains a repo-with-port but no tag.
39
+ # example: localhost:5000/ubuntu
40
+ repo = image_string
41
+ tag = nil
42
+ image_name = repo.split('/')[1..-1].join
43
+ else
44
+ # If there's one colon in the image string and it doesn't preceed a slash, or if
45
+ # there is no colon at all, then it separates the repo from the tag, if there is a tag.
46
+ # example: chef/inspec:1.46.3
47
+ # example: chef/inspec
48
+ # example: ubuntu:14.04
49
+ repo, tag = image_string.split(':')
50
+ image_name = repo
51
+ end
52
+
53
+ # return the repo, image_name and tag parsed from the string, which can be merged into
54
+ # the rest of the user-supplied options
55
+ { repo: repo, image_name: image_name, tag: tag }
56
+ end
57
+ end
@@ -0,0 +1,94 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Copyright 2017, Christoph Hartmann
4
+ #
5
+ # author: Christoph Hartmann
6
+ # author: Patrick Muench
7
+ # author: Dominik Richter
8
+ # author: Matt Kulka
9
+
10
+ require_relative 'docker_object'
11
+
12
+ module Inspec::Resources
13
+ class DockerService < Inspec.resource(1)
14
+ include Inspec::Resources::DockerObject
15
+
16
+ name 'docker_service'
17
+ desc 'Swarm-mode service'
18
+ example "
19
+ describe docker_service('service1') do
20
+ it { should exist }
21
+ its('id') { should_not eq '' }
22
+ its('image') { should eq 'alpine:latest' }
23
+ its('repo') { should eq 'alpine' }
24
+ its('tag') { should eq 'latest' }
25
+ end
26
+
27
+ describe docker_service(id: '4a415e366388') do
28
+ it { should exist }
29
+ end
30
+
31
+ describe docker_service(image: 'alpine:latest') do
32
+ it { should exist }
33
+ end
34
+ "
35
+
36
+ def initialize(opts = {})
37
+ # do sanitizion of input values
38
+ o = opts.dup
39
+ o = { name: opts } if opts.is_a?(String)
40
+ @opts = sanitize_options(o)
41
+ end
42
+
43
+ def name
44
+ object_info.names[0] if object_info.entries.size == 1
45
+ end
46
+
47
+ def image
48
+ object_info.images[0] if object_info.entries.size == 1
49
+ end
50
+
51
+ def image_name
52
+ parse_components_from_image(image)[:image_name] if object_info.entries.size == 1
53
+ end
54
+
55
+ def repo
56
+ parse_components_from_image(image)[:repo] if object_info.entries.size == 1
57
+ end
58
+
59
+ def tag
60
+ parse_components_from_image(image)[:tag] if object_info.entries.size == 1
61
+ end
62
+
63
+ def mode
64
+ object_info.modes[0] if object_info.entries.size == 1
65
+ end
66
+
67
+ def replicas
68
+ object_info.replicas[0] if object_info.entries.size == 1
69
+ end
70
+
71
+ def ports
72
+ object_info.ports[0] if object_info.entries.size == 1
73
+ end
74
+
75
+ def to_s
76
+ service = @opts[:name] || @opts[:id]
77
+ "Docker Service #{service}"
78
+ end
79
+
80
+ private
81
+
82
+ def sanitize_options(opts)
83
+ opts.merge(parse_components_from_image(opts[:image]))
84
+ end
85
+
86
+ def object_info
87
+ return @info if defined?(@info)
88
+ opts = @opts
89
+ @info = inspec.docker.services.where {
90
+ name == opts[:name] || image == opts[:image] || (!id.nil? && !opts[:id].nil? && (id == opts[:id] || id.start_with?(opts[:id])))
91
+ }
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,31 @@
1
+ module Inspec::Resources
2
+ class FileSystemResource < Inspec.resource(1)
3
+ name 'filesystem'
4
+ supports os_family: 'linux'
5
+ desc 'Use the filesystem InSpec resource to test file system'
6
+ example "
7
+ describe filesystem('/') do
8
+ its('size') { should be >= 32000 }
9
+ end
10
+ "
11
+ attr_reader :partition
12
+
13
+ def initialize(partition)
14
+ @partition = partition
15
+ end
16
+
17
+ def size
18
+ @size ||= begin
19
+ cmd = inspec.command("df #{partition} --output=size")
20
+ raise Inspec::Exceptions::ResourceFailed, "Unable to get available space for partition #{partition}" if cmd.stdout.nil? || cmd.stdout.empty? || !cmd.exit_status.zero?
21
+
22
+ value = cmd.stdout.gsub(/\dK-blocks[\r\n]/, '').strip
23
+ value.to_i
24
+ end
25
+ end
26
+
27
+ def to_s
28
+ "Filesystem #{partition}"
29
+ end
30
+ end
31
+ end
@@ -36,6 +36,7 @@ class GrubConfig < Inspec.resource(1)
36
36
  elsif os.debian?
37
37
  @conf_path = path || '/boot/grub/grub.cfg'
38
38
  @defaults_path = '/etc/default/grub'
39
+ @grubenv_path = '/boot/grub2/grubenv'
39
40
  @version = 'grub2'
40
41
  elsif os[:name] == 'amazon'
41
42
  @conf_path = path || '/etc/grub.conf'
@@ -52,6 +53,7 @@ class GrubConfig < Inspec.resource(1)
52
53
  else
53
54
  @conf_path = path || '/boot/grub2/grub.cfg'
54
55
  @defaults_path = '/etc/default/grub'
56
+ @grubenv_path = '/boot/grub2/grubenv'
55
57
  @version = 'grub2'
56
58
  end
57
59
  end
@@ -71,35 +73,73 @@ class GrubConfig < Inspec.resource(1)
71
73
  ######################################################################
72
74
 
73
75
  def grub2_parse_kernel_lines(content, conf)
74
- # Find all "menuentry" lines and then parse them into arrays
75
- menu_entry = 0
76
+ menu_entries = extract_menu_entries(content)
77
+
78
+ if @kernel == 'default'
79
+ default_menu_entry(menu_entries, conf['GRUB_DEFAULT'])
80
+ else
81
+ menu_entries.find { |entry| entry['name'] == @kernel }
82
+ end
83
+ end
84
+
85
+ def extract_menu_entries(content)
86
+ menu_entries = []
87
+
76
88
  lines = content.split("\n")
77
- kernel_opts = {}
78
- kernel_opts['insmod'] = []
79
- lines.each_with_index do |file_line, index|
80
- next unless file_line =~ /(^|\s)menuentry\s.*/
81
- lines.drop(index+1).each do |kernel_line|
82
- next if kernel_line =~ /(^|\s)(menu|}).*/
83
- if menu_entry == conf['GRUB_DEFAULT'].to_i && @kernel == 'default'
84
- if kernel_line =~ /(^|\s)initrd.*/
85
- kernel_opts['initrd'] = kernel_line.split(' ')[1]
86
- end
87
- if kernel_line =~ /(^|\s)linux.*/
88
- kernel_opts['kernel'] = kernel_line.split
89
- end
90
- if kernel_line =~ /(^|\s)set root=.*/
91
- kernel_opts['root'] = kernel_line.split('=')[1].tr('\'', '')
92
- end
93
- if kernel_line =~ /(^|\s)insmod.*/
94
- kernel_opts['insmod'].push(kernel_line.split(' ')[1])
95
- end
96
- else
97
- menu_entry += 1
98
- break
89
+ lines.each_with_index do |line, index|
90
+ next unless line =~ /^menuentry\s+.*/
91
+ entry = {}
92
+ entry['insmod'] = []
93
+
94
+ # Extract name from menuentry line
95
+ capture_data = line.match(/(?:^|\s+).*menuentry\s*['|"](.*)['|"]\s*--/)
96
+ if capture_data.nil? || capture_data.captures[0].nil?
97
+ raise Inspec::Exceptions::ResourceFailed "Failed to extract menuentry name from #{line}"
98
+ end
99
+
100
+ entry['name'] = capture_data.captures[0]
101
+
102
+ # Begin processing from index forward until a `}` line is met
103
+ lines.drop(index+1).each do |mline|
104
+ break if mline =~ /^\s*}\s*$/
105
+ case mline
106
+ when /(?:^|\s*)initrd.*/
107
+ entry['initrd'] = mline.split(' ')[1]
108
+ when /(?:^|\s*)linux.*/
109
+ entry['kernel'] = mline.split
110
+ when /(?:^|\s*)set root=.*/
111
+ entry['root'] = mline.split('=')[1].tr('\'', '')
112
+ when /(?:^|\s*)insmod.*/
113
+ entry['insmod'] << mline.split(' ')[1]
99
114
  end
100
115
  end
116
+
117
+ menu_entries << entry
101
118
  end
102
- kernel_opts
119
+
120
+ menu_entries
121
+ end
122
+
123
+ def default_menu_entry(menu_entries, default)
124
+ # If the default entry isn't `saved` then a number is used as an index.
125
+ # By default this is `0`, which would be the first item in the list.
126
+ return menu_entries[default.to_i] unless default == 'saved'
127
+
128
+ grubenv_contents = inspec.file(@grubenv_path).content
129
+
130
+ # The location of the grubenv file is not guaranteed. In the case that
131
+ # the file does not exist this will return the 0th entry. This will also
132
+ # return the 0th entry if InSpec lacks permission to read the file. Both
133
+ # of these reflect the default Grub2 behavior.
134
+ return menu_entries[0] if grubenv_contents.nil?
135
+
136
+ default_name = SimpleConfig.new(grubenv_contents).params['saved_entry']
137
+ default_entry = menu_entries.select { |k| k['name'] == default_name }[0]
138
+ return default_entry unless default_entry.nil?
139
+
140
+ # It is possible for the saved entry to not be valid . For example, grubenv
141
+ # not being up to date. If so, the 0th entry is the default.
142
+ menu_entries[0]
103
143
  end
104
144
 
105
145
  ###################################################################
@@ -74,8 +74,16 @@ module Inspec::Resources
74
74
  describe security_policy do
75
75
  its('SeNetworkLogonRight') { should include 'S-1-5-11' }
76
76
  end
77
+
78
+ describe security_policy(translate_sid: true) do
79
+ its('SeNetworkLogonRight') { should include 'NT AUTHORITY\\Authenticated Users' }
80
+ end
77
81
  "
78
82
 
83
+ def initialize(opts = {})
84
+ @translate_sid = opts[:translate_sid] || false
85
+ end
86
+
79
87
  def content
80
88
  read_content
81
89
  end
@@ -142,10 +150,17 @@ module Inspec::Resources
142
150
  if val =~ /^\d+$/
143
151
  val.to_i
144
152
  # special handling for SID array
145
- elsif val =~ /^\*\S/
146
- val.split(',').map { |v|
147
- v.sub('*S', 'S')
148
- }
153
+ elsif val =~ /[,]{0,1}\*\S/
154
+ if @translate_sid
155
+ val.split(',').map { |v|
156
+ object_name = inspec.command("(New-Object System.Security.Principal.SecurityIdentifier(\"#{v.sub('*S', 'S')}\")).Translate( [System.Security.Principal.NTAccount]).Value").stdout.to_s.strip
157
+ object_name.empty? || object_name.nil? ? v.sub('*S', 'S') : object_name
158
+ }
159
+ else
160
+ val.split(',').map { |v|
161
+ v.sub('*S', 'S')
162
+ }
163
+ end
149
164
  # special handling for string values with "
150
165
  elsif !(m = /^\"(.*)\"$/.match(val)).nil?
151
166
  m[1]
@@ -250,7 +250,17 @@ module Inspec::Resources
250
250
  end
251
251
 
252
252
  def is_enabled?(service_name)
253
- inspec.command("#{service_ctl} is-enabled #{service_name} --quiet").exit_status == 0
253
+ result = inspec.command("#{service_ctl} is-enabled #{service_name} --quiet")
254
+ return true if result.exit_status == 0
255
+
256
+ # Some systems may not have a `.service` file for a particular service
257
+ # which causes the `systemctl is-enabled` check to fail despite the
258
+ # service being enabled. In that event we fallback to `sysv_service`.
259
+ if result.stderr =~ /Failed to get.*No such file or directory/
260
+ return inspec.sysv_service(service_name).enabled?
261
+ end
262
+
263
+ false
254
264
  end
255
265
 
256
266
  def is_active?(service_name)
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.50.1
4
+ version: 1.51.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dominik Richter
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-01-17 00:00:00.000000000 Z
11
+ date: 2018-01-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: train
@@ -319,6 +319,7 @@ files:
319
319
  - docs/resources/docker.md.erb
320
320
  - docs/resources/docker_container.md.erb
321
321
  - docs/resources/docker_image.md.erb
322
+ - docs/resources/docker_service.md.erb
322
323
  - docs/resources/elasticsearch.md.erb
323
324
  - docs/resources/etc_fstab.md.erb
324
325
  - docs/resources/etc_group.md.erb
@@ -326,6 +327,7 @@ files:
326
327
  - docs/resources/etc_hosts_allow.md.erb
327
328
  - docs/resources/etc_hosts_deny.md.erb
328
329
  - docs/resources/file.md.erb
330
+ - docs/resources/filesystem.md.erb
329
331
  - docs/resources/firewalld.md.erb
330
332
  - docs/resources/gem.md.erb
331
333
  - docs/resources/group.md.erb
@@ -571,12 +573,15 @@ files:
571
573
  - lib/resources/docker.rb
572
574
  - lib/resources/docker_container.rb
573
575
  - lib/resources/docker_image.rb
576
+ - lib/resources/docker_object.rb
577
+ - lib/resources/docker_service.rb
574
578
  - lib/resources/elasticsearch.rb
575
579
  - lib/resources/etc_fstab.rb
576
580
  - lib/resources/etc_group.rb
577
581
  - lib/resources/etc_hosts.rb
578
582
  - lib/resources/etc_hosts_allow_deny.rb
579
583
  - lib/resources/file.rb
584
+ - lib/resources/filesystem.rb
580
585
  - lib/resources/firewalld.rb
581
586
  - lib/resources/gem.rb
582
587
  - lib/resources/groups.rb