inspec-core 4.18.51 → 4.18.85

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +61 -0
  3. data/README.md +3 -3
  4. data/inspec-core.gemspec +51 -0
  5. data/lib/bundles/inspec-supermarket/cli.rb +1 -0
  6. data/lib/inspec/backend.rb +49 -47
  7. data/lib/inspec/base_cli.rb +2 -2
  8. data/lib/inspec/cached_fetcher.rb +4 -0
  9. data/lib/inspec/cli.rb +5 -0
  10. data/lib/inspec/config.rb +1 -1
  11. data/lib/inspec/control_eval_context.rb +131 -199
  12. data/lib/inspec/dependencies/requirement.rb +1 -1
  13. data/lib/inspec/dependencies/resolver.rb +46 -0
  14. data/lib/inspec/dsl_shared.rb +25 -3
  15. data/lib/inspec/fetcher.rb +0 -3
  16. data/lib/inspec/fetcher/git.rb +4 -0
  17. data/lib/inspec/fetcher/url.rb +1 -2
  18. data/lib/inspec/file_provider.rb +4 -2
  19. data/lib/inspec/library_eval_context.rb +37 -37
  20. data/lib/inspec/plugin/v1/plugin_types/fetcher.rb +27 -0
  21. data/lib/inspec/plugin/v1/plugins.rb +0 -1
  22. data/lib/inspec/profile.rb +8 -6
  23. data/lib/inspec/profile_context.rb +74 -9
  24. data/lib/inspec/profile_vendor.rb +48 -3
  25. data/lib/inspec/resource.rb +192 -41
  26. data/lib/inspec/resources/aide_conf.rb +1 -1
  27. data/lib/inspec/resources/apache_conf.rb +15 -31
  28. data/lib/inspec/resources/command.rb +1 -1
  29. data/lib/inspec/resources/crontab.rb +56 -56
  30. data/lib/inspec/resources/etc_fstab.rb +1 -1
  31. data/lib/inspec/resources/etc_group.rb +1 -1
  32. data/lib/inspec/resources/etc_hosts.rb +2 -3
  33. data/lib/inspec/resources/etc_hosts_allow_deny.rb +1 -1
  34. data/lib/inspec/resources/file.rb +2 -2
  35. data/lib/inspec/resources/filesystem.rb +4 -4
  36. data/lib/inspec/resources/groups.rb +16 -2
  37. data/lib/inspec/resources/iis_app.rb +1 -1
  38. data/lib/inspec/resources/ini.rb +1 -2
  39. data/lib/inspec/resources/mount.rb +2 -2
  40. data/lib/inspec/resources/oracledb_session.rb +1 -1
  41. data/lib/inspec/resources/package.rb +22 -0
  42. data/lib/inspec/resources/passwd.rb +1 -1
  43. data/lib/inspec/resources/platform.rb +36 -36
  44. data/lib/inspec/resources/port.rb +1 -1
  45. data/lib/inspec/resources/postfix_conf.rb +1 -1
  46. data/lib/inspec/resources/service.rb +23 -15
  47. data/lib/inspec/resources/users.rb +3 -3
  48. data/lib/inspec/resources/virtualization.rb +15 -11
  49. data/lib/inspec/resources/x509_certificate.rb +18 -4
  50. data/lib/inspec/resources/xinetd_conf.rb +1 -1
  51. data/lib/inspec/resources/xml.rb +1 -2
  52. data/lib/inspec/rspec_extensions.rb +12 -0
  53. data/lib/inspec/rule.rb +63 -22
  54. data/lib/inspec/utils/filter.rb +2 -0
  55. data/lib/inspec/utils/parser.rb +244 -240
  56. data/lib/inspec/utils/simpleconfig.rb +1 -1
  57. data/lib/inspec/version.rb +1 -1
  58. data/lib/matchers/matchers.rb +11 -10
  59. data/lib/plugins/inspec-compliance/lib/inspec-compliance.rb +3 -0
  60. data/lib/plugins/inspec-habitat/lib/inspec-habitat/profile.rb +2 -2
  61. data/lib/plugins/inspec-init/templates/profiles/aws/README.md +192 -0
  62. data/lib/plugins/inspec-init/templates/profiles/aws/attributes.yml +2 -0
  63. data/lib/plugins/inspec-init/templates/profiles/aws/controls/example.rb +39 -0
  64. data/lib/plugins/inspec-init/templates/profiles/aws/inspec.yml +22 -0
  65. data/lib/plugins/inspec-init/templates/profiles/azure/README.md +56 -0
  66. data/lib/plugins/inspec-init/templates/profiles/azure/controls/example.rb +14 -0
  67. data/lib/plugins/inspec-init/templates/profiles/azure/inspec.yml +14 -0
  68. data/lib/plugins/inspec-init/templates/profiles/gcp/README.md +66 -0
  69. data/lib/plugins/inspec-init/templates/profiles/gcp/attributes.yml +2 -0
  70. data/lib/plugins/inspec-init/templates/profiles/gcp/controls/example.rb +27 -0
  71. data/lib/plugins/inspec-init/templates/profiles/gcp/inspec.yml +19 -0
  72. data/lib/source_readers/inspec.rb +1 -1
  73. metadata +87 -74
  74. data/lib/inspec/plugin/v1/plugin_types/resource.rb +0 -176
  75. data/lib/plugins/inspec-init/templates/profiles/os/libraries/.gitkeep +0 -0
