inspec-core 5.17.4 → 5.18.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (133) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/etc/deprecations.json +4 -0
  4. data/inspec-core.gemspec +1 -1
  5. data/lib/inspec/base_cli.rb +5 -0
  6. data/lib/inspec/cli.rb +62 -9
  7. data/lib/inspec/dependencies/dependency_set.rb +6 -2
  8. data/lib/inspec/dsl.rb +18 -5
  9. data/lib/inspec/errors.rb +2 -0
  10. data/lib/inspec/exceptions.rb +2 -0
  11. data/lib/inspec/fetcher/url.rb +1 -1
  12. data/lib/inspec/file_provider.rb +36 -0
  13. data/lib/inspec/iaf_file.rb +127 -0
  14. data/lib/inspec/profile.rb +17 -7
  15. data/lib/inspec/resources/aide_conf.rb +4 -0
  16. data/lib/inspec/resources/apache.rb +4 -0
  17. data/lib/inspec/resources/apache_conf.rb +4 -0
  18. data/lib/inspec/resources/apt.rb +6 -1
  19. data/lib/inspec/resources/audit_policy.rb +5 -0
  20. data/lib/inspec/resources/auditd_conf.rb +4 -0
  21. data/lib/inspec/resources/bash.rb +4 -0
  22. data/lib/inspec/resources/bond.rb +4 -0
  23. data/lib/inspec/resources/bridge.rb +4 -0
  24. data/lib/inspec/resources/cassandradb_conf.rb +5 -0
  25. data/lib/inspec/resources/cassandradb_session.rb +8 -3
  26. data/lib/inspec/resources/chocolatey_package.rb +4 -0
  27. data/lib/inspec/resources/chrony_conf.rb +4 -0
  28. data/lib/inspec/resources/command.rb +5 -0
  29. data/lib/inspec/resources/cpan.rb +4 -0
  30. data/lib/inspec/resources/cran.rb +4 -0
  31. data/lib/inspec/resources/cron.rb +5 -0
  32. data/lib/inspec/resources/csv.rb +6 -1
  33. data/lib/inspec/resources/dh_params.rb +4 -0
  34. data/lib/inspec/resources/docker_container.rb +4 -0
  35. data/lib/inspec/resources/docker_image.rb +4 -0
  36. data/lib/inspec/resources/docker_plugin.rb +4 -0
  37. data/lib/inspec/resources/docker_service.rb +4 -0
  38. data/lib/inspec/resources/etc_group.rb +4 -0
  39. data/lib/inspec/resources/etc_hosts_allow_deny.rb +5 -0
  40. data/lib/inspec/resources/file.rb +6 -1
  41. data/lib/inspec/resources/filesystem.rb +4 -0
  42. data/lib/inspec/resources/gem.rb +4 -0
  43. data/lib/inspec/resources/groups.rb +4 -0
  44. data/lib/inspec/resources/grub_conf.rb +4 -0
  45. data/lib/inspec/resources/host.rb +4 -0
  46. data/lib/inspec/resources/http.rb +4 -0
  47. data/lib/inspec/resources/ibmdb2_conf.rb +8 -0
  48. data/lib/inspec/resources/ibmdb2_session.rb +12 -3
  49. data/lib/inspec/resources/iis_app.rb +4 -0
  50. data/lib/inspec/resources/iis_app_pool.rb +4 -0
  51. data/lib/inspec/resources/iis_site.rb +4 -0
  52. data/lib/inspec/resources/inetd_conf.rb +4 -0
  53. data/lib/inspec/resources/interface.rb +4 -0
  54. data/lib/inspec/resources/ip6tables.rb +4 -0
  55. data/lib/inspec/resources/ipfilter.rb +4 -0
  56. data/lib/inspec/resources/ipnat.rb +4 -0
  57. data/lib/inspec/resources/iptables.rb +4 -0
  58. data/lib/inspec/resources/json.rb +4 -0
  59. data/lib/inspec/resources/kernel_module.rb +4 -0
  60. data/lib/inspec/resources/kernel_parameter.rb +4 -0
  61. data/lib/inspec/resources/key_rsa.rb +4 -0
  62. data/lib/inspec/resources/ksh.rb +4 -0
  63. data/lib/inspec/resources/limits_conf.rb +4 -0
  64. data/lib/inspec/resources/login_defs.rb +4 -0
  65. data/lib/inspec/resources/mongodb.rb +4 -0
  66. data/lib/inspec/resources/mongodb_conf.rb +5 -0
  67. data/lib/inspec/resources/mongodb_session.rb +6 -1
  68. data/lib/inspec/resources/mount.rb +4 -0
  69. data/lib/inspec/resources/mssql_session.rb +4 -0
  70. data/lib/inspec/resources/mssql_sys_conf.rb +7 -0
  71. data/lib/inspec/resources/mysql_conf.rb +4 -0
  72. data/lib/inspec/resources/mysql_session.rb +8 -1
  73. data/lib/inspec/resources/nginx.rb +6 -1
  74. data/lib/inspec/resources/nginx_conf.rb +4 -0
  75. data/lib/inspec/resources/noop.rb +4 -0
  76. data/lib/inspec/resources/npm.rb +4 -0
  77. data/lib/inspec/resources/ntp_conf.rb +4 -0
  78. data/lib/inspec/resources/oneget.rb +4 -0
  79. data/lib/inspec/resources/opa_api.rb +10 -0
  80. data/lib/inspec/resources/opa_cli.rb +14 -0
  81. data/lib/inspec/resources/oracledb_conf.rb +5 -0
  82. data/lib/inspec/resources/oracledb_listener_conf.rb +4 -0
  83. data/lib/inspec/resources/oracledb_session.rb +10 -0
  84. data/lib/inspec/resources/os.rb +4 -0
  85. data/lib/inspec/resources/os_env.rb +4 -0
  86. data/lib/inspec/resources/package.rb +4 -0
  87. data/lib/inspec/resources/parse_config.rb +10 -1
  88. data/lib/inspec/resources/pip.rb +4 -0
  89. data/lib/inspec/resources/platform.rb +4 -0
  90. data/lib/inspec/resources/postfix_conf.rb +4 -0
  91. data/lib/inspec/resources/postgres_conf.rb +4 -0
  92. data/lib/inspec/resources/postgres_session.rb +8 -4
  93. data/lib/inspec/resources/powershell.rb +4 -0
  94. data/lib/inspec/resources/processes.rb +6 -4
  95. data/lib/inspec/resources/rabbitmq_config.rb +4 -0
  96. data/lib/inspec/resources/registry_key.rb +4 -0
  97. data/lib/inspec/resources/security_identifier.rb +4 -0
  98. data/lib/inspec/resources/security_policy.rb +4 -0
  99. data/lib/inspec/resources/service.rb +4 -0
  100. data/lib/inspec/resources/ssh_config.rb +4 -0
  101. data/lib/inspec/resources/sybase_conf.rb +4 -0
  102. data/lib/inspec/resources/sybase_session.rb +4 -0
  103. data/lib/inspec/resources/sys_info.rb +4 -0
  104. data/lib/inspec/resources/timezone.rb +4 -0
  105. data/lib/inspec/resources/users.rb +4 -0
  106. data/lib/inspec/resources/vbscript.rb +5 -0
  107. data/lib/inspec/resources/virtualization.rb +4 -0
  108. data/lib/inspec/resources/windows_feature.rb +5 -1
  109. data/lib/inspec/resources/windows_firewall.rb +4 -0
  110. data/lib/inspec/resources/windows_firewall_rule.rb +4 -0
  111. data/lib/inspec/resources/windows_hotfix.rb +4 -0
  112. data/lib/inspec/resources/windows_task.rb +4 -0
  113. data/lib/inspec/resources/wmi.rb +4 -0
  114. data/lib/inspec/resources/x509_certificate.rb +59 -0
  115. data/lib/inspec/resources/yum.rb +4 -0
  116. data/lib/inspec/resources/zfs_dataset.rb +4 -0
  117. data/lib/inspec/resources/zfs_pool.rb +4 -0
  118. data/lib/inspec/rule.rb +1 -1
  119. data/lib/inspec/secrets/yaml.rb +7 -1
  120. data/lib/inspec/ui.rb +1 -0
  121. data/lib/inspec/utils/yaml_profile_summary.rb +34 -0
  122. data/lib/inspec/version.rb +1 -1
  123. data/lib/plugins/inspec-reporter-html2/templates/body.html.erb +4 -4
  124. data/lib/plugins/inspec-reporter-html2/templates/control.html.erb +1 -1
  125. data/lib/plugins/inspec-reporter-html2/templates/profile.html.erb +1 -1
  126. data/lib/plugins/{inspec-artifact/inspec-artifact.gemspec → inspec-sign/inspec-sign.gemspec} +2 -2
  127. data/lib/plugins/inspec-sign/lib/inspec-sign/base.rb +161 -0
  128. data/lib/plugins/{inspec-artifact/lib/inspec-artifact → inspec-sign/lib/inspec-sign}/cli.rb +14 -23
  129. data/lib/plugins/inspec-sign/lib/inspec-sign.rb +12 -0
  130. data/lib/source_readers/inspec.rb +8 -2
  131. metadata +10 -8
  132. data/lib/plugins/inspec-artifact/lib/inspec-artifact/base.rb +0 -187
  133. data/lib/plugins/inspec-artifact/lib/inspec-artifact.rb +0 -12
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b31dbb074483f274162eeea0fde1b234cd19e1c65257e19f7d0bc2f46c375b70
4
- data.tar.gz: 31756fedad66edc248e5ae7b1ca5ab08408f6d7d6e6ce6dfb9053d1323c1acac
3
+ metadata.gz: ba97ee3e25e02fba9b85f797fa1a773d2e8fa7628112be422d187c0e46cfce40
4
+ data.tar.gz: a82f51e5c6ba3e1db8c4580f92a33d91bcc2e0c2a8339850e1f168c1569b8818
5
5
  SHA512:
