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.
- checksums.yaml +4 -4
- data/Gemfile +61 -0
- data/README.md +3 -3
- data/inspec-core.gemspec +51 -0
- data/lib/bundles/inspec-supermarket/cli.rb +1 -0
- data/lib/inspec/backend.rb +49 -47
- data/lib/inspec/base_cli.rb +2 -2
- data/lib/inspec/cached_fetcher.rb +4 -0
- data/lib/inspec/cli.rb +5 -0
- data/lib/inspec/config.rb +1 -1
- data/lib/inspec/control_eval_context.rb +131 -199
- data/lib/inspec/dependencies/requirement.rb +1 -1
- data/lib/inspec/dependencies/resolver.rb +46 -0
- data/lib/inspec/dsl_shared.rb +25 -3
- data/lib/inspec/fetcher.rb +0 -3
- data/lib/inspec/fetcher/git.rb +4 -0
- data/lib/inspec/fetcher/url.rb +1 -2
- data/lib/inspec/file_provider.rb +4 -2
- data/lib/inspec/library_eval_context.rb +37 -37
- data/lib/inspec/plugin/v1/plugin_types/fetcher.rb +27 -0
- data/lib/inspec/plugin/v1/plugins.rb +0 -1
- data/lib/inspec/profile.rb +8 -6
- data/lib/inspec/profile_context.rb +74 -9
- data/lib/inspec/profile_vendor.rb +48 -3
- data/lib/inspec/resource.rb +192 -41
- data/lib/inspec/resources/aide_conf.rb +1 -1
- data/lib/inspec/resources/apache_conf.rb +15 -31
- data/lib/inspec/resources/command.rb +1 -1
- data/lib/inspec/resources/crontab.rb +56 -56
- data/lib/inspec/resources/etc_fstab.rb +1 -1
- data/lib/inspec/resources/etc_group.rb +1 -1
- data/lib/inspec/resources/etc_hosts.rb +2 -3
- data/lib/inspec/resources/etc_hosts_allow_deny.rb +1 -1
- data/lib/inspec/resources/file.rb +2 -2
- data/lib/inspec/resources/filesystem.rb +4 -4
- data/lib/inspec/resources/groups.rb +16 -2
- data/lib/inspec/resources/iis_app.rb +1 -1
- data/lib/inspec/resources/ini.rb +1 -2
- data/lib/inspec/resources/mount.rb +2 -2
- data/lib/inspec/resources/oracledb_session.rb +1 -1
- data/lib/inspec/resources/package.rb +22 -0
- data/lib/inspec/resources/passwd.rb +1 -1
- data/lib/inspec/resources/platform.rb +36 -36
- data/lib/inspec/resources/port.rb +1 -1
- data/lib/inspec/resources/postfix_conf.rb +1 -1
- data/lib/inspec/resources/service.rb +23 -15
- data/lib/inspec/resources/users.rb +3 -3
- data/lib/inspec/resources/virtualization.rb +15 -11
- data/lib/inspec/resources/x509_certificate.rb +18 -4
- data/lib/inspec/resources/xinetd_conf.rb +1 -1
- data/lib/inspec/resources/xml.rb +1 -2
- data/lib/inspec/rspec_extensions.rb +12 -0
- data/lib/inspec/rule.rb +63 -22
- data/lib/inspec/utils/filter.rb +2 -0
- data/lib/inspec/utils/parser.rb +244 -240
- data/lib/inspec/utils/simpleconfig.rb +1 -1
- data/lib/inspec/version.rb +1 -1
- data/lib/matchers/matchers.rb +11 -10
- data/lib/plugins/inspec-compliance/lib/inspec-compliance.rb +3 -0
- data/lib/plugins/inspec-habitat/lib/inspec-habitat/profile.rb +2 -2
- data/lib/plugins/inspec-init/templates/profiles/aws/README.md +192 -0
- data/lib/plugins/inspec-init/templates/profiles/aws/attributes.yml +2 -0
- data/lib/plugins/inspec-init/templates/profiles/aws/controls/example.rb +39 -0
- data/lib/plugins/inspec-init/templates/profiles/aws/inspec.yml +22 -0
- data/lib/plugins/inspec-init/templates/profiles/azure/README.md +56 -0
- data/lib/plugins/inspec-init/templates/profiles/azure/controls/example.rb +14 -0
- data/lib/plugins/inspec-init/templates/profiles/azure/inspec.yml +14 -0
- data/lib/plugins/inspec-init/templates/profiles/gcp/README.md +66 -0
- data/lib/plugins/inspec-init/templates/profiles/gcp/attributes.yml +2 -0
- data/lib/plugins/inspec-init/templates/profiles/gcp/controls/example.rb +27 -0
- data/lib/plugins/inspec-init/templates/profiles/gcp/inspec.yml +19 -0
- data/lib/source_readers/inspec.rb +1 -1
- metadata +87 -74
- data/lib/inspec/plugin/v1/plugin_types/resource.rb +0 -176
- 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("
|
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
|
-
|
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
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
when /@
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
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
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
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
|
@@ -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: "
|
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
|
@@ -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,
|
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: "
|
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.
|
33
|
-
@fsman =
|
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
|
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
|
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') }
|
data/lib/inspec/resources/ini.rb
CHANGED
@@ -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: "
|
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
|
@@ -18,11 +18,16 @@ module Inspec::Resources
|
|
18
18
|
@platform = inspec.backend.platform
|
19
19
|
end
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
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:
|
61
|
+
name: name,
|
56
62
|
families: families,
|
57
|
-
release:
|
63
|
+
release: release,
|
64
|
+
arch: arch,
|
58
65
|
}
|
66
|
+
# rubocop:enable Layout/AlignHash
|
59
67
|
|
60
|
-
|
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
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
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
|
-
|
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
|
-
|
106
|
+
release =~ /#{cleaned}/
|
107
107
|
else
|
108
108
|
release == value
|
109
109
|
end
|