inspec 1.42.3 → 1.43.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -32,7 +32,7 @@ module Compliance
32
32
  if config['token'].nil? && config['refresh_token'].nil?
33
33
  if config['server_type'] == 'automate'
34
34
  server = 'automate'
35
- msg = 'inspec compliance login_automate https://your_automate_server --user USER --ent ENT --dctoken DCTOKEN or --usertoken USERTOKEN'
35
+ msg = 'inspec compliance login https://your_automate_server --user USER --ent ENT --dctoken DCTOKEN or --token USERTOKEN'
36
36
  else
37
37
  server = 'compliance'
38
38
  msg = "inspec compliance login https://your_compliance_server --user admin --insecure --token 'PASTE TOKEN HERE' "
@@ -90,8 +90,7 @@ EOF
90
90
 
91
91
  raise 'Unable to determine compliance profile name. This can be caused by ' \
92
92
  'an incorrect server in your configuration. Try to login to compliance ' \
93
- 'via the `inspec compliance login` or `inspec compliance login_automate` ' \
94
- 'commands.' if m.nil?
93
+ 'via the `inspec compliance login` command.' if m.nil?
95
94
 
96
95
  "#{m[:owner]}/#{m[:id]}"
97
96
  end
@@ -2,10 +2,11 @@
2
2
 
3
3
  module Inspec
4
4
  class Control
5
- attr_accessor :id, :title, :desc, :impact, :tests, :tags
5
+ attr_accessor :id, :title, :desc, :impact, :tests, :tags, :refs
6
6
  def initialize
7
7
  @tests = []
8
8
  @tags = []
9
+ @refs = []
9
10
  end
10
11
 
11
12
  def add_test(t)
@@ -20,12 +21,13 @@ module Inspec
20
21
  { id: id, title: title, desc: desc, impact: impact, tests: tests.map(&:to_hash), tags: tags.map(&:to_hash) }
21
22
  end
22
23
 
23
- def to_ruby
24
+ def to_ruby # rubocop:disable Metrics/AbcSize
24
25
  res = ["control #{id.inspect} do"]
25
26
  res.push " title #{title.inspect}" unless title.to_s.empty?
26
27
  res.push " desc #{prettyprint_text(desc, 2)}" unless desc.to_s.empty?
27
28
  res.push " impact #{impact}" unless impact.nil?
28
29
  tags.each { |t| res.push(indent(t.to_ruby, 2)) }
30
+ refs.each { |t| res.push(" ref #{print_ref(t)}") }
29
31
  tests.each { |t| res.push(indent(t.to_ruby, 2)) }
30
32
  res.push 'end'
31
33
  res.join("\n")
@@ -33,6 +35,12 @@ module Inspec
33
35
 
34
36
  private
35
37
 
38
+ def print_ref(x)
39
+ return x.inspect if x.is_a?(String)
40
+ raise "Cannot process the ref: #{x}" unless x.is_a?(Hash)
41
+ '('+x.inspect+')'
42
+ end
43
+
36
44
  # Pretty-print a text block of InSpec code
37
45
  #
38
46
  # @param s [String] should not be empty
@@ -106,7 +106,8 @@ module Inspec
106
106
  # we share the backend between profiles.
107
107
  #
108
108
  # This will cause issues if a profile attempts to load a file via `inspec.profile.file`
109
- @backend = options[:backend].nil? ? Inspec::Backend.create(options) : options[:backend].dup
109
+ train_options = options.select { |k, _| k != 'target' } # See https://github.com/chef/inspec/pull/1646
110
+ @backend = options[:backend].nil? ? Inspec::Backend.create(train_options) : options[:backend].dup
110
111
  @runtime_profile = RuntimeProfile.new(self)
111
112
  @backend.profile = @runtime_profile
112
113
 
@@ -84,12 +84,15 @@ require 'resources/bash'
84
84
  require 'resources/bond'
85
85
  require 'resources/bridge'
86
86
  require 'resources/command'
87
+ require 'resources/cran'
88
+ require 'resources/cpan'
87
89
  require 'resources/crontab'
88
90
  require 'resources/dh_params'
89
91
  require 'resources/directory'
90
92
  require 'resources/docker'
91
93
  require 'resources/docker_container'
92
94
  require 'resources/docker_image'
95
+ require 'resources/elasticsearch'
93
96
  require 'resources/etc_fstab'
94
97
  require 'resources/etc_group'
95
98
  require 'resources/etc_hosts_allow_deny'
@@ -4,5 +4,5 @@
4
4
  # author: Christoph Hartmann
5
5
 
6
6
  module Inspec