6
- metadata.gz: e765163668a3799ae45fbe2a5ddd219832341c32b01b62422506324a62c44b99ad771f47c662be5abb1198fdd65969e2a038f54c5059841561edda42170f7631
7
- data.tar.gz: bbbadea0724f15d1a67c895eab750eea1a660bfc2e65143af703f8b5a88eb9e0c9fde1f9c08356fd9e4b32d202d620902fbad8784618cc01eec866c20f5247c7
6
+ metadata.gz: beb78893376f0b92b9cf33741f8fab471f66dd328fa1f28c87b05737da7f73266327eded07ca67f0b91a747625dfcb61011b42c06a25914d01f727b07a962456
7
+ data.tar.gz: 193aeef4576e2af4466a176b80e107cd45fe0c0c0f6db290d17696cec1eb7dbf6b58b555bf8c0df4b9bb4a9d5aa8d26f542993b5be1d600a296c3ec50e531d09
data/Gemfile CHANGED
@@ -29,7 +29,7 @@ group :test do
29
29
  gem "json_schemer", ">= 0.2.1", "< 0.2.19"
30
30
  gem "m"
31
31
  gem "minitest-sprint", "~> 1.0"
32
- gem "minitest", "~> 5.5"
32
+ gem "minitest", "5.15.0"
33
33
  gem "mocha", "~> 1.1"