@@ -67,7 +67,7 @@ module Inspec::Resources
67
67
  res = if inspec.platform.name == "alpine"
68
68
  inspec.backend.run_command("which \"#{@command}\"")
69
69
  else
70
- inspec.backend.run_command("bash -c 'type \"#{@command}\"'")
70
+ inspec.backend.run_command("sh -c 'type \"#{@command}\"'")
71
71
  end
72
72
  elsif inspec.os.windows?
73
73
  res = inspec.backend.run_command("Get-Command \"#{@command}\"")
@@ -32,7 +32,7 @@ module Inspec::Resources
32
32
 
33
33
  attr_reader :params
34
34
 
35
- include CommentParser
35
+ include Inspec::Utils::CommentParser
36
36
 
37
37
  def initialize(opts = nil)
38
38
  if opts.respond_to?(:fetch)
@@ -67,6 +67,7 @@ module Inspec::Resources
67
67
  end
68
68
 
69
69
  def crontab_cmd
70
+ # TODO: the -u scenario needs to be able to do sudo
70
71
  @user.nil? ? "crontab -l" : "crontab -l -u #{@user}"
71
72
  end
72
73
 
@@ -108,66 +109,65 @@ module Inspec::Resources
108
109
  !@user.nil?
109
110
  end
110
111
 
111
- def parse_system_crontab(data)
112
+ # rubocop:disable Layout/AlignHash
113
+
114
+ DEFAULT_TIMES = {
115
+ "minute" => "*",
116
+ "hour" => "*",
117
+ "day" => "*",
118
+ "month" => "*",
119
+ "weekday" => "*",
120
+ }.freeze
121
+
122
+ SYSTEM_COLUMNS = %w{minute hour day month weekday user command}.freeze
123
+ USER_COLUMNS = %w{minute hour day month weekday command}.freeze
124
+
125
+ HOURLY = { "minute" => "0" }.freeze
126
+ DAILY = HOURLY .merge("hour" => "0").freeze
127
+ WEEKLY = HOURLY .merge("weekday" => "0").freeze
128
+ MONTHLY = DAILY .merge("day" => "1").freeze
129
+ YEARLY = MONTHLY .merge("month" => "1").freeze
130
+ REBOOT = {
131
+ "minute" => "-1",
132
+ "hour" => "-1",
133
+ "day" => "-1",
134
+ "month" => "-1",
135
+ "weekday" => "-1",
136
+ }.freeze
137
+
138
+ def merge_crontab(data, default)
112
139
  case data