7
- VERSION = '1.42.3'.freeze
7
+ VERSION = '1.43.5'.freeze
8
8
  end
@@ -0,0 +1,60 @@
1
+ # encoding: utf-8
2
+ # author: Christoph Hartmann
3
+ # author: Dominik Richter
4
+ # author: Markus Grobelin
5
+
6
+ # Usage:
7
+ # describe cpan('DBD::Pg') do
8
+ # it { should be_installed }
9
+ # end
10
+ #
11
+
12
+ module Inspec::Resources
13
+ class CpanPackage < Inspec.resource(1)
14
+ name 'cpan'
15
+ desc 'Use the `cpan` InSpec audit resource to test Perl modules that are installed by system packages or the CPAN installer.'
16
+ example "
17
+ describe cpan('DBD::Pg') do
18
+ it { should be_installed }
19
+ end
20
+ "
21
+
22
+ def initialize(package_name, perl_lib_path = nil)
23
+ @package_name = package_name
24
+ @perl_lib_path = perl_lib_path
25
+ @perl_cmd = 'perl'
26
+
27
+ # this resource is not supported on Windows
28
+ return skip_resource 'The `cpan` resource is not supported on your OS yet.' if inspec.os.windows?
29
+ return skip_resource 'perl not found' unless inspec.command(@perl_cmd).exist?
30
+ end
31
+
32
+ def info
33
+ return @info if defined?(@info)
34
+
35
+ @info = {}
36
+ @info[:type] = 'cpan'
37
+ @info[:name] = @package_name
38
+ # set PERL5LIB environment variable if a custom lib path is given
39
+ lib_path = @perl_lib_path.nil? ? '' : "PERL5LIB=#{@perl_lib_path} "
40
+ cmd = inspec.command("#{lib_path+@perl_cmd} -le 'eval \"require $ARGV[0]\" and print $ARGV[0]->VERSION or exit 1' #{@package_name}")
41
+ @info[:installed] = cmd.exit_status.zero?
42
+ return @info unless cmd.exit_status.zero?
43
+
44
+ @info[:version] = cmd.stdout.strip
45
+ @info
46
+ end
47
+
48
+ def installed?
49
+ info[:installed] == true
50
+ end
51
+
52
+ def version
53
+ info[:version]
54
+ end
55
+
56
+ def to_s
57
+ "Perl Module #{@package_name}"
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,66 @@
1
+ # encoding: utf-8
2
+ # author: Christoph Hartmann
3
+ # author: Dominik Richter
4
+ # author: Markus Grobelin
5
+
6
+ # Usage:
7
+ # describe cran('DBI') do
8
+ # it { should be_installed }
9
+ # end
10
+ #
11
+
12
+ module Inspec::Resources
13
+ class CranPackage < Inspec.resource(1)
14
+ name 'cran'
15
+ desc 'Use the `cran` InSpec audit resource to test R modules that are installed from CRAN package repository.'
16
+ example "
17
+ describe cran('DBI') do
18
+ it { should be_installed }
19
+ end
20
+ "
21
+
22
+ def initialize(package_name)
23
+ @package_name = package_name
24
+ @r_cmd = 'Rscript'
25
+
26
+ # this resource is not supported on Windows
27
+ return skip_resource 'The `cran` resource is not supported on your OS yet.' if inspec.os.windows?
28
+ return skip_resource 'Rscript not found' unless inspec.command(@r_cmd).exist?
29
+ end
30
+
31
+ def info
32
+ return @info if defined?(@info)
33
+
34
+ @info = {}
35
+ @info[:type] = 'cran'
36
+ @info[:name] = @package_name
37
+ cmd = inspec.command("#{@r_cmd} -e 'packageVersion(\"#{@package_name}\")'")
38
+ return @info unless cmd.exit_status.zero?
39
+
40
+ # Extract package version from Rscript output
41
+ # Output includes unicode punctuation (backticks) characters like so:
42
+ # [1] '0.5.1'
43
+ #
44
+ # So make sure command output is converted to unicode, as it returns ASCII-8BIT by default
45
+ utf8_stdout = cmd.stdout.chomp.force_encoding(Encoding::UTF_8)
46
+ params = /^\[\d+\]\s+(?:\p{Initial_Punctuation})(.+)(?:\p{Final_Punctuation})$/.match(utf8_stdout)
47
+ @info[:installed] = !params.nil?
48
+ return @info unless @info[:installed]
49
+
50
+ @info[:version] = params[1]
51
+ @info
52
+ end
53
+
54
+ def installed?
55
+ info[:installed] == true
56
+ end
57
+
58
+ def version
59
+ info[:version]
60
+ end
61
+
62
+ def to_s
63
+ "R Module #{@package_name}"
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,172 @@
1
+ # encoding: utf-8
2
+
3
+ require 'utils/filter'
4
+ require 'hashie/mash'
5
+ require 'resources/package'
6
+
7
+ module Inspec::Resources
8
+ class Elasticsearch < Inspec.resource(1) # rubocop:disable Metrics/ClassLength
9
+ name 'elasticsearch'
10
+ desc "Use the Elasticsearch InSpec audit resource to test the status of nodes in
11
+ an Elasticsearch cluster."
12
+
13
+ example "
14
+ describe elasticsearch('http://eshost.mycompany.biz:9200/', username: 'elastic', password: 'changeme', ssl_verify: false) do
15
+ its('node_count') { should >= 3 }
16
+ end
17
+
18
+ describe elasticsearch do
19
+ its('node_name') { should include 'node1' }
20
+ its('os') { should_not include 'MacOS' }
21
+ its('version') { should cmp > 1.2.0 }
22
+ end
23
+ "
24
+
25
+ filter = FilterTable.create
26
+ filter.add_accessor(:where)
27
+ .add_accessor(:entries)
28
+ .add(:cluster_name, field: 'cluster_name')
29
+ .add(:node_name, field: 'name')
30
+ .add(:transport_address, field: 'transport_address')
31
+ .add(:host, field: 'host')
32
+ .add(:ip, field: 'ip')
33
+ .add(:version, field: 'version')
34
+ .add(:build_hash, field: 'build_hash')
35
+ .add(:total_indexing_buffer, field: 'total_indexing_buffer')
36
+ .add(:roles, field: 'roles')
37
+ .add(:settings, field: 'settings')
38
+ .add(:os, field: 'os')
39
+ .add(:process, field: 'process')
40
+ .add(:jvm, field: 'jvm')
41
+ .add(:transport, field: 'transport')
42
+ .add(:http, field: 'http')
43
+ .add(:plugins, field: 'plugins')
44
+ .add(:plugin_list, field: 'plugin_list')
45
+ .add(:modules, field: 'modules')
46
+ .add(:module_list, field: 'module_list')
47
+ .add(:node_id, field: 'node_id')
48
+ .add(:ingest, field: 'ingest')
49
+ .add(:exists?) { |x| !x.entries.empty? }
50
+ .add(:node_count) { |t, _|
51
+ t.entries.length
52
+ }
53
+
54
+ filter.connect(self, :nodes)
55
+
56
+ attr_reader :nodes, :url
57
+
58
+ def initialize(opts = {})
59
+ return skip_resource 'Package `curl` not avaiable on the host' unless inspec.command('curl').exist?
60
+
61
+ @url = opts.fetch(:url, 'http://localhost:9200')
62
+
63
+ username = opts.fetch(:username, nil)
64
+ password = opts.fetch(:password, nil)
65
+ ssl_verify = opts.fetch(:ssl_verify, true)
66
+
67
+ cmd = inspec.command(curl_command_string(username, password, ssl_verify))
68
+
69
+ # after implementation of PR #2235, this begin..rescue won't be necessary.
70
+ # The checks in verify_curl_success! can raise their own skip message exception.
71
+ begin
72
+ verify_curl_success!(cmd)
73
+ rescue => e
74
+ return skip_resource e.message
75
+ end
76
+
77
+ begin
78
+ content = JSON.parse(cmd.stdout)
79
+ # after implementation of PR #2235, this can be broken out of the begin..rescue
80
+ # clause. The checks in verify_json_payload! can raise their own skip message exception.
81
+ verify_json_payload!(content)
82
+ rescue JSON::ParserError => e
83
+ return skip_resource "Couldn't parse the Elasticsearch response: #{e.message}"
84
+ rescue => e
85
+ return skip_resource e.message
86
+ end
87
+
88
+ @nodes = parse_cluster(content)
89
+ end
90
+
91
+ def to_s
92
+ "Elasticsearch Cluster #{url}"
93
+ end
94
+
95
+ private
96
+
97
+ def parse_cluster(content)
98
+ return [] unless content['nodes']
99
+
100
+ nodes = []
101
+
102
+ content['nodes'].each do |node_id, node_data|
103
+ node_data = fix_mash_key_collision(node_data)
104
+
105
+ node = Hashie::Mash.new(node_data)
106
+ node.node_id = node_id
107
+ node.plugin_list = node.plugins.map(&:name)
108
+ node.module_list = node.modules.map(&:name)
109
+ node.cluster_name = node.settings.cluster.name
110
+ nodes << node
111
+ end
112
+
113
+ nodes
114
+ end
115
+
116
+ #
117
+ # Hashie::Mash will throw warnings if the Mash contains a key that is the same as a built-in
118
+ # method on a Hashie::Mash instance. This is a crude way of avoiding those warnings without
119
+ # hard-coding a bunch of key renames.
120
+ #
121
+ # Any key that is in conflict will be renamed "es_ORIGINALKEY"
122
+ #
123
+ def fix_mash_key_collision(data)
124
+ test_mash = Hashie::Mash.new
125
+
126
+ new_data = {}
127
+ data.each do |key, value|
128
+ new_key = test_mash.respond_to?(key.to_sym) ? "es_#{key}" : key
129
+ new_value = value.is_a?(Hash) ? fix_mash_key_collision(value) : value
130
+
131
+ new_data[new_key] = new_value
132
+ end
133
+
134
+ new_data
135
+ end
136
+
137
+ def curl_command_string(username, password, ssl_verify)
138
+ cmd_string = ['curl']
139
+ cmd_string << '-k' unless ssl_verify
140
+ cmd_string << "-H 'Content-Type: application/json'"
141
+ cmd_string << " -u #{username}:#{password}" unless username.nil? || password.nil?
142
+ cmd_string << URI.join(url, '_nodes')
143
+
144
+ cmd_string.join(' ')
145
+ end
146
+
147
+ def verify_curl_success!(cmd)
148
+ # the following lines captures known possible curl command errors and provides compact skip resource messeges
149
+ if cmd.stderr =~ /Failed to connect/
150
+ raise "Connection refused - please check the URL #{url} for accuracy"
151
+ end
152
+
153
+ if cmd.stderr =~ /Peer's Certificate issuer is not recognized/
154
+ raise 'Connection refused - peer certificate issuer is not recognized'
155
+ end
156
+
157
+ if !cmd.exit_status.zero?
158
+ raise "Error fetching Elastcsearch data from curl #{url}: #{cmd.stderr}"
159
+ end
160
+ end
161
+
162
+ def verify_json_payload!(content)
163
+ unless content['error'].nil?
164
+ raise "#{content['error']['type']}: #{content['error']['reason']}"
165
+ end
166
+
167
+ if content['_nodes']['successful'].zero?
168
+ raise 'No successful nodes available in cluster'
169
+ end
170
+ end
171
+ end
172
+ 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.42.3
4
+ version: 1.43.5
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-10-18 00:00:00.000000000 Z
11
+ date: 2017-10-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: train
@@ -324,6 +324,8 @@ files:
324
324
  - docs/resources/bridge.md.erb