34
34
  gem "nokogiri", "~> 1.9"
35
35
  gem "pry-byebug"
@@ -121,6 +121,10 @@
121
121
  "cli_option_target_id":{
122
122
  "action": "warn",
123
123
  "prefix": "The --target-id option is deprecated in InSpec 5. Its value will be ignored."
124
+ },
125
+ "renamed_to_inspec_export":{
126
+ "action": "ignore",
127
+ "prefix": "The `inspec json` command is deprecated in InSpec 5 and replaced with `inspec export` command."
124
128
  }
125
129
  }
126
130
  }
data/inspec-core.gemspec CHANGED
@@ -45,5 +45,5 @@ Gem::Specification.new do |spec|
45
45
  spec.add_dependency "semverse", "~> 3.0"
46
46
  spec.add_dependency "multipart-post", "~> 2.0"
47
47
 
48
- spec.add_dependency "train-core", "~> 3.0"
48
+ spec.add_dependency "train-core", "~> 3.10"
49
49
  end
@@ -138,6 +138,8 @@ module Inspec
138
138
  desc: "Provides path to Docker API endpoint (Docker)"
139
139
  option :ssh_config_file, type: :array,
140
140
  desc: "A list of paths to the ssh config file, e.g ~/.ssh/config or /etc/ssh/ssh_config"
141
+ option :podman_url, type: :string,
142
+ desc: "Provides path to Podman API endpoint"
141
143
  end
142
144
 
143
145
  def self.profile_options
@@ -323,6 +325,9 @@ module Inspec
323
325
 
324
326
  def pretty_handle_exception(exception)
325
327
  case exception
328
+ when Inspec::InvalidProfileSignature
329
+ $stderr.puts exception.message
330
+ Inspec::UI.new.exit(:bad_signature)
326
331
  when Inspec::Error
327
332
  $stderr.puts exception.message
328
333
  exit(1)
data/lib/inspec/cli.rb CHANGED
@@ -5,6 +5,7 @@ require "inspec/dist"
5
5
  require "inspec/backend"
6
6
  require "inspec/dependencies/cache"
7
7
  require "inspec/utils/json_profile_summary"
8
+ require "inspec/utils/yaml_profile_summary"
8
9
 
9
10
  module Inspec # TODO: move this somewhere "better"?
10
11
  autoload :BaseCLI, "inspec/base_cli"
@@ -69,25 +70,77 @@ class Inspec::InspecCLI < Inspec::BaseCLI
69
70
  desc: "A list of tags to filter controls and include only those. Ignore all other tests."
70
71
  profile_options
71
72
  def json(target)
72
- require "json" unless defined?(JSON)
73
+ # This deprecation warning is ignored currently.
74
+ Inspec.deprecate(:renamed_to_inspec_export)
75
+ export(target, true)
76
+ end
73
77
 
