inspec 2.2.102 → 2.2.112
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -0
- data/CHANGELOG.md +25 -7
- data/Rakefile +8 -2
- data/docs/profiles.md +9 -0
- data/docs/resources/aws_security_group.md.erb +19 -2
- data/docs/resources/gem.md.erb +24 -5
- data/docs/resources/mssql_session.md.erb +8 -0
- data/lib/inspec/plugin/v2/loader.rb +33 -7
- data/lib/inspec/reporters/json_automate.rb +1 -1
- data/lib/inspec/version.rb +1 -1
- data/lib/plugins/README.md +16 -0
- data/lib/plugins/inspec-artifact/lib/inspec-artifact.rb +12 -0
- data/lib/plugins/inspec-artifact/lib/inspec-artifact/base.rb +162 -0
- data/lib/plugins/inspec-artifact/lib/inspec-artifact/cli.rb +114 -0
- data/lib/plugins/inspec-artifact/test/functional/inspec_artifact_test.rb +46 -0
- data/lib/plugins/inspec-habitat/lib/inspec-habitat.rb +11 -0
- data/lib/plugins/inspec-habitat/lib/inspec-habitat/cli.rb +39 -0
- data/lib/plugins/inspec-habitat/lib/inspec-habitat/profile.rb +394 -0
- data/lib/plugins/inspec-habitat/test/unit/profile_test.rb +184 -0
- data/lib/{bundles → plugins}/inspec-init/README.md +0 -0
- data/lib/plugins/inspec-init/lib/inspec-init.rb +12 -0
- data/lib/plugins/inspec-init/lib/inspec-init/cli.rb +28 -0
- data/lib/plugins/inspec-init/lib/inspec-init/renderer.rb +81 -0
- data/lib/{bundles → plugins/inspec-init/lib}/inspec-init/templates/profile/README.md +0 -0
- data/lib/{bundles → plugins/inspec-init/lib}/inspec-init/templates/profile/controls/example.rb +0 -0
- data/lib/{bundles → plugins/inspec-init/lib}/inspec-init/templates/profile/inspec.yml +0 -0
- data/lib/{bundles → plugins/inspec-init/lib}/inspec-init/templates/profile/libraries/.gitkeep +0 -0
- data/lib/plugins/inspec-init/test/functional/inspec_init_test.rb +30 -0
- data/lib/plugins/shared/core_plugin_test_helper.rb +50 -0
- data/lib/resources/aws/aws_security_group.rb +38 -6
- data/lib/resources/gem.rb +7 -1
- data/lib/resources/mssql_session.rb +4 -2
- metadata +21 -17
- data/lib/bundles/inspec-artifact.rb +0 -7
- data/lib/bundles/inspec-artifact/README.md +0 -1
- data/lib/bundles/inspec-artifact/cli.rb +0 -278
- data/lib/bundles/inspec-habitat.rb +0 -12
- data/lib/bundles/inspec-habitat/cli.rb +0 -37
- data/lib/bundles/inspec-habitat/log.rb +0 -10
- data/lib/bundles/inspec-habitat/profile.rb +0 -391
- data/lib/bundles/inspec-init.rb +0 -12
- data/lib/bundles/inspec-init/cli.rb +0 -39
- data/lib/bundles/inspec-init/renderer.rb +0 -79
@@ -0,0 +1,184 @@
|
|
1
|
+
require 'mixlib/log'
|
2
|
+
require 'ostruct'
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'mocha/setup'
|
5
|
+
require_relative '../../lib/inspec-habitat/profile.rb'
|
6
|
+
|
7
|
+
describe InspecPlugins::Habitat::Profile do
|
8
|
+
let(:profile) do
|
9
|
+
OpenStruct.new(
|
10
|
+
name: 'my_profile',
|
11
|
+
version: '1.2.3',
|
12
|
+
files: %w(file1 file2)
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:subject) { InspecPlugins::Habitat::Profile.new('/path/to/profile', { 'log_level' => 'fatal' }) }
|
17
|
+
|
18
|
+
before do
|
19
|
+
Inspec::Log.level(:fatal)
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#verify_profile' do
|
23
|
+
it 'exits if the profile is not valid' do
|
24
|
+
profile = mock
|
25
|
+
profile.stubs(:check).returns(summary: { valid: false })
|
26
|
+
subject.expects(:profile).returns(profile)
|
27
|
+
proc { subject.send(:verify_profile) }.must_raise SystemExit
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'does not exist if the profile is valid' do
|
31
|
+
profile = mock
|
32
|
+
profile.stubs(:check).returns(summary: { valid: true })
|
33
|
+
subject.expects(:profile).returns(profile)
|
34
|
+
subject.send(:verify_profile)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe '#vendor_profile_dependencies' do
|
39
|
+
let(:profile_vendor) do
|
40
|
+
profile_vendor = mock
|
41
|
+
profile_vendor.stubs(:lockfile).returns(lockfile)
|
42
|
+
profile_vendor.stubs(:cache_path).returns(cache_path)
|
43
|
+
profile_vendor
|
44
|
+
end
|
45
|
+
let(:lockfile) { mock }
|
46
|
+
let(:cache_path) { mock }
|
47
|
+
|
48
|
+
before do
|
49
|
+
Inspec::ProfileVendor.expects(:new).returns(profile_vendor)
|
50
|
+
end
|
51
|
+
|
52
|
+
describe 'when lockfile exists and cache dir exists' do
|
53
|
+
it 'does not vendor the dependencies' do
|
54
|
+
lockfile.expects(:exist?).returns(true)
|
55
|
+
cache_path.expects(:exist?).returns(true)
|
56
|
+
profile_vendor.expects(:vendor!).never
|
57
|
+
profile_vendor.expects(:make_readable).never
|
58
|
+
subject.send(:vendor_profile_dependencies)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe 'when the lockfile exists but the cache dir does not' do
|
63
|
+
it 'vendors the dependencies and refreshes the profile object' do
|
64
|
+
lockfile.expects(:exist?).returns(true)
|
65
|
+
cache_path.expects(:exist?).returns(false)
|
66
|
+
profile_vendor.expects(:vendor!)
|
67
|
+
profile_vendor.expects(:make_readable)
|
68
|
+
subject.expects(:create_profile_object)
|
69
|
+
|
70
|
+
subject.send(:vendor_profile_dependencies)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe 'when the lockfile does not exist' do
|
75
|
+
it 'vendors the dependencies and refreshes the profile object' do
|
76
|
+
lockfile.expects(:exist?).returns(false)
|
77
|
+
profile_vendor.expects(:vendor!)
|
78
|
+
profile_vendor.expects(:make_readable)
|
79
|
+
subject.expects(:create_profile_object)
|
80
|
+
|
81
|
+
subject.send(:vendor_profile_dependencies)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe '#validate_habitat_installed' do
|
87
|
+
it 'exits if hab --version fails' do
|
88
|
+
cmd = mock
|
89
|
+
cmd.stubs(:error?).returns(true)
|
90
|
+
cmd.stubs(:run_command)
|
91
|
+
cmd.stubs(:stdout)
|
92
|
+
cmd.stubs(:stderr)
|
93
|
+
Mixlib::ShellOut.expects(:new).with('hab --version').returns(cmd)
|
94
|
+
proc { subject.send(:validate_habitat_installed) }.must_raise SystemExit
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe '#validate_habitat_origin' do
|
99
|
+
it 'does not exit if the origin key exists' do
|
100
|
+
subject.expects(:habitat_origin).returns('12345')
|
101
|
+
subject.send(:validate_habitat_origin)
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'exits if no origin key exists' do
|
105
|
+
subject.expects(:habitat_origin).returns(nil)
|
106
|
+
proc { subject.send(:validate_habitat_origin) }.must_raise SystemExit
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe '#validate_habitat_auth_token' do
|
111
|
+
it 'does not exit if the auth_token exists' do
|
112
|
+
subject.expects(:habitat_auth_token).returns('12345')
|
113
|
+
subject.send(:validate_habitat_auth_token)
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'exits if no auth_token exists' do
|
117
|
+
subject.expects(:habitat_auth_token).returns(nil)
|
118
|
+
proc { subject.send(:validate_habitat_auth_token) }.must_raise SystemExit
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
describe '#build_hart' do
|
123
|
+
before do
|
124
|
+
subject.expects(:work_dir).at_least_once.returns(Dir.tmpdir)
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'exits if the build fails' do
|
128
|
+
subject.expects(:system).returns(false)
|
129
|
+
proc { subject.send(:build_hart) }.must_raise SystemExit
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'exits if more than one hart is created' do
|
133
|
+
subject.expects(:system).returns(true)
|
134
|
+
Dir.expects(:glob).returns(%w(hart1 hart2))
|
135
|
+
proc { subject.send(:build_hart) }.must_raise SystemExit
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'exits if more than no hart is created' do
|
139
|
+
subject.expects(:system).returns(true)
|
140
|
+
Dir.expects(:glob).returns([])
|
141
|
+
proc { subject.send(:build_hart) }.must_raise SystemExit
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'returns the hart filename' do
|
145
|
+
subject.expects(:system).returns(true)
|
146
|
+
Dir.expects(:glob).returns(%w(hart1))
|
147
|
+
subject.send(:build_hart).must_equal('hart1')
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
describe '#upload_hart' do
|
152
|
+
it 'exits if the upload failed' do
|
153
|
+
env = {
|
154
|
+
'TERM' => 'vt100',
|
155
|
+
'HAB_AUTH_TOKEN' => 'my_token',
|
156
|
+
'HAB_NONINTERACTIVE' => 'true',
|
157
|
+
}
|
158
|
+
|
159
|
+
cmd = mock
|
160
|
+
cmd.stubs(:run_command)
|
161
|
+
cmd.stubs(:error?).returns(true)
|
162
|
+
cmd.stubs(:stdout)
|
163
|
+
cmd.stubs(:stderr)
|
164
|
+
|
165
|
+
subject.expects(:habitat_auth_token).returns('my_token')
|
166
|
+
Mixlib::ShellOut.expects(:new).with("hab pkg upload my_hart", env: env).returns(cmd)
|
167
|
+
proc { subject.send(:upload_hart, 'my_hart') }.must_raise SystemExit
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
describe '#habitat_cli_config' do
|
172
|
+
it 'returns an empty hash if the CLI config does not exist' do
|
173
|
+
File.expects(:exist?).with(File.join(ENV['HOME'], '.hab', 'etc', 'cli.toml')).returns(false)
|
174
|
+
subject.send(:habitat_cli_config).must_equal({})
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'returns parsed TOML from the hab config file' do
|
178
|
+
config_file = File.join(ENV['HOME'], '.hab', 'etc', 'cli.toml')
|
179
|
+
File.expects(:exist?).with(config_file).returns(true)
|
180
|
+
Tomlrb.expects(:load_file).with(config_file).returns(foo: 1)
|
181
|
+
subject.send(:habitat_cli_config).must_equal(foo: 1)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
File without changes
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'pathname'
|
4
|
+
require_relative 'renderer'
|
5
|
+
|
6
|
+
module InspecPlugins
|
7
|
+
module Init
|
8
|
+
class CLI < Inspec.plugin(2, :cli_command)
|
9
|
+
subcommand_desc 'init SUBCOMMAND', 'Initialize InSpec objects'
|
10
|
+
|
11
|
+
# Look in the 'template' directory, and register a subcommand
|
12
|
+
# for each template directory found there.
|
13
|
+
template_dir = File.join(File.dirname(__FILE__), 'templates')
|
14
|
+
Dir.glob(File.join(template_dir, '*')) do |template|
|
15
|
+
template_name = Pathname.new(template).relative_path_from(Pathname.new(template_dir)).to_s
|
16
|
+
|
17
|
+
# register command for the template
|
18
|
+
desc "#{template_name} NAME", "Create a new #{template_name}"
|
19
|
+
option :overwrite, type: :boolean, default: false,
|
20
|
+
desc: 'Overwrites existing directory'
|
21
|
+
define_method template_name.to_sym do |name_for_new_structure|
|
22
|
+
renderer = InspecPlugins::Init::Renderer.new(self, options)
|
23
|
+
renderer.render_with_values(template_name, name: name_for_new_structure)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'erb'
|
3
|
+
|
4
|
+
module InspecPlugins
|
5
|
+
module Init
|
6
|
+
class Renderer
|
7
|
+
# Creates a renderer able to render the given template type
|
8
|
+
# 1. iterate over all files
|
9
|
+
# 2. read content in erb
|
10
|
+
# 3. write to full_destination_root_path
|
11
|
+
|
12
|
+
attr_reader :overwrite_mode, :ui
|
13
|
+
def initialize(cli_ui, cli_options = {})
|
14
|
+
@ui = cli_ui
|
15
|
+
@overwrite_mode = cli_options['overwrite']
|
16
|
+
end
|
17
|
+
|
18
|
+
# rubocop: disable Metrics/AbcSize
|
19
|
+
def render_with_values(template_type, template_values = {})
|
20
|
+
# look for template directory
|
21
|
+
base_dir = File.join(File.dirname(__FILE__), 'templates', template_type)
|
22
|
+
# prepare glob for all subdirectories and files
|
23
|
+
template_glob = File.join(base_dir, '**', '{*,.*}')
|
24
|
+
# Use the name attribute to define the path to the profile.
|
25
|
+
profile_path = template_values[:name]
|
26
|
+
# Use slashes (\, /) to split up the name into an Array then use the last entry
|
27
|
+
# to reset the name of the profile.
|
28
|
+
template_values[:name] = template_values[:name].split(%r{\\|\/}).last
|
29
|
+
# Generate the full full_destination_root_path path on disk
|
30
|
+
full_destination_root_path = Pathname.new(Dir.pwd).join(profile_path)
|
31
|
+
ui.plain_text "Create new #{template_type} at #{ui.mark_text(full_destination_root_path)}"
|
32
|
+
|
33
|
+
# check that the directory does not exist
|
34
|
+
if File.exist?(full_destination_root_path) && !overwrite_mode
|
35
|
+
ui.plain_text "#{ui.mark_text(full_destination_root_path)} exists already, use --overwrite"
|
36
|
+
ui.exit(1)
|
37
|
+
end
|
38
|
+
|
39
|
+
# ensure that full_destination_root_path directory is available
|
40
|
+
FileUtils.mkdir_p(full_destination_root_path)
|
41
|
+
|
42
|
+
# iterate over files and write to full_destination_root_path
|
43
|
+
Dir.glob(template_glob) do |file|
|
44
|
+
relative_destination_item_path = Pathname.new(file).relative_path_from(Pathname.new(base_dir))
|
45
|
+
full_destination_item_path = Pathname.new(full_destination_root_path).join(relative_destination_item_path)
|
46
|
+
if File.directory?(file)
|
47
|
+
ui.li "Create directory #{ui.mark_text(relative_destination_item_path)}"
|
48
|
+
FileUtils.mkdir_p(full_destination_item_path)
|
49
|
+
elsif File.file?(file)
|
50
|
+
ui.li "Create file #{ui.mark_text(relative_destination_item_path)}"
|
51
|
+
# read & render content
|
52
|
+
content = render(File.read(file), template_values)
|
53
|
+
# write file content
|
54
|
+
File.write(full_destination_item_path, content)
|
55
|
+
else
|
56
|
+
ui.plain_text "Ignore #{file}, because its not an file or directoy"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
# rubocop: enable Metrics/AbcSize
|
61
|
+
|
62
|
+
# This is a render helper to bind hash values to a ERB template
|
63
|
+
# ERB provides result_with_hash in ruby 2.5.0+, which does exactly this
|
64
|
+
def render(template_content, hash)
|
65
|
+
# create a new binding class
|
66
|
+
cls = Class.new do
|
67
|
+
hash.each do |key, value|
|
68
|
+
define_method key.to_sym do
|
69
|
+
value
|
70
|
+
end
|
71
|
+
end
|
72
|
+
# expose binding
|
73
|
+
define_method :bind do
|
74
|
+
binding
|
75
|
+
end
|
76
|
+
end
|
77
|
+
ERB.new(template_content).result(cls.new.bind)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
File without changes
|
data/lib/{bundles → plugins/inspec-init/lib}/inspec-init/templates/profile/controls/example.rb
RENAMED
File without changes
|
File without changes
|
data/lib/{bundles → plugins/inspec-init/lib}/inspec-init/templates/profile/libraries/.gitkeep
RENAMED
File without changes
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require_relative '../../../shared/core_plugin_test_helper.rb'
|
4
|
+
|
5
|
+
class InitCli < MiniTest::Test
|
6
|
+
include CorePluginFunctionalHelper
|
7
|
+
|
8
|
+
def test_generating_inspec_profile
|
9
|
+
Dir.mktmpdir do |dir|
|
10
|
+
profile = File.join(dir, 'test-profile')
|
11
|
+
out = run_inspec_process("init profile test-profile", prefix: "cd #{dir} &&")
|
12
|
+
assert_equal 0, out.exit_status
|
13
|
+
assert_includes out.stdout, 'Create new profile at'
|
14
|
+
assert_includes out.stdout, profile
|
15
|
+
assert_includes Dir.entries(profile).join, 'inspec.yml'
|
16
|
+
assert_includes Dir.entries(profile).join, 'README.md'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_profile_with_slash_name
|
21
|
+
Dir.mktmpdir do |dir|
|
22
|
+
profile = dir + '/test/deeper/profile'
|
23
|
+
out = run_inspec_process("init profile test/deeper/profile", prefix: "cd #{dir} &&")
|
24
|
+
assert_equal 0, out.exit_status
|
25
|
+
assert_equal true, File.exist?(profile)
|
26
|
+
profile = YAML.load_file("#{profile}/inspec.yml")
|
27
|
+
assert_equal 'profile', profile['name']
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
|
2
|
+
# Load test harness - MiniTest
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'minitest/unit'
|
5
|
+
require 'minitest/pride'
|
6
|
+
require 'minitest/spec'
|
7
|
+
|
8
|
+
# Data formats commonly used in testing
|
9
|
+
require 'json'
|
10
|
+
require 'ostruct'
|
11
|
+
|
12
|
+
# Utilities often needed
|
13
|
+
require 'fileutils'
|
14
|
+
|
15
|
+
# Configure MiniTest to expose things like `let`
|
16
|
+
class Module
|
17
|
+
include Minitest::Spec::DSL
|
18
|
+
end
|
19
|
+
|
20
|
+
module CorePluginBaseHelper
|
21
|
+
let(:repo_path) { File.expand_path(File.join(__FILE__, '..', '..', '..', '..')) }
|
22
|
+
let(:inspec_bin_path) { File.join(repo_path, 'bin', 'inspec') }
|
23
|
+
let(:core_mock_path) { File.join(repo_path, 'test', 'unit', 'mock') }
|
24
|
+
let(:core_fixture_plugins_path) { File.join(core_mock_path, 'plugins') }
|
25
|
+
let(:core_config_dir_path) { File.join(core_mock_path, 'config_dirs') }
|
26
|
+
|
27
|
+
let(:registry) { Inspec::Plugin::V2::Registry.instance }
|
28
|
+
end
|
29
|
+
|
30
|
+
module CorePluginFunctionalHelper
|
31
|
+
include CorePluginBaseHelper
|
32
|
+
|
33
|
+
require 'train'
|
34
|
+
TRAIN_CONNECTION = Train.create('local', command_runner: :generic).connection
|
35
|
+
|
36
|
+
def run_inspec_process(command_line, opts = {})
|
37
|
+
prefix = ''
|
38
|
+
if opts.key?(:prefix)
|
39
|
+
prefix = opts[:prefix]
|
40
|
+
elsif opts.key?(:env)
|
41
|
+
prefix = opts[:env].to_a.map { |assignment| "#{assignment[0]}=#{assignment[1]}" }.join(' ')
|
42
|
+
end
|
43
|
+
TRAIN_CONNECTION.run_command("#{prefix} #{inspec_bin_path} #{command_line}")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
module CorePluginUnitHelper
|
48
|
+
include CorePluginBaseHelper
|
49
|
+
require 'inspec'
|
50
|
+
end
|
@@ -12,7 +12,7 @@ class AwsSecurityGroup < Inspec.resource(1)
|
|
12
12
|
supports platform: 'aws'
|
13
13
|
|
14
14
|
include AwsSingularResourceMixin
|
15
|
-
attr_reader :description, :group_id, :group_name, :vpc_id, :inbound_rules, :outbound_rules
|
15
|
+
attr_reader :description, :group_id, :group_name, :vpc_id, :inbound_rules, :outbound_rules, :inbound_rules_count, :outbound_rules_count
|
16
16
|
|
17
17
|
def to_s
|
18
18
|
"EC2 Security Group #{@group_id}"
|
@@ -57,6 +57,7 @@ class AwsSecurityGroup < Inspec.resource(1)
|
|
57
57
|
matched &&= allow__match_port(rule, criteria)
|
58
58
|
matched &&= allow__match_protocol(rule, criteria)
|
59
59
|
matched &&= allow__match_ipv4_range(rule, criteria)
|
60
|
+
matched &&= allow__match_ipv6_range(rule, criteria)
|
60
61
|
matched
|
61
62
|
end
|
62
63
|
end
|
@@ -65,6 +66,7 @@ class AwsSecurityGroup < Inspec.resource(1)
|
|
65
66
|
allowed_criteria = [
|
66
67
|
:from_port,
|
67
68
|
:ipv4_range,
|
69
|
+
:ipv6_range,
|
68
70
|
:port,
|
69
71
|
:position,
|
70
72
|
:protocol,
|
@@ -149,11 +151,17 @@ class AwsSecurityGroup < Inspec.resource(1)
|
|
149
151
|
rule[:ip_protocol] == prot
|
150
152
|
end
|
151
153
|
|
152
|
-
def
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
154
|
+
def match_ipv4_or_6_range(rule, criteria)
|
155
|
+
if criteria.key?(:ipv4_range)
|
156
|
+
query = criteria[:ipv4_range]
|
157
|
+
query = [query] unless query.is_a?(Array)
|
158
|
+
ranges = rule[:ip_ranges].map { |rng| rng[:cidr_ip] }
|
159
|
+
else # IPv6
|
160
|
+
query = criteria[:ipv6_range]
|
161
|
+
query = [query] unless query.is_a?(Array)
|
162
|
+
ranges = rule[:ipv_6_ranges].map { |rng| rng[:cidr_ipv_6] }
|
163
|
+
end
|
164
|
+
|
157
165
|
if criteria[:exact]
|
158
166
|
Set.new(query) == Set.new(ranges)
|
159
167
|
else
|
@@ -169,6 +177,16 @@ class AwsSecurityGroup < Inspec.resource(1)
|
|
169
177
|
end
|
170
178
|
end
|
171
179
|
|
180
|
+
def allow__match_ipv4_range(rule, criteria)
|
181
|
+
return true unless criteria.key?(:ipv4_range)
|
182
|
+
match_ipv4_or_6_range(rule, criteria)
|
183
|
+
end
|
184
|
+
|
185
|
+
def allow__match_ipv6_range(rule, criteria)
|
186
|
+
return true unless criteria.key?(:ipv6_range)
|
187
|
+
match_ipv4_or_6_range(rule, criteria)
|
188
|
+
end
|
189
|
+
|
172
190
|
def validate_params(raw_params)
|
173
191
|
recognized_params = check_resource_param_names(
|
174
192
|
raw_params: raw_params,
|
@@ -196,6 +214,18 @@ class AwsSecurityGroup < Inspec.resource(1)
|
|
196
214
|
validated_params
|
197
215
|
end
|
198
216
|
|
217
|
+
def count_sg_rules(ip_permissions)
|
218
|
+
rule_count = 0
|
219
|
+
ip_permissions.each do |ip_permission|
|
220
|
+
[:ip_ranges, :ipv_6_ranges, :user_id_group_pairs].each do |key|
|
221
|
+
if ip_permission.key? key
|
222
|
+
rule_count += ip_permission[key].length
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
rule_count
|
227
|
+
end
|
228
|
+
|
199
229
|
def fetch_from_api # rubocop: disable Metrics/AbcSize
|
200
230
|
backend = BackendFactory.create(inspec_runner)
|
201
231
|
|
@@ -233,7 +263,9 @@ class AwsSecurityGroup < Inspec.resource(1)
|
|
233
263
|
@group_name = dsg_response.security_groups[0].group_name
|
234
264
|
@vpc_id = dsg_response.security_groups[0].vpc_id
|
235
265
|
@inbound_rules = dsg_response.security_groups[0].ip_permissions.map(&:to_h)
|
266
|
+
@inbound_rules_count = count_sg_rules(dsg_response.security_groups[0].ip_permissions.map(&:to_h))
|
236
267
|
@outbound_rules = dsg_response.security_groups[0].ip_permissions_egress.map(&:to_h)
|
268
|
+
@outbound_rules_count = count_sg_rules(dsg_response.security_groups[0].ip_permissions_egress.map(&:to_h))
|
237
269
|
end
|
238
270
|
|
239
271
|
class Backend
|