113
- when /@hourly .*/
114
- elements = data.split(/\s+/, 3)
115
- { "minute" => "0", "hour" => "*", "day" => "*", "month" => "*", "weekday" => "*", "user" => elements.at(1), "command" => elements.at(2) }
116
- when /@(midnight|daily) .*/
117
- elements = data.split(/\s+/, 3)
118
- { "minute" => "0", "hour" => "0", "day" => "*", "month" => "*", "weekday" => "*", "user" => elements.at(1), "command" => elements.at(2) }
119
- when /@weekly .*/
120
- elements = data.split(/\s+/, 3)
121
- { "minute" => "0", "hour" => "0", "day" => "*", "month" => "*", "weekday" => "0", "user" => elements.at(1), "command" => elements.at(2) }
122
- when /@monthly ./
123
- elements = data.split(/\s+/, 3)
124
- { "minute" => "0", "hour" => "0", "day" => "1", "month" => "*", "weekday" => "*", "user" => elements.at(1), "command" => elements.at(2) }
125
- when /@(annually|yearly) .*/
126
- elements = data.split(/\s+/, 3)
127
- { "minute" => "0", "hour" => "0", "day" => "1", "month" => "1", "weekday" => "*", "user" => elements.at(1), "command" => elements.at(2) }
128
- when /@reboot .*/
129
- elements = data.split(/\s+/, 3)
130
- { "minute" => "-1", "hour" => "-1", "day" => "-1", "month" => "-1", "weekday" => "-1", "user" => elements.at(1), "command" => elements.at(2) }
131
- else
132
- elements = data.split(/\s+/, 7)
133
- {
134
- "minute" => elements.at(0),
135
- "hour" => elements.at(1),
136
- "day" => elements.at(2),
137
- "month" => elements.at(3),
138
- "weekday" => elements.at(4),
139
- "user" => elements.at(5),
140
- "command" => elements.at(6),
141
- }
140
+ when /@hourly /
141
+ default.merge(HOURLY)
142
+ when /@(midnight|daily) /
143
+ default.merge(DAILY)
144
+ when /@weekly /
145
+ default.merge(WEEKLY)
146
+ when /@monthly /
147
+ default.merge(MONTHLY)
148
+ when /@(annually|yearly) /
149
+ default.merge(YEARLY)
150
+ when /@reboot /
151
+ default.merge(REBOOT)
142
152
  end
143
153
  end
144
154
 
155
+ def parse_system_crontab(data)
156
+ _, user, cmd = data.split(/\s+/, 3)
157
+ default = DEFAULT_TIMES.merge("user" => user,
158
+ "command" => cmd)
159
+
160
+ merge_crontab(data, default) ||
161
+ SYSTEM_COLUMNS.zip(data.split(/\s+/, 7)).to_h
162
+ end
163
+
145
164
  def parse_user_crontab(data)
146
- case data
147
- when /@hourly .*/
148
- { "minute" => "0", "hour" => "*", "day" => "*", "month" => "*", "weekday" => "*", "user" => @user, "command" => data.split(/\s+/, 2).at(1) }
149
- when /@(midnight|daily) .*/
150
- { "minute" => "0", "hour" => "0", "day" => "*", "month" => "*", "weekday" => "*", "user" => @user, "command" => data.split(/\s+/, 2).at(1) }
151
- when /@weekly .*/
152
- { "minute" => "0", "hour" => "0", "day" => "*", "month" => "*", "weekday" => "0", "user" => @user, "command" => data.split(/\s+/, 2).at(1) }
153
- when /@monthly ./
154
- { "minute" => "0", "hour" => "0", "day" => "1", "month" => "*", "weekday" => "*", "user" => @user, "command" => data.split(/\s+/, 2).at(1) }
155
- when /@(annually|yearly) .*/
156
- { "minute" => "0", "hour" => "0", "day" => "1", "month" => "1", "weekday" => "*", "user" => @user, "command" => data.split(/\s+/, 2).at(1) }
157
- when /@reboot .*/
158
- { "minute" => "-1", "hour" => "-1", "day" => "-1", "month" => "-1", "weekday" => "-1", "user" => @user, "command" => data.split(/\s+/, 2).at(1) }
159
- else
160
- elements = data.split(/\s+/, 6)
161
- {
162
- "minute" => elements.at(0),
163
- "hour" => elements.at(1),
164
- "day" => elements.at(2),
165
- "month" => elements.at(3),
166
- "weekday" => elements.at(4),
167
- "user" => @user,
168
- "command" => elements.at(5),
169
- }
170
- end
165
+ _, cmd = data.split(/\s+/, 2)
166
+ default = DEFAULT_TIMES.merge("user" => @user,
167
+ "command" => cmd)
168
+
169
+ merge_crontab(data, default) ||
170
+ USER_COLUMNS.zip(data.split(/\s+/, 6)).to_h.merge("user" => @user)
171
171
  end