78
+ desc "export PATH", "read the profile in PATH and generate a summary in the given format."
79
+ option :what, type: :string,
80
+ desc: "What to export: profile (default), readme, metadata."
81
+ option :format, type: :string,
82
+ desc: "The output format to use: json, raw, yaml. If valid format is not provided then it will use the default for the given 'what'."
83
+ option :output, aliases: :o, type: :string,
84
+ desc: "Save the created output to a path"
85
+ option :controls, type: :array,
86
+ desc: "For --what=profile, a list of controls to include. Ignore all other tests."
87
+ option :tags, type: :array,
88
+ desc: "For --what=profile, a list of tags to filter controls and include only those. Ignore all other tests."
89
+ profile_options
90
+ def export(target, as_json = false)
74
91
  o = config
75
92
  diagnose(o)
76
93
  o["log_location"] = $stderr
77
94
  configure_logger(o)
78
95
 
96
+ # using dup to resolve "can't modify frozen String" error.
97
+ what = o[:what].dup || "profile"
98
+ what.downcase!
99
+ raise Inspec::Error.new("Unrecognized option '#{what}' for --what - expected one of profile, readme, or metadata.") unless %w{profile readme metadata}.include?(what)
100
+
101
+ default_format_for_what = {
102
+ "profile" => "yaml",
103
+ "metadata" => "raw",
104
+ "readme" => "raw",
105
+ }
106
+ valid_formats_for_what = {
107
+ "profile" => %w{yaml json},
108
+ "metadata" => %w{yaml raw}, # not going to argue
109
+ "readme" => ["raw"],
110
+ }
111
+ format = o[:format] || default_format_for_what[what]
112
+ # default is json if we were called as old json command
113
+ format = "json" if as_json
114
+ raise Inspec::Error.new("Invalid option '#{format}' for --format and --what combination") unless format && valid_formats_for_what[what].include?(format)
115
+
79
116
  o[:backend] = Inspec::Backend.create(Inspec::Config.mock)
80
117
  o[:check_mode] = true
81
118
  o[:vendor_cache] = Inspec::Cache.new(o[:vendor_cache])
82
-
83
119
  profile = Inspec::Profile.for_target(target, o)
84
120
  dst = o[:output].to_s
85
121
 
86
- # Write JSON
87
- Inspec::Utils::JsonProfileSummary.produce_json(
88
- info: profile.info,
89
- write_path: dst
90
- )
122
+ case what
123
+ when "profile"
124
+ if format == "json"
125
+ require "json" unless defined?(JSON)
126
+ # Write JSON
127
+ Inspec::Utils::JsonProfileSummary.produce_json(
128
+ info: profile.info,
129
+ write_path: dst
130
+ )
131
+ elsif format == "yaml"
132
+ Inspec::Utils::YamlProfileSummary.produce_yaml(
133
+ info: profile.info,
134
+ write_path: dst
135
+ )
136
+ end
137
+ when "readme"
138
+ out = dst.empty? ? $stdout : File.open(dst, "w")
139
+ out.write(profile.readme)
140
+ when "metadata"
141
+ out = dst.empty? ? $stdout : File.open(dst, "w")
142
+ out.write(profile.metadata_src)
143
+ end
91
144
  rescue StandardError => e
92
145
  pretty_handle_exception(e)
93
146
  end
@@ -189,12 +242,12 @@ class Inspec::InspecCLI < Inspec::BaseCLI
189
242
  desc: "Fallback to using local archives if fetching fails."
190
243
  option :ignore_errors, type: :boolean, default: false,
191
244
  desc: "Ignore profile warnings."
192
- def archive(path)
245
+ def archive(path, log_level = nil)
193
246
  o = config
194
247
  diagnose(o)
195
248
 
196
249
  o[:logger] = Logger.new($stdout)
197
- o[:logger].level = get_log_level(o[:log_level])
250
+ o[:logger].level = get_log_level(log_level || o[:log_level])
198
251
  o[:backend] = Inspec::Backend.create(Inspec::Config.mock)
199
252
 
200
253
  # Force vendoring with overwrite when archiving
@@ -25,7 +25,9 @@ module Inspec
25
25
  def self.from_array(dependencies, cwd, cache, backend)
26
26
  dep_list = {}
27
27
  dependencies.each do |d|
28
- dep_list[d.name] = d
28
+ # if depedent profile does not have a source version then only name is used in dependency hash
29
+ key_name = (d.source_version ? "#{d.name}-#{d.source_version}" : "#{d.name}") rescue "#{d.name}"
30
+ dep_list[key_name] = d
29
31
  end
30
32
  new(cwd, cache, dep_list, backend)
31
33
  end
@@ -39,7 +41,9 @@ module Inspec
39
41
  def self.flatten_dep_tree(dep_tree)
40
42
  dep_list = {}
41
43
  dep_tree.each do |d|