325
325
  - docs/resources/bsd_service.md.erb
326
326
  - docs/resources/command.md.erb
327
+ - docs/resources/cpan.md.erb
328
+ - docs/resources/cran.md.erb
327
329
  - docs/resources/crontab.md.erb
328
330
  - docs/resources/csv.md.erb
329
331
  - docs/resources/dh_params.md
@@ -331,6 +333,7 @@ files:
331
333
  - docs/resources/docker.md.erb
332
334
  - docs/resources/docker_container.md.erb
333
335
  - docs/resources/docker_image.md.erb
336
+ - docs/resources/elasticsearch.md.erb
334
337
  - docs/resources/etc_fstab.md.erb
335
338
  - docs/resources/etc_group.md.erb
336
339
  - docs/resources/etc_hosts.md.erb
@@ -467,6 +470,7 @@ files:
467
470
  - lib/bundles/inspec-compliance/.kitchen.yml
468
471
  - lib/bundles/inspec-compliance/README.md
469
472
  - lib/bundles/inspec-compliance/api.rb
473
+ - lib/bundles/inspec-compliance/api/login.rb
470
474
  - lib/bundles/inspec-compliance/bootstrap.sh
471
475
  - lib/bundles/inspec-compliance/cli.rb
472
476
  - lib/bundles/inspec-compliance/configuration.rb
@@ -572,6 +576,8 @@ files:
572
576
  - lib/resources/bond.rb
573
577
  - lib/resources/bridge.rb
574
578
  - lib/resources/command.rb
579
+ - lib/resources/cpan.rb
580
+ - lib/resources/cran.rb
575
581
  - lib/resources/crontab.rb
576
582
  - lib/resources/csv.rb
577
583
  - lib/resources/dh_params.rb
@@ -579,6 +585,7 @@ files:
579
585
  - lib/resources/docker.rb
580
586
  - lib/resources/docker_container.rb
581
587
  - lib/resources/docker_image.rb
588
+ - lib/resources/elasticsearch.rb
582
589
  - lib/resources/etc_fstab.rb
583
590
  - lib/resources/etc_group.rb
584
591
  - lib/resources/etc_hosts.rb