172
172
  end
173
173
  end
@@ -25,7 +25,7 @@ module Inspec::Resources
25
25
 
26
26
  attr_reader :params
27
27
 
28
- include CommentParser
28
+ include Inspec::Utils::CommentParser
29
29
  include FileReader
30
30
 
31
31
  def initialize(fstab_path = nil)
@@ -24,7 +24,7 @@ require "inspec/utils/file_reader"
24
24
  module Inspec::Resources
25
25
  class EtcGroup < Inspec.resource(1)
26
26
  include Converter
27
- include CommentParser
27
+ include Inspec::Utils::CommentParser
28
28
 
29
29
  name "etc_group"
30
30
  supports platform: "unix"
@@ -4,8 +4,7 @@ require "inspec/utils/file_reader"
4
4
  module Inspec::Resources
5
5
  class EtcHosts < Inspec.resource(1)
6
6
  name "etc_hosts"
7
- supports platform: "linux"
8
- supports platform: "bsd"
7
+ supports platform: "unix"
9
8
  supports platform: "windows"
10
9
  desc 'Use the etc_hosts InSpec audit resource to find an
11
10
  ip_address and its associated hosts'
@@ -19,7 +18,7 @@ module Inspec::Resources
19
18
 
20
19
  attr_reader :params
21
20
 
22
- include CommentParser
21
+ include Inspec::Utils::CommentParser
23
22
  include FileReader
24
23
 
25
24
  DEFAULT_UNIX_PATH = "/etc/hosts".freeze
@@ -16,7 +16,7 @@ module Inspec::Resources
16
16
 
17
17
  attr_reader :params
18
18
 
19
- include CommentParser
19
+ include Inspec::Utils::CommentParser
20
20
  include FileReader
21
21
 
22
22
  def initialize(hosts_allow_path = nil)
@@ -17,12 +17,12 @@ module Inspec::Resources
17
17
  # TODO: rename file_resource.rb
18
18
  class FileResource < Inspec.resource(1)
19
19
  include FilePermissionsSelector
20
- include LinuxMountParser
20
+ include Inspec::Utils::LinuxMountParser
21
21
 
22
22
  name "file"
23
23
  supports platform: "unix"
24
24
  supports platform: "windows"
25
- desc "Use the file InSpec audit resource to test all system file types, including files, directories, symbolic links, named pipes, sockets, character devices, block devices, and doors."
25
+ desc "Use the file InSpec audit resource to test all system file types, including files, directories, symbolic links, etc."
26
26
  example <<~EXAMPLE
27
27
  describe file('path') do
28
28
  it { should exist }
@@ -3,7 +3,7 @@ require "inspec/resources/command"
3
3
  module Inspec::Resources
4
4
  class FileSystemResource < Inspec.resource(1)
5
5
  name "filesystem"
6
- supports platform: "linux"
6
+ supports platform: "unix"
7
7
  supports platform: "windows"
8
8
  desc "Use the filesystem InSpec resource to test file system"
9
9
  example <<~EXAMPLE
@@ -29,8 +29,8 @@ module Inspec::Resources
29
29
  @fsman = nil
30
30
 
31
31
  os = inspec.os
32
- if os.linux?
33
- @fsman = LinuxFileSystemResource.new(inspec)
32
+ if os.unix?
33
+ @fsman = UnixFileSystemResource.new(inspec)
34
34
  elsif os.windows?
35
35
  @fsman = WindowsFileSystemResource.new(inspec)
36
36
  else
@@ -93,7 +93,7 @@ module Inspec::Resources
93
93
  end
94
94
  end
95
95
 
96
- class LinuxFileSystemResource < FsManagement
96
+ class UnixFileSystemResource < FsManagement
97
97
  def info(partition)
98
98
  cmd = inspec.command("df #{partition} -PT")