42
- dep_list[d.name] = d
44
+ # if depedent profile does not have a source version then only name is used in dependency hash
45
+ key_name = (d.source_version ? "#{d.name}-#{d.source_version}" : "#{d.name}") rescue d.name
46
+ dep_list[key_name] = d
43
47
  dep_list.merge!(flatten_dep_tree(d.dependencies))
44
48
  end
45
49
  dep_list
data/lib/inspec/dsl.rb CHANGED
@@ -6,13 +6,13 @@ require "inspec/utils/deprecated_cloud_resources_list"
6
6
  module Inspec::DSL
7
7
  attr_accessor :backend
8
8
 
9
- def require_controls(id, &block)
10
- opts = { profile_id: id, include_all: false, backend: @backend, conf: @conf, dependencies: @dependencies }
9
+ def require_controls(id, version = nil, &block)
10
+ opts = { profile_id: id, include_all: false, backend: @backend, conf: @conf, dependencies: @dependencies, profile_version: version }
11
11
  ::Inspec::DSL.load_spec_files_for_profile(self, opts, &block)
12
12
  end
13
13
 
14
- def include_controls(id, &block)
15
- opts = { profile_id: id, include_all: true, backend: @backend, conf: @conf, dependencies: @dependencies }
14
+ def include_controls(id, version = nil, &block)
15
+ opts = { profile_id: id, include_all: true, backend: @backend, conf: @conf, dependencies: @dependencies, profile_version: version }
16
16
  ::Inspec::DSL.load_spec_files_for_profile(self, opts, &block)
17
17
  end
18
18
 
@@ -85,7 +85,20 @@ module Inspec::DSL
85
85
  def self.load_spec_files_for_profile(bind_context, opts, &block)
86
86
  dependencies = opts[:dependencies]
87
87
  profile_id = opts[:profile_id]
88
- dep_entry = dependencies.list[profile_id]
88
+ profile_version = opts[:profile_version]
89
+
90
+ new_profile_id = nil
91
+ if profile_version
92
+ new_profile_id = "#{profile_id}-#{profile_version}"
93
+ else
94
+ dependencies.list.keys.each do |key|
95
+ # If dep profile does not contain a source version, key does not contain a version as well. In that case new_profile_id will be always nil and instead profile_id would be used to fetch profile from dependency list.
96
+ profile_id_key = key.split("-")
97
+ profile_id_key.pop
98
+ new_profile_id = key if profile_id_key.join("-") == profile_id
99
+ end
100
+ end
101
+ dep_entry = new_profile_id ? dependencies.list[new_profile_id] : dependencies.list[profile_id]
89
102
 
90
103
  if dep_entry.nil?
91
104
  raise <<~EOF
data/lib/inspec/errors.rb CHANGED
@@ -22,4 +22,6 @@ module Inspec
22
22
  attr_accessor :gem_name
23
23
  attr_accessor :version
24
24
  end
25
+
26
+ class InvalidProfileSignature < Error; end
25
27
  end
@@ -8,5 +8,7 @@ module Inspec
8
8
  class ResourceFailed < StandardError; end
9
9
  class ResourceSkipped < StandardError; end
10
10
  class SecretsBackendNotFound < ArgumentError; end
11
+ class ProfileValidationKeyNotFound < ArgumentError; end
12
+ class ProfileSigningKeyNotFound < ArgumentError; end
11
13
  end
12
14
  end
@@ -262,7 +262,7 @@ module Inspec::Fetcher
262
262
 
263
263
  open(target, opts)
264
264
 
265
- rescue SocketError, Errno::ECONNREFUSED, OpenURI::HTTPError => e
265
+ rescue SocketError, Net::OpenTimeout, Errno::ECONNREFUSED, OpenURI::HTTPError => e
266
266
  raise Inspec::FetcherFailure, "Profile URL dependency #{target} could not be fetched: #{e.message}"
267
267
  end
268
268
 
@@ -2,6 +2,7 @@ require "rubygems/package" unless defined?(Gem::Package)
2
2
  require "pathname" unless defined?(Pathname)
3
3
  require "zlib" unless defined?(Zlib)
4
4
  require "zip" unless defined?(Zip)
5
+ require "inspec/iaf_file"
5
6
 
6
7
  module Inspec
7
8
  class FileProvider
@@ -14,6 +15,13 @@ module Inspec
14
15
  TarProvider.new(path)
15
16
  elsif File.exist?(path) && path.end_with?(".zip")
16
17
  ZipProvider.new(path)
18
+ elsif File.exist?(path) && path.end_with?(".iaf")
19
+ iaf_file = IafFile.new(path)
20
+ if iaf_file.valid?
21
+ IafProvider.new(path)
22
+ else
23
+ raise Inspec::InvalidProfileSignature, "Profile signature is invalid."
24
+ end
17
25
  elsif File.exist?(path)
18
26
  DirProvider.new(path)
19
27
  else
@@ -216,6 +224,34 @@ module Inspec
216
224
  end
