inspec-core 5.17.4 → 5.18.14

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.
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