99
99
  if cmd.stdout.nil? || cmd.stdout.empty? || cmd.exit_status != 0
@@ -173,6 +173,8 @@ module Inspec::Resources
173
173
  end
174
174
 
175
175
  def groups
176
+ # https://apple.stackexchange.com/a/130815
177
+
176
178
  group_by_id = runmap("dscl . -list /Groups PrimaryGroupID") { |l| name, id = l.split; [id.to_i, name] }
177
179
  userss = runmap("dscl . -list /Users PrimaryGroupID") { |l| name, id = l.split; [name, id.to_i] }
178
180
  membership = runmap("dscl . -list /Groups GroupMembership") { |l| key, *vs = l.split; [key, vs] }
@@ -196,9 +198,21 @@ module Inspec::Resources
196
198
  users = g.delete("users") || ""
197
199
  users = users.split
198
200
  users += Array(users_by_group[g["name"]])
199
- g["members"] = users
200
- g["members"].sort.join ","
201
+ g["members"] = users.sort
201
202
  end
203
+
204
+ groups # de-dupe/merge by gid
205
+ .group_by { |g| g["gid"] }
206
+ .values
207
+ .map { |subgroups|
208
+ g = subgroups.first
209
+
210
+ if subgroups.size != 1
211
+ g["members"] = subgroups.map { |h| h["members"] }.flatten.uniq
212
+ end
213
+
214
+ g
215
+ }
202
216
  end
203
217
  end
204
218
 
@@ -10,7 +10,7 @@ module Inspec::Resources
10
10
  describe iis_app('/myapp', 'Default Web Site') do
11
11
  it { should exist }
12
12
  it { should have_application_pool('MyAppPool') }
13
- it { should have_protocols('http') }
13
+ it { should have_protocol('http') }
14
14
  it { should have_site_name('Default Web Site') }
15
15
  it { should have_physical_path('C:\\inetpub\\wwwroot\\myapp') }
16
16
  it { should have_path('\\My Application') }
@@ -4,8 +4,7 @@ require "inspec/utils/simpleconfig"
4
4
  module Inspec::Resources
5
5
  class IniConfig < JsonConfig
6
6
  name "ini"
7
- supports platform: "unix"
8
- supports platform: "windows"
7
+ supports platform: "os"
9
8
  desc "Use the ini InSpec audit resource to test data in a INI file."
10
9
  example <<~EXAMPLE
11
10
  descibe ini do
@@ -79,10 +79,10 @@ module Inspec::Resources
79
79
  end
80
80
 
81
81
  class LinuxMounts < MountsInfo
82
- include LinuxMountParser
82
+ include Inspec::Utils::LinuxMountParser
83
83
  end
84
84
 
85
85
  class BsdMounts < MountsInfo
86
- include BsdMountParser
86
+ include Inspec::Utils::BsdMountParser
87
87
  end
88
88
  end
@@ -86,7 +86,7 @@ module Inspec::Resources
86
86
  elsif @su_user.nil?
