inspec-core 5.22.65 → 5.22.80
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.
- checksums.yaml +4 -4
- data/Gemfile +10 -3
- data/inspec-core.gemspec +2 -2
- data/lib/inspec/exceptions.rb +1 -0
- data/lib/inspec/profile.rb +2 -2
- data/lib/inspec/resources/audit_policy.rb +8 -2
- data/lib/inspec/resources/groups.rb +52 -0
- data/lib/inspec/resources/postgres_session.rb +8 -4
- data/lib/inspec/secrets/yaml.rb +9 -3
- data/lib/inspec/version.rb +1 -1
- data/lib/inspec/waiver_file_reader.rb +90 -32
- metadata +11 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6b46f57de93a21fa00ddeb70944cc1bb3cf846c73d1b33c5460496472773b0fa
|
4
|
+
data.tar.gz: a1f020b14dc5f06c81f98d7fabaa593b5a0696b5cd4370625382b627c216493e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f72371f72e1195698128502801aefea2e698bd2c705c00b849547c2f8b18881bb05964de87715cbea5301ee6284db60fba6a9f080915d3f672686174c0ec1e59
|
7
|
+
data.tar.gz: 56a96407e6c3dd29f7d33c0ee128cf419aac43e01c48c6c220c3041cf20aeee4478d9be1ec280f2732391ca9d7eef5db19371e69d6105036e13fbbca5a6c3e53
|
data/Gemfile
CHANGED
@@ -12,7 +12,7 @@ gem "inspec-bin", path: "./inspec-bin"
|
|
12
12
|
# ffi version v1.17.0 is breaking verify pipeline as it requires
|
13
13
|
# rubygems version to be upgraded to >= 3.3.22 Ref:https://buildkite.com/chef/inspec-inspec-main-verify-private/builds/812#018fe177-2ccb-45ed-a25e-213c8a6453df/698-707
|
14
14
|
|
15
|
-
gem "ffi", ">= 1.15.5", "< 1.
|
15
|
+
gem "ffi", ">= 1.15.5", "< 1.17.0"
|
16
16
|
|
17
17
|
# We have a build issue 2023-11-13 with unf_ext 0.0.9 so we are pinning to 0.0.8.2
|
18
18
|
# See https://github.com/knu/ruby-unf_ext/issues/74 https://buildkite.com/chef/inspec-inspec-inspec-5-omnibus-release/builds/22
|
@@ -37,8 +37,10 @@ group :test do
|
|
37
37
|
gem "minitest-sprint", "~> 1.0"
|
38
38
|
gem "minitest", "5.15.0"
|
39
39
|
gem "mocha"
|
40
|
-
|
41
|
-
gem "
|
40
|
+
# Pinning this version as it breaking for ruby 3.1.0
|
41
|
+
gem "nokogiri", "< 1.17.2"
|
42
|
+
# Pinning this version as it breaking for ruby 3.0.0
|
43
|
+
gem "pry-byebug", "< 3.11.0"
|
42
44
|
gem "pry"
|
43
45
|
gem "rake"
|
44
46
|
gem "simplecov"
|
@@ -61,6 +63,11 @@ end
|
|
61
63
|
# Remove this pin when upgrading to Ruby 3.2 or higher.
|
62
64
|
gem "zeitwerk", "~> 2.6.0", "< 2.7"
|
63
65
|
|
66
|
+
# Pinning dry-core,dry-core,dry-types to < 1.1.0 as it is breaking the build because 1.1.0 is incompatible with the current version, ruby 3.0.x on CI
|
67
|
+
gem "dry-types", "<= 1.7.2" if RUBY_VERSION < "3.1.0"
|
68
|
+
gem "dry-core", "> 1.0.0", "< 1.1.0" if RUBY_VERSION < "3.1.0"
|
69
|
+
gem "dry-inflector", "<= 1.1.0" if RUBY_VERSION < "3.1.0"
|
70
|
+
|
64
71
|
# Pinning securerandom to < 0.4.0 as it is breaking the build because 0.4.0 is incompatible with the current version, ruby 3.0.x on CI
|
65
72
|
# Remove this pin when upgrading to Ruby 3.1 or higher on CI.
|
66
73
|
gem "securerandom", "< 0.4.0" if RUBY_VERSION < "3.1.0"
|
data/inspec-core.gemspec
CHANGED
@@ -36,7 +36,7 @@ Gem::Specification.new do |spec|
|
|
36
36
|
spec.add_dependency "rspec-its", "~> 1.2"
|
37
37
|
spec.add_dependency "pry", "~> 0.13"
|
38
38
|
spec.add_dependency "hashie", ">= 3.4", "< 6.0"
|
39
|
-
spec.add_dependency "mixlib-log", "~> 3.0"
|
39
|
+
spec.add_dependency "mixlib-log", "~> 3.0", "< 3.2"
|
40
40
|
spec.add_dependency "sslshake", "~> 1.2"
|
41
41
|
spec.add_dependency "parallel", "~> 1.9"
|
42
42
|
spec.add_dependency "faraday", ">= 1", "< 3"
|
@@ -55,5 +55,5 @@ Gem::Specification.new do |spec|
|
|
55
55
|
# which was causing a LoadError ('cannot load such file -- ast') for users/applications using 'inspec-core'.
|
56
56
|
spec.add_dependency "cookstyle"
|
57
57
|
|
58
|
-
spec.add_dependency "train-core", "~> 3.
|
58
|
+
spec.add_dependency "train-core", "~> 3.12.13"
|
59
59
|
end
|
data/lib/inspec/exceptions.rb
CHANGED
data/lib/inspec/profile.rb
CHANGED
@@ -575,7 +575,7 @@ module Inspec
|
|
575
575
|
include_tests: include_tests)
|
576
576
|
|
577
577
|
# Collect all metadata defined in the control block and inputs defined inside the control block
|
578
|
-
src.ast
|
578
|
+
src.ast&.each_node { |n|
|
579
579
|
ctl_id_collector.process(n)
|
580
580
|
input_collector.process(n)
|
581
581
|
}
|
@@ -637,7 +637,7 @@ module Inspec
|
|
637
637
|
}
|
638
638
|
source_location_ref = @source_reader.target.abs_path(control_filename)
|
639
639
|
Inspec::Profile::AstHelper::TitleCollector.new(group_data)
|
640
|
-
.process(src.ast
|
640
|
+
.process(src.ast&.child_nodes&.first) # Picking the title defined for the whole controls file
|
641
641
|
group_controls = @info_from_parse[:controls].select { |control| control[:source_location][:ref] == source_location_ref }
|
642
642
|
group_data[:controls] = group_controls.map { |control| control[:id] }
|
643
643
|
|
@@ -39,11 +39,17 @@ module Inspec::Resources
|
|
39
39
|
# expected result:
|
40
40
|
# Machine Name,Policy Target,Subcategory,Subcategory GUID,Inclusion Setting,Exclusion Setting
|
41
41
|
# WIN-MB8NINQ388J,System,Kerberos Authentication Service,{0CCE9242-69AE-11D9-BED3-505054503030},No Auditing,
|
42
|
-
|
42
|
+
auditpol_cmd = "Auditpol /get /subcategory:'#{key}' /r"
|
43
|
+
result ||= inspec.command(auditpol_cmd)
|
44
|
+
|
45
|
+
unless result.exit_status == 0
|
46
|
+
error = result.stdout + "\n" + result.stderr
|
47
|
+
raise Inspec::Exceptions::ResourceFailed, "Error while executing #{auditpol_cmd} command: #{error}"
|
48
|
+
end
|
43
49
|
|
44
50
|
# find line
|
45
51
|
target = nil
|
46
|
-
result.each_line do |s|
|
52
|
+
result.stdout.each_line do |s|
|
47
53
|
target = s.strip if s =~ /\b.*#{key}.*\b/
|
48
54
|
end
|
49
55
|
|
@@ -200,8 +200,60 @@ module Inspec::Resources
|
|
200
200
|
# implements generic unix groups via /etc/group
|
201
201
|
class UnixGroup < GroupInfo
|
202
202
|
def groups
|
203
|
+
get_group_info
|
204
|
+
end
|
205
|
+
|
206
|
+
private
|
207
|
+
|
208
|
+
def get_group_info
|
209
|
+
# First, try to fetch group info using getent
|
210
|
+
group_info = fetch_group_info_using_getent
|
211
|
+
|
212
|
+
return group_info unless group_info.empty?
|
213
|
+
|
214
|
+
# If getent fails, fallback to reading group info from /etc/group using inspec.etc_group.entries
|
215
|
+
Inspec::Log.debug("Falling back to reading group info from /etc/group as getent is unavailable or failed.")
|
203
216
|
inspec.etc_group.entries
|
204
217
|
end
|
218
|
+
|
219
|
+
# Fetches group information using the getent utility
|
220
|
+
def fetch_group_info_using_getent
|
221
|
+
# Find getent utility on the system
|
222
|
+
bin = find_getent_utility
|
223
|
+
|
224
|
+
# If getent is available, fetch group info
|
225
|
+
return [] unless bin
|
226
|
+
|
227
|
+
cmd = inspec.command("#{bin} group")
|
228
|
+
return parse_group_info(cmd) if cmd.exit_status.to_i == 0
|
229
|
+
|
230
|
+
# If getent fails, log the error and return an empty array
|
231
|
+
Inspec::Log.debug("Failed to execute #{bin} group: #{cmd.stderr}.")
|
232
|
+
[]
|
233
|
+
end
|
234
|
+
|
235
|
+
# Parses group info from the command output
|
236
|
+
def parse_group_info(cmd)
|
237
|
+
cmd.stdout.strip.split("\n").map do |line|
|
238
|
+
name, password, gid, members = line.split(":")
|
239
|
+
{
|
240
|
+
"name" => name,
|
241
|
+
"password" => password,
|
242
|
+
"gid" => gid.to_i,
|
243
|
+
"members" => members,
|
244
|
+
}
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
# Checks if getent exists on the system
|
249
|
+
def find_getent_utility
|
250
|
+
%w{/usr/bin/getent /bin/getent getent}.each do |cmd|
|
251
|
+
return cmd if inspec.command(cmd).exist?
|
252
|
+
end
|
253
|
+
# Log debug information if getent is not found
|
254
|
+
Inspec::Log.debug("Could not find `getent` on your system.")
|
255
|
+
nil # Return nil if getent is not found
|
256
|
+
end
|
205
257
|
end
|
206
258
|
|
207
259
|
# OSX uses opendirectory for groups, so `/etc/group` may not be fully accurate
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# copyright: 2015, Vulcano Security GmbH
|
2
2
|
|
3
3
|
require "shellwords" unless defined?(Shellwords)
|
4
|
-
|
4
|
+
require "cgi" unless defined?(CGI)
|
5
5
|
module Inspec::Resources
|
6
6
|
class Lines
|
7
7
|
attr_reader :output, :exit_status
|
@@ -74,6 +74,10 @@ module Inspec::Resources
|
|
74
74
|
Shellwords.escape(query)
|
75
75
|
end
|
76
76
|
|
77
|
+
def encoded_password(password)
|
78
|
+
CGI.escape(password)
|
79
|
+
end
|
80
|
+
|
77
81
|
def create_psql_cmd(query, db = [])
|
78
82
|
dbs = db.map { |x| "#{x}" }.join(" ")
|
79
83
|
|
@@ -82,14 +86,14 @@ module Inspec::Resources
|
|
82
86
|
# Socket connection only enabled for non-windows platforms
|
83
87
|
# Windows does not support unix domain sockets
|
84
88
|
option_port = @port.nil? ? "" : "-p #{@port}" # add explicit port if specified
|
85
|
-
"psql -d postgresql://#{@user}:#{@pass}@/#{dbs}?host=#{@socket_path} #{option_port} -A -t -w -c #{escaped_query(query)}"
|
89
|
+
"psql -d postgresql://#{@user}:#{encoded_password(@pass)}@/#{dbs}?host=#{@socket_path} #{option_port} -A -t -w -c #{escaped_query(query)}"
|
86
90
|
else
|
87
91
|
# Host in connection string establishes tcp/ip connection
|
88
92
|
if inspec.os.windows?
|
89
93
|
warn "Socket based connection not supported in windows, connecting using host" if @socket_path
|
90
|
-
"psql -d postgresql://#{@user}:#{@pass}@#{@host}:#{@port}/#{dbs} -A -t -w -c \"#{query}\""
|
94
|
+
"psql -d postgresql://#{@user}:#{encoded_password(@pass)}@#{@host}:#{@port}/#{dbs} -A -t -w -c \"#{query}\""
|
91
95
|
else
|
92
|
-
"psql -d postgresql://#{@user}:#{@pass}@#{@host}:#{@port}/#{dbs} -A -t -w -c #{escaped_query(query)}"
|
96
|
+
"psql -d postgresql://#{@user}:#{encoded_password(@pass)}@#{@host}:#{@port}/#{dbs} -A -t -w -c #{escaped_query(query)}"
|
93
97
|
end
|
94
98
|
end
|
95
99
|
end
|
data/lib/inspec/secrets/yaml.rb
CHANGED
@@ -24,12 +24,18 @@ module Secrets
|
|
24
24
|
@inputs = ::YAML.load_file(target)
|
25
25
|
end
|
26
26
|
|
27
|
-
|
28
|
-
|
27
|
+
# In case of empty yaml file raise the warning else raise the parsing error.
|
28
|
+
if !@inputs || @inputs.empty?
|
29
|
+
Inspec::Log.warn("Unable to parse #{target}: YAML file is empty.")
|
29
30
|
@inputs = nil
|
31
|
+
elsif !@inputs.is_a?(Hash)
|
32
|
+
# Exits with usage error.
|
33
|
+
Inspec::Log.error("Unable to parse #{target}: invalid YAML or contents is not a Hash")
|
34
|
+
Inspec::UI.new.exit(:usage_error)
|
30
35
|
end
|
31
36
|
rescue => e
|
32
|
-
|
37
|
+
# Any other error related to Yaml parsing will be raised here.
|
38
|
+
raise "Error reading YAML file #{target}: #{e}"
|
33
39
|
end
|
34
40
|
end
|
35
41
|
end
|
data/lib/inspec/version.rb
CHANGED
@@ -5,6 +5,8 @@ require "inspec/utils/waivers/json_file_reader"
|
|
5
5
|
module Inspec
|
6
6
|
class WaiverFileReader
|
7
7
|
|
8
|
+
SUPPORTED_FILE_EXTENSION = %w{.yaml .yml .csv .json}.freeze
|
9
|
+
|
8
10
|
def self.fetch_waivers_by_profile(profile_id, files)
|
9
11
|
read_waivers_from_file(profile_id, files) if @waivers_data.nil? || @waivers_data[profile_id].nil?
|
10
12
|
@waivers_data[profile_id]
|
@@ -15,49 +17,105 @@ module Inspec
|
|
15
17
|
output = {}
|
16
18
|
|
17
19
|
files.each do |file_path|
|
18
|
-
|
19
|
-
data = nil
|
20
|
-
if [".yaml", ".yml"].include? file_extension
|
21
|
-
data = Secrets::YAML.resolve(file_path)
|
22
|
-
unless data.nil?
|
23
|
-
data = data.inputs
|
24
|
-
validate_json_yaml(data)
|
25
|
-
end
|
26
|
-
elsif file_extension == ".csv"
|
27
|
-
data = Waivers::CSVFileReader.resolve(file_path)
|
28
|
-
headers = Waivers::CSVFileReader.headers
|
29
|
-
validate_headers(headers)
|
30
|
-
elsif file_extension == ".json"
|
31
|
-
data = Waivers::JSONFileReader.resolve(file_path)
|
32
|
-
validate_json_yaml(data) unless data.nil?
|
33
|
-
end
|
34
|
-
output.merge!(data) if !data.nil? && data.is_a?(Hash)
|
20
|
+
next unless valid_waiver_file?(file_path)
|
35
21
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
22
|
+
data = parse_waiver_file(file_path)
|
23
|
+
output.merge!(data) if data.is_a?(Hash)
|
24
|
+
rescue Inspec::Exceptions::WaiversFileNotReadable, Inspec::Exceptions::WaiversFileInvalidFormatting => e
|
25
|
+
Inspec::Log.error "Error reading waivers file #{file_path}. #{e.message}"
|
26
|
+
Inspec::UI.new.exit(:usage_error)
|
41
27
|
end
|
42
28
|
|
43
29
|
@waivers_data[profile_id] = output
|
44
30
|
end
|
45
31
|
|
46
|
-
def self.
|
47
|
-
|
48
|
-
|
32
|
+
def self.valid_waiver_file?(file_path)
|
33
|
+
# Check if the file is readable
|
34
|
+
file_extension = File.extname(file_path).downcase
|
35
|
+
unless SUPPORTED_FILE_EXTENSION.include?(file_extension)
|
36
|
+
raise Inspec::Exceptions::WaiversFileNotReadable,
|
37
|
+
"Unsupported file extension for '#{file_path}'. Allowed waiver file extensions: #{SUPPORTED_FILE_EXTENSION.join(", ")}"
|
38
|
+
end
|
39
|
+
|
40
|
+
# Check if the file is empty
|
41
|
+
if File.zero?(file_path)
|
42
|
+
Inspec::Log.warn "Waivers file '#{file_path}' is empty. Skipping waivers."
|
43
|
+
return false
|
44
|
+
end
|
49
45
|
|
50
|
-
|
51
|
-
|
52
|
-
|
46
|
+
true
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.parse_waiver_file(file_path)
|
50
|
+
file_extension = File.extname(file_path).downcase
|
51
|
+
|
52
|
+
case file_extension
|
53
|
+
when ".yaml", ".yml"
|
54
|
+
data = Secrets::YAML.resolve(file_path)&.inputs
|
55
|
+
validate_json_yaml(data)
|
56
|
+
when ".csv"
|
57
|
+
data = Waivers::CSVFileReader.resolve(file_path)
|
58
|
+
validate_csv_headers(Waivers::CSVFileReader.headers)
|
59
|
+
when ".json"
|
60
|
+
data = Waivers::JSONFileReader.resolve(file_path)
|
61
|
+
validate_json_yaml(data)
|
62
|
+
end
|
63
|
+
|
64
|
+
data
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.all_fields
|
68
|
+
%w{control_id justification expiration_date run}
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.validate_csv_headers(headers)
|
72
|
+
invalid_headers_info = fetch_invalid_headers_info(headers)
|
73
|
+
# Warn if blank column found in csv file
|
74
|
+
Inspec::Log.warn "Invalid column headers: Column can't be nil" if invalid_headers_info[:blank_column]
|
75
|
+
# Warn if extra header found in csv file
|
76
|
+
Inspec::Log.warn "Extra header/s #{invalid_headers_info[:extra_headers]}" unless invalid_headers_info[:extra_headers].empty?
|
77
|
+
unless invalid_headers_info[:missing_required_fields].empty?
|
78
|
+
raise Inspec::Exceptions::WaiversFileInvalidFormatting,
|
79
|
+
"Missing required header/s #{invalid_headers_info[:missing_required_fields]}. Fix headers in file to proceed."
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.fetch_invalid_headers_info(headers, json_yaml = false)
|
84
|
+
required_fields = json_yaml ? %w{justification} : %w{control_id justification}
|
85
|
+
data = {}
|
86
|
+
data[:missing_required_fields] = []
|
87
|
+
# Finds missing required fields
|
88
|
+
unless (required_fields - headers).empty?
|
89
|
+
data[:missing_required_fields] = required_fields - headers
|
90
|
+
end
|
91
|
+
# If column with no header found set the blank_column flag. Only applicable for csv
|
92
|
+
data[:blank_column] = headers.include?(nil) ? true : false
|
93
|
+
# Find extra headers/parameters
|
94
|
+
data[:extra_headers] = (headers - all_fields)
|
95
|
+
data
|
53
96
|
end
|
54
97
|
|
55
98
|
def self.validate_json_yaml(data)
|
56
|
-
|
57
|
-
|
58
|
-
|
99
|
+
return if data.nil?
|
100
|
+
|
101
|
+
missing_required_field = false
|
102
|
+
data.each do |key, value|
|
103
|
+
# In case of yaml or json we need to validate headers/parametes for each value
|
104
|
+
invalid_headers_info = fetch_invalid_headers_info(value.keys, true)
|
105
|
+
# WARN in case of extra parameters found in each waived control
|
106
|
+
Inspec::Log.warn "Control ID #{key}: extra parameter/s #{invalid_headers_info[:extra_headers]}" unless invalid_headers_info[:extra_headers].empty?
|
107
|
+
unless invalid_headers_info[:missing_required_fields].empty?
|
108
|
+
missing_required_field = true
|
109
|
+
# Log error for each waived control
|
110
|
+
Inspec::Log.error "Control ID #{key}: missing required parameter/s #{invalid_headers_info[:missing_required_fields]}"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Raise error if any of the waived control has missing required filed
|
115
|
+
if missing_required_field
|
116
|
+
raise Inspec::Exceptions::WaiversFileInvalidFormatting,
|
117
|
+
"Missing required parameter [justification]. Fix parameters in file to proceed."
|
59
118
|
end
|
60
|
-
validate_headers(headers.flatten.uniq, true)
|
61
119
|
end
|
62
120
|
end
|
63
121
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: inspec-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.22.
|
4
|
+
version: 5.22.80
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chef InSpec Team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-04-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: chef-telemetry
|
@@ -185,6 +185,9 @@ dependencies:
|
|
185
185
|
- - "~>"
|
186
186
|
- !ruby/object:Gem::Version
|
187
187
|
version: '3.0'
|
188
|
+
- - "<"
|
189
|
+
- !ruby/object:Gem::Version
|
190
|
+
version: '3.2'
|
188
191
|
type: :runtime
|
189
192
|
prerelease: false
|
190
193
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -192,6 +195,9 @@ dependencies:
|
|
192
195
|
- - "~>"
|
193
196
|
- !ruby/object:Gem::Version
|
194
197
|
version: '3.0'
|
198
|
+
- - "<"
|
199
|
+
- !ruby/object:Gem::Version
|
200
|
+
version: '3.2'
|
195
201
|
- !ruby/object:Gem::Dependency
|
196
202
|
name: sslshake
|
197
203
|
requirement: !ruby/object:Gem::Requirement
|
@@ -384,14 +390,14 @@ dependencies:
|
|
384
390
|
requirements:
|
385
391
|
- - "~>"
|
386
392
|
- !ruby/object:Gem::Version
|
387
|
-
version:
|
393
|
+
version: 3.12.13
|
388
394
|
type: :runtime
|
389
395
|
prerelease: false
|
390
396
|
version_requirements: !ruby/object:Gem::Requirement
|
391
397
|
requirements:
|
392
398
|
- - "~>"
|
393
399
|
- !ruby/object:Gem::Version
|
394
|
-
version:
|
400
|
+
version: 3.12.13
|
395
401
|
description: InSpec provides a framework for creating end-to-end infrastructure tests.
|
396
402
|
You can use it for integration or even compliance testing. Create fully portable
|
397
403
|
test profiles and use them in your workflow to ensure stability and security. Integrate
|
@@ -868,7 +874,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
868
874
|
- !ruby/object:Gem::Version
|
869
875
|
version: '0'
|
870
876
|
requirements: []
|
871
|
-
rubygems_version: 3.
|
877
|
+
rubygems_version: 3.3.27
|
872
878
|
signing_key:
|
873
879
|
specification_version: 4
|
874
880
|
summary: Infrastructure and compliance testing. Core library.
|