217
225
  end # class TarProvider
218
226
 
227
+ class IafProvider < TarProvider
228
+ attr_reader :files
229
+
230
+ def initialize(path)
231
+ f = File.open(path, "rb")
232
+ version = f.readline.strip!
233
+ if version == "INSPEC-PROFILE-1"
234
+ while f.readline != "\n" do end
235
+ content = f.read
236
+ f.close
237
+ elsif version == "INSPEC-PROFILE-2"
238
+ f.readline.strip!
239
+ content = f.read
240
+ f.close
241
+ content = content.slice(490, content.length).lstrip
242
+ else
243
+ raise Inspec::InvalidProfileSignature, "Unrecognized IAF version."
244
+ end
245
+
246
+ tmpfile = nil
247
+ Dir.mktmpdir do |workdir|
248
+ tmpfile = Pathname.new(workdir).join("temp_profile.tar.gz")
249
+ File.open(tmpfile, "wb") { |fl| fl.write(content) }
250
+ super(tmpfile)
251
+ end
252
+ end
253
+ end # class IafProvider
254
+
219
255
  class RelativeFileProvider
220
256
  BLACKLIST_FILES = [
221
257
  "/pax_global_header",
@@ -0,0 +1,127 @@
1
+ require "base64" unless defined?(Base64)
2
+ require "openssl" unless defined?(OpenSSL)
3
+ require "set" unless defined?(Set)
4
+ require "uri" unless defined?(URI)
5
+
6
+ module Inspec
7
+ class IafFile
8
+ KEY_ALG = OpenSSL::PKey::RSA
9
+ INSPEC_PROFILE_VERSION_1 = "INSPEC-PROFILE-1".freeze
10
+ INSPEC_PROFILE_VERSION_2 = "INSPEC-PROFILE-2".freeze
11
+
12
+ ARTIFACT_DIGEST = OpenSSL::Digest::SHA512
13
+ ARTIFACT_DIGEST_NAME = "SHA512".freeze
14
+
15
+ VALID_PROFILE_VERSIONS = Set.new [INSPEC_PROFILE_VERSION_1, INSPEC_PROFILE_VERSION_2]
16
+ VALID_PROFILE_DIGESTS = Set.new [ARTIFACT_DIGEST_NAME]
17
+
18
+ def self.find_validation_key(keyname)
19
+ [
20
+ ".",
21
+ File.join(Inspec.config_dir, "keys"),
22
+ File.join(Inspec.src_root, "etc", "keys"),
23
+ ].each do |path|
24
+ filename = File.join(path, "#{keyname}.pem.pub")
25
+ return filename if File.exist?(filename)
26
+ rescue ArgumentError => e
27
+ puts e
28
+ raise Inspec::Exceptions::ProfileValidationKeyNotFound.new("Validation key #{keyname} not found")
29
+ end
30
+
31
+ # Retry if we can fetch it from github
32
+ return find_validation_key(keyname) if fetch_validation_key_from_github(keyname)
33
+
34
+ raise Inspec::Exceptions::ProfileValidationKeyNotFound.new("Validation key #{keyname} not found")
35
+ end
36
+
37
+ def self.find_signing_key(keyname)
38
+ [".", File.join(Inspec.config_dir, "keys")].each do |path|
39
+ filename = File.join(path, "#{keyname}.pem.key")
40
+ return filename if File.exist?(filename)
41
+ end
42
+ raise Inspec::Exceptions::ProfileSigningKeyNotFound.new("Signing key #{keyname} not found")
43
+ end
44
+
45
+ def self.fetch_validation_key_from_github(keyname)
46
+ URI.open("https://raw.githubusercontent.com/inspec/inspec/main/etc/keys/#{keyname}.pem.pub") do |r|
47
+ puts "Fetching validation key '#{keyname}' from github"
48
+ dir = File.join(Inspec.config_dir, "keys")
49
+ FileUtils.mkdir_p dir
50
+ key_file = File.join(dir, "#{keyname}.pem.pub")
51
+ File.open(key_file, "w") do |f|
52
+ r.each_line do |line|
53
+ f.puts line
54
+ end
55
+ end
56
+ end
57
+ true
58
+ rescue OpenURI::HTTPError
59
+ false
60
+ end
61
+
62
+ attr_reader :key_name, :version
63
+
64
+ def initialize(path)
65
+ @path = path
66
+ @key_name = nil
67
+ end
68
+
69
+ def valid?
70
+ header = []
71
+ valid = true
72
+ f = File.open(@path, "rb")
73
+ @version = f.readline.strip!
74
+ if version == INSPEC_PROFILE_VERSION_1
75
+ header << version
76
+ header << f.readline.strip!
77
+ header << f.readline.strip!
78
+
79
+ file_sig = ""
80
+ # the signature is multi-line
81
+ while (line = f.readline) != "\n"
82
+ file_sig += line
83
+ end
84
+ header << file_sig.strip!
85
+ f.close
86
+
87
+ f = File.open(@path, "rb")
88
+ while f.readline != "\n" do end
89
+ content = f.read
90
+ f.close
91
+ elsif version == INSPEC_PROFILE_VERSION_2
92
+ header << version
93
+ header << f.readline.strip!
94
+ content = f.read
95
+ f.close
96
+
97
+ header_content = content.unpack("h*").pack("H*")
98
+ header << header_content.slice(0, 100).rstrip
99
+ header << header_content.slice(100, 20).rstrip
100
+ header << header_content.slice(120, 370).rstrip + "\n" # \n at the end is require in this field
101
+ content = content.slice(490, content.length).lstrip
102
+ else
103
+ valid = false
104
+ end
105
+
106
+ @key_name = header[2]
107
+ validation_key_path = Inspec::IafFile.find_validation_key(@key_name)
108
+
109
+ unless valid_header?(header)
110
+ valid = false
111
+ end
112
+
113
+ verification_key = KEY_ALG.new File.read validation_key_path
114
+ signature = Base64.decode64(header[4])
115
+ digest = ARTIFACT_DIGEST.new
116
+ unless verification_key.verify digest, signature, content
117
+ valid = false
118
+ end
119
+
120
+ valid
121
+ end
122
+
123
+ def valid_header?(header)
124
+ VALID_PROFILE_VERSIONS.member?(header[0]) && VALID_PROFILE_DIGESTS.member?(header[3])
125
+ end
126
+ end
127
+ end
@@ -350,22 +350,24 @@ module Inspec
350
350
  def load_libraries
351
351
  return @runner_context if @libraries_loaded
352
352
 
353
- locked_dependencies.dep_list.each_with_index do |(_name, dep), i|
353
+ locked_dependencies.dep_list.each_with_index do |(_name, dep), index|
354
354
  d = dep.profile
355
355
  # this will force a dependent profile load so we are only going to add
356
356
  # this metadata if the parent profile is supported.
357
357
  if @supports_platform && !d.supports_platform?
358
358
  # since ruby 1.9 hashes are ordered so we can just use index values here
359
359
  # TODO: NO! this is a violation of encapsulation to an extreme
360
- metadata.dependencies[i][:status] = "skipped"
361
- msg = "Skipping profile: '#{d.name}' on unsupported platform: '#{d.backend.platform.name}/#{d.backend.platform.release}'."
362
- metadata.dependencies[i][:status_message] = msg
363
- metadata.dependencies[i][:skip_message] = msg # Repeat as skip_message for backward compatibility
360
+ if metadata.dependencies[index]
361
+ metadata.dependencies[index][:status] = "skipped"
362
+ msg = "Skipping profile: '#{d.name}' on unsupported platform: '#{d.backend.platform.name}/#{d.backend.platform.release}'."
363
+ metadata.dependencies[index][:status_message] = msg
364
+ metadata.dependencies[index][:skip_message] = msg # Repeat as skip_message for backward compatibility
365
+ end
364
366
  next
365
- elsif metadata.dependencies[i]
367
+ elsif metadata.dependencies[index]
366
368
  # Currently wrapper profiles will load all dependencies, and then we
367
369
  # load them again when we dive down. This needs to be re-done.
368
- metadata.dependencies[i][:status] = "loaded"
370
+ metadata.dependencies[index][:status] = "loaded"
369
371
  end
370
372
 
371
373
  # rubocop:disable Layout/ExtraSpacing
@@ -746,6 +748,14 @@ module Inspec
746
748
  @source_reader.target.files
747
749
  end
748
750
 
751
+ def readme
752
+ @source_reader.readme&.values&.first
753
+ end
754
+
755
+ def metadata_src
756
+ @source_reader.metadata_src
757
+ end
758
+
749
759
  #
750
760
  # TODO(ssd): Relative path handling really needs to be carefully
751
761
  # thought through, especially with respect to relative paths in
@@ -48,6 +48,10 @@ module Inspec::Resources
48
48
 
49
49
  filter.install_filter_methods_on_resource(self, :params)
50
50
 
51
+ def resource_id
52
+ @conf_path || "aide_conf"
53
+ end
54
+
51
55
  def to_s
52
56
  "AIDE Config"
53
57
  end
@@ -40,6 +40,10 @@ module Inspec::Resources
40
40
  end
41
41
  end
42
42
 
43
+ def resource_id
44
+ @conf_path || "apache"
45
+ end
46
+
43
47
  def to_s
44
48
  "Apache Environment"
45
49
  end
@@ -124,6 +124,10 @@ module Inspec::Resources
124
124
  @params["ServerRoot"] || @params["serverroot"]
125
125
  end
126
126
 
127
+ def resource_id
128
+ @conf_path || "apache_conf"
129
+ end
130
+
127
131
  def to_s
128
132
  "Apache Config #{conf_path}"
129
133
  end
@@ -39,10 +39,11 @@ module Inspec::Resources
39
39
  EXAMPLE
40
40
 
41
41
  def initialize(ppa_name)
42
+ @ppa_name = ppa_name
42
43
  @deb_url = nil
43
44
  # check if the os is ubuntu or debian
44
45
  if inspec.os.debian?
45
- @deb_url = determine_ppa_url(ppa_name)
46
+ @deb_url = determine_ppa_url(@ppa_name)
46
47
  else
47
48
  # this resource is only supported on ubuntu and debian
48
49
  skip_resource "The `apt` resource is not supported on your OS yet."
@@ -61,6 +62,10 @@ module Inspec::Resources
61
62
  actives.size == 1 && actives[0] = true
62
63
  end
63
64
 
65
+ def resource_id
66
+ @deb_url || @ppa_name || "apt repository"
67
+ end
68
+
64
69
  def to_s
65
70
  "Apt Repository #{@deb_url}"
66
71
  end
@@ -57,6 +57,11 @@ module Inspec::Resources
57
57
  values
58
58
  end
59
59
 
60
+ # Since this resource does not have any unique identifier for resource, sending the Auditpol command as UUID.
61
+ def resource_id
62
+ "audit_policy"
63
+ end
64
+
60
65
  def to_s
61
66
  "Audit Policy"
62
67
  end
@@ -27,6 +27,10 @@ module Inspec::Resources
27
27
  read_params[name.to_s]
28
28
  end
29
29
 
30
+ def resource_id
31
+ @conf_path || "auditd_conf"
32
+ end
33
+
30
34
  def to_s
31
35
  "Audit Daemon Config"
32
36
  end
@@ -28,6 +28,10 @@ module Inspec::Resources
28
28
  super(CommandWrapper.wrap(command, options))
29
29
  end
30
30
 
31
+ def resource_id
32
+ @raw_command || "bash"
33
+ end
34
+
31
35
  def to_s
32
36
  "Bash command #{@raw_command}"
33
37
  end
@@ -63,6 +63,10 @@ module Inspec::Resources
63
63
  params["Bonding Mode"].first
64
64
  end
65
65
 
66
+ def resource_id
67
+ @path || "bond"
68
+ end
69
+
66
70
  def to_s
67
71
  "Bond #{@bond}"
68
72
  end
@@ -45,6 +45,10 @@ module Inspec::Resources
45
45
  bridge_info.nil? ? nil : bridge_info[:interfaces]
46
46
  end
47
47
 
48
+ def resource_id
49
+ @bridge_name || "bridge"
50
+ end
51
+
48
52
  def to_s
49
53
  "Bridge #{@bridge_name}"
50
54
  end
@@ -31,6 +31,11 @@ module Inspec::Resources
31
31
  super(@conf_path)
32
32
  end
33
33
 
34
+ # if system unables to determine the cassandra conf path the @conf_path can be nil so in that case sending "" string as resource_id
35
+ def resource_id
36
+ @conf_path || "cassandradb_conf"
37
+ end
38
+
34
39
  private
35
40
 
36
41
  def parse(content)
@@ -1,10 +1,11 @@
1
1
  module Inspec::Resources
2
2
  class Lines
3
- attr_reader :output
3
+ attr_reader :output, :exit_status
4
4
 
5
- def initialize(raw, desc)
5
+ def initialize(raw, desc, exit_status)
6
6
  @output = raw
7
7
  @desc = desc
8
+ @exit_status = exit_status
8
9
  end
9
10
 
10
11
  def to_s
@@ -40,10 +41,14 @@ module Inspec::Resources
40
41
  if cmd.exit_status != 0 || out =~ /Unable to connect to any servers/ || out.downcase =~ /^error:.*/
41
42
  raise Inspec::Exceptions::ResourceFailed, "Cassandra query with errors: #{out}"
42
43
  else
43
- Lines.new(cmd.stdout.strip, "Cassandra query: #{q}")
44
+ Lines.new(cmd.stdout.strip, "Cassandra query: #{q}", cmd.exit_status)
44
45
  end
45
46
  end
46
47
 
48
+ def resource_id
49
+ "cassandradb_session:User:#{@user}:Host:#{host}"
50
+ end
51
+
47
52
  def to_s
48
53
  "Cassandra DB Session"
49
54
  end
@@ -45,6 +45,10 @@ module Inspec::Resources
45
45
  end
46
46
  end
47
47
 
48
+ def resource_id
49
+ @package_name || "chocolatey_package"
50
+ end
51
+
48
52
  def to_s
49
53
  "Chocolatey package #{package_name}"
50
54
  end