87
87
  %{#{sql_prefix}#{bin} "#{user}"/"#{password}"@#{host}:#{port}/#{@service} as #{@db_role}#{sql_postfix}}
88
88
  else
89
- %{su - #{@su_user} -c "env ORACLE_SID=#{@service} #{bin} / as #{@db_role}#{sql_postfix}}
89
+ %{su - #{@su_user} -c "env ORACLE_SID=#{@service} #{bin} / as #{@db_role}#{sql_postfix}"}
90
90
  end
91
91
  end
92
92
 
@@ -46,6 +46,8 @@ module Inspec::Resources
46
46
  @pkgman = HpuxPkg.new(inspec)
47
47
  elsif ["alpine"].include?(os[:name])
48
48
  @pkgman = AlpinePkg.new(inspec)
49
+ elsif ["freebsd"].include?(os[:name])
50
+ @pkgman = FreebsdPkg.new(inspec)
49
51
  else
50
52
  raise Inspec::Exceptions::ResourceSkipped, "The `package` resource is not supported on your OS yet."
51
53
  end
@@ -274,6 +276,26 @@ module Inspec::Resources
274
276
  end
275
277
  end
276
278
 
279
+ class FreebsdPkg < PkgManagement
280
+ def info(package_name)
281
+ cmd = inspec.command("pkg info #{package_name}")
282
+ return {} if cmd.exit_status.to_i != 0
283
+
284
+ params = SimpleConfig.new(
285
+ cmd.stdout.chomp,
286
+ assignment_regex: /^\s*([^:]*?)\s*:\s*(.*?)\s*$/,
287
+ multiple_values: false
288
+ ).params
289
+
290
+ {
291
+ name: params["Name"],
292
+ installed: true,
293
+ version: params["Version"],
294
+ type: "pkg",
295
+ }
296
+ end
297
+ end
298
+
277
299
  # Determines the installed packages on Windows using the Windows package registry entries.
278
300
  # @see: http://blogs.technet.com/b/heyscriptingguy/archive/2013/11/15/use-powershell-to-find-installed-software.aspx
279
301
  class WindowsPkg < PkgManagement
@@ -33,7 +33,7 @@ module Inspec::Resources
33
33
  end
34
34
  EXAMPLE
35
35
 
36
- include PasswdParser
36
+ include Inspec::Utils::PasswdParser
37
37
  include FileReader
38
38
 
39
39
  attr_reader :params
@@ -18,11 +18,16 @@ module Inspec::Resources
18
18
  @platform = inspec.backend.platform
19
19
  end
20
20
 
21
- # add helper methods for easy access of properties
22
- %w{family release arch}.each do |property|
23
- define_method(property.to_sym) do
24
- @platform[property]
25
- end
21
+ def family
22
+ @platform.family
23
+ end
24
+
25
+ def release
26
+ @platform.release
27
+ end
28
+
29
+ def arch
30
+ @platform.arch if @platform.respond_to?(:arch)
26
31
  end
27
32
 
28
33
  def families
@@ -51,46 +56,41 @@ module Inspec::Resources
51
56
  end
52
57
 
53
58
  def params
59
+ # rubocop:disable Layout/AlignHash
54
60
  h = {
55
- name: name,
61
+ name: name,
56
62
  families: families,
57
- release: release,
63
+ release: release,
64
+ arch: arch,
58
65
  }
66
+ # rubocop:enable Layout/AlignHash
59
67
 
60
- # Avoid adding Arch for APIs (not applicable)
61
- unless in_family?("api")
62
- h[:arch] = arch
63
- end
68
+ h.delete :arch if in_family?("api") # not applicable if api
64
69
 
65
70
  h
66
71
  end
67
72
 
68
73
  def supported?(supports)
69
- return true if supports.nil? || supports.empty?
70
-
71
- status = true
72
- supports.each do |support|
73
- support.each do |k, v|
74
- status =
75
- case k
76
- when :os_family, :"os-family", :platform_family, :"platform-family" then
77
- in_family?(v)
78
- when :os, :platform then
79
- platform?(v)
80
- when :os_name, :"os-name", :platform_name, :"platform-name" then
81
- name == v
82
- when :release then
83
- check_release(v)
84
- else
85
- false
86
- end
87
-
88
- break if status == false
89
- end
90
- return true if status == true
91
- end
74
+ raise ArgumentError, "`supports` is nil." unless supports
75
+
76
+ supports.any? { |support|
77
+ support.all? { |k, v|
78
+ case normalize(k)
79
+ when :os_family, :platform_family then
80
+ in_family?(v)
81
+ when :os, :platform then
82
+ platform?(v)
83
+ when :os_name, :platform_name then
84
+ name == v
85
+ when :release then
86
+ check_release(v)
87
+ end
88
+ }
89
+ } || supports.empty?
90
+ end
92
91
 
93
- status
92
+ def normalize(key) # TODO: dumb... push this up or remove need
93
+ key.to_s.tr("-", "_").to_sym
94
94
  end
95
95
 
96
96
  def to_s
@@ -103,7 +103,7 @@ module Inspec::Resources
103
103
  # allow wild card matching
104
104
  if value.include?("*")
105
105
  cleaned = Regexp.escape(value).gsub('\*', ".*?")
106
- !(release =~ /#{cleaned}/).nil?
106
+ release =~ /#{cleaned}/
107
107
  else
108
108
  release == value
109
109
  end