contrast-agent 4.10.0 → 4.11.0
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/lib/contrast/agent/assess/contrast_object.rb +0 -3
- data/lib/contrast/agent/assess/policy/preshift.rb +7 -6
- data/lib/contrast/agent/assess/policy/propagator/match_data.rb +4 -4
- data/lib/contrast/agent/assess/policy/propagator/remove.rb +4 -9
- data/lib/contrast/agent/assess/policy/trigger_method.rb +1 -2
- data/lib/contrast/agent/inventory/dependency_usage_analysis.rb +1 -1
- data/lib/contrast/agent/request.rb +5 -3
- data/lib/contrast/agent/request_context.rb +8 -3
- data/lib/contrast/agent/scope.rb +32 -20
- data/lib/contrast/agent/tracepoint_hook.rb +11 -3
- data/lib/contrast/agent/version.rb +1 -1
- data/lib/contrast/utils/class_util.rb +26 -19
- data/lib/contrast/utils/io_util.rb +42 -34
- data/lib/contrast/utils/lru_cache.rb +43 -0
- data/lib/contrast/utils/ruby_ast_rewriter.rb +1 -1
- metadata +13 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2ad97d601b81e16e1d0263d86b60a3acd0e5a5ff9cb3f42598c262774a518169
|
4
|
+
data.tar.gz: 749f87aefffd1e1504834dc7f919d45280cf560a20805184757dd9f6bda97477
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cfa15549565b4f17c431332c7bc7c6fe84bd5bea321860db84f24a2df5e2d5241675200ed6e50ebe53fc319d94ade6ebfed26fe664fc297dde54a1fc9f645fda
|
7
|
+
data.tar.gz: 017f02883faee2d281b7b052844653ddbb744fa27f02cf5739c38e50256eb054effb966c5b35b79b05e7d3af62f35d90509352f5c4327c9474e936c7e740ef19
|
@@ -35,9 +35,6 @@ module Contrast
|
|
35
35
|
if object
|
36
36
|
@object = Contrast::Utils::ClassUtil.to_contrast_string(object)
|
37
37
|
@object_type = object.cs__class.cs__name
|
38
|
-
# TODO: RUBY-1084 determine if we need to copy these tags to
|
39
|
-
# restore immutability. For instance, if these tags were on a
|
40
|
-
# String that was then #reverse!'d, would our tags be wrong?
|
41
38
|
@tags = Contrast::Agent::Assess::Tracker.properties(object)&.tags
|
42
39
|
else
|
43
40
|
@object = Contrast::Utils::ObjectShare::NIL_STRING
|
@@ -83,20 +83,21 @@ module Contrast
|
|
83
83
|
end
|
84
84
|
|
85
85
|
def append_arg_details preshift, args
|
86
|
-
|
86
|
+
args_length = args.length
|
87
|
+
preshift.args = Array.new(args_length)
|
88
|
+
preshift.arg_lengths = Array.new(args_length)
|
87
89
|
idx = 0
|
88
|
-
while idx <
|
90
|
+
while idx < args_length
|
89
91
|
original_arg = args[idx]
|
90
|
-
p_arg =
|
92
|
+
p_arg = can_dup?(false, original_arg) ? original_arg.dup : original_arg
|
93
|
+
preshift.args[idx] = p_arg
|
94
|
+
preshift.arg_lengths[idx] = Contrast::Utils::DuckUtils.quacks_to?(p_arg, :length) ? p_arg.length : 0
|
91
95
|
idx += 1
|
92
96
|
next if p_arg.__id__ == original_arg.__id__
|
93
97
|
next unless Contrast::Agent::Assess::Tracker.tracked?(original_arg)
|
94
98
|
|
95
99
|
Contrast::Agent::Assess::Tracker.copy(original_arg, p_arg)
|
96
100
|
end
|
97
|
-
preshift.arg_lengths = preshift.args.map do |preshift_arg|
|
98
|
-
Contrast::Utils::DuckUtils.quacks_to?(preshift_arg, :length) ? preshift_arg.length : 0
|
99
|
-
end
|
100
101
|
end
|
101
102
|
end
|
102
103
|
end
|
@@ -15,7 +15,7 @@ module Contrast
|
|
15
15
|
case ret
|
16
16
|
when Array
|
17
17
|
idx = 0
|
18
|
-
while idx < ret.
|
18
|
+
while idx < ret.length
|
19
19
|
return_value = ret[idx]
|
20
20
|
index = idx
|
21
21
|
idx += 1
|
@@ -34,7 +34,7 @@ module Contrast
|
|
34
34
|
|
35
35
|
def captures_tagger propagation_node, preshift, ret, _block
|
36
36
|
idx = 0
|
37
|
-
while idx < ret.
|
37
|
+
while idx < ret.length
|
38
38
|
return_value = ret[idx]
|
39
39
|
index = idx
|
40
40
|
idx += 1
|
@@ -48,7 +48,7 @@ module Contrast
|
|
48
48
|
|
49
49
|
def to_a_tagger propagation_node, preshift, ret, _block
|
50
50
|
idx = 0
|
51
|
-
while idx < ret.
|
51
|
+
while idx < ret.length
|
52
52
|
return_value = ret[idx]
|
53
53
|
index = idx
|
54
54
|
idx += 1
|
@@ -61,7 +61,7 @@ module Contrast
|
|
61
61
|
|
62
62
|
def values_at_tagger propagation_node, preshift, ret, _block
|
63
63
|
idx = 0
|
64
|
-
while idx < ret.
|
64
|
+
while idx < ret.length
|
65
65
|
return_value = ret[idx]
|
66
66
|
return_index = idx
|
67
67
|
idx += 1
|
@@ -26,7 +26,6 @@ module Contrast
|
|
26
26
|
return unless (properties = Contrast::Agent::Assess::Tracker.properties!(target))
|
27
27
|
|
28
28
|
source_string = source.is_a?(String) ? source : source.to_s
|
29
|
-
|
30
29
|
# If the lengths are the same, we should just copy the tags because nothing was removed, but a new
|
31
30
|
# instance could have been created. copy_from will handle the case where the source is the target.
|
32
31
|
if source_string.length == target.length
|
@@ -34,10 +33,7 @@ module Contrast
|
|
34
33
|
return
|
35
34
|
end
|
36
35
|
|
37
|
-
source_chars = source_string.chars
|
38
36
|
source_idx = 0
|
39
|
-
|
40
|
-
target_chars = target.chars
|
41
37
|
target_idx = 0
|
42
38
|
|
43
39
|
remove_ranges = []
|
@@ -45,10 +41,9 @@ module Contrast
|
|
45
41
|
|
46
42
|
# loop over the target, the result of the delete every range of characters that it differs from the
|
47
43
|
# source represents a section that was deleted. these sections need to have their tags updated
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
source_char = source_chars[source_idx]
|
44
|
+
while target_idx < target.length
|
45
|
+
target_char = target[target_idx]
|
46
|
+
source_char = source_string[source_idx]
|
52
47
|
if target_char == source_char
|
53
48
|
target_idx += 1
|
54
49
|
if start
|
@@ -63,7 +58,7 @@ module Contrast
|
|
63
58
|
|
64
59
|
# once we're done looping over the target, anything left over is extra from the source that was
|
65
60
|
# deleted. tags applying to it need to be removed.
|
66
|
-
remove_ranges << (source_idx...
|
61
|
+
remove_ranges << (source_idx...source_string.length) if source_idx != source_string.length
|
67
62
|
|
68
63
|
# handle deleting the removed ranges
|
69
64
|
properties.delete_tags_at_ranges(remove_ranges)
|
@@ -246,9 +246,8 @@ module Contrast
|
|
246
246
|
logger.debug('Trigger source is untrackable. Unable to inspect.',
|
247
247
|
node_id: trigger_node.id,
|
248
248
|
source_id: source.__id__,
|
249
|
-
source_type: source.cs__class.
|
249
|
+
source_type: source.cs__class.cs__name,
|
250
250
|
frozen: source.cs__frozen?)
|
251
|
-
logger.trace(source.to_s[0..99])
|
252
251
|
end
|
253
252
|
end
|
254
253
|
|
@@ -60,7 +60,7 @@ module Contrast
|
|
60
60
|
|
61
61
|
digest = Contrast::Utils::Sha256Builder.instance.build_from_spec(spec)
|
62
62
|
unless digest
|
63
|
-
logger.debug('Unable to resolve digest for gem spec', spec: spec.to_s)
|
63
|
+
logger.debug('Unable to resolve digest for gem spec', spec: spec.to_s) if logger.debug?
|
64
64
|
return
|
65
65
|
end
|
66
66
|
report_path = adjust_path_for_reporting(path, spec)
|
@@ -92,10 +92,12 @@ module Contrast
|
|
92
92
|
defined?(Rack::Multipart::UploadedFile) &&
|
93
93
|
body.is_a?(Rack::Multipart::UploadedFile)
|
94
94
|
|
95
|
-
logger.trace(
|
95
|
+
logger.trace('not parsing uploaded file body',
|
96
|
+
file_name: body.original_filename,
|
97
|
+
content_type: body.content_type)
|
96
98
|
@_body = nil
|
97
99
|
else
|
98
|
-
logger.trace(
|
100
|
+
logger.trace('parsing body from request', body_type: body.cs__class.cs__name)
|
99
101
|
@_body = Contrast::Utils::StringUtils.force_utf8(read_body(body))
|
100
102
|
end
|
101
103
|
|
@@ -185,7 +187,7 @@ module Contrast
|
|
185
187
|
when Enumerable
|
186
188
|
idx = 0
|
187
189
|
res = {}
|
188
|
-
while idx < val.
|
190
|
+
while idx < val.length
|
189
191
|
res.merge! normalize_params(val[idx], prefix: "#{ prefix }[#{ idx }]")
|
190
192
|
idx += 1
|
191
193
|
end
|
@@ -131,8 +131,10 @@ module Contrast
|
|
131
131
|
handle_protect_state(service_response)
|
132
132
|
ia = service_response.input_analysis
|
133
133
|
if ia
|
134
|
-
logger.trace
|
135
|
-
|
134
|
+
if logger.trace?
|
135
|
+
logger.trace('Analysis from Contrast Service', evaluations: ia.results.length)
|
136
|
+
logger.trace('Results', input_analysis: ia.inspect)
|
137
|
+
end
|
136
138
|
@speedracer_input_analysis = ia
|
137
139
|
speedracer_input_analysis.request = request
|
138
140
|
else
|
@@ -202,7 +204,10 @@ module Contrast
|
|
202
204
|
rule = ::Contrast::PROTECT.rule(rule_id)
|
203
205
|
next unless rule
|
204
206
|
|
205
|
-
logger.debug
|
207
|
+
if logger.debug?
|
208
|
+
logger.debug('Building attack result from Contrast Service input analysis result',
|
209
|
+
result: ia_result.inspect)
|
210
|
+
end
|
206
211
|
|
207
212
|
attack_result = if rule.mode == :BLOCK
|
208
213
|
# special case for rules (like reflected xss) that used to have an infilter / block mode
|
data/lib/contrast/agent/scope.rb
CHANGED
@@ -104,39 +104,51 @@ module Contrast
|
|
104
104
|
exit_split_scope!
|
105
105
|
end
|
106
106
|
|
107
|
-
#
|
108
|
-
#
|
109
|
-
# Prefer the static methods if you know what scope you need at the call site.
|
107
|
+
# Static methods to be used, the cases are defined by the usage from the above methods
|
108
|
+
# if more methods are added - please extend the case statements as they are no longed dynamic
|
110
109
|
def in_scope? name
|
111
|
-
|
112
|
-
|
113
|
-
|
110
|
+
case name
|
111
|
+
when :contrast
|
112
|
+
in_contrast_scope?
|
113
|
+
when :deserialization
|
114
|
+
in_deserialization_scope?
|
115
|
+
when :split
|
116
|
+
in_split_scope?
|
117
|
+
else
|
118
|
+
raise NoMethodError, "Scope '#{ name.inspect }' is not registered as a scope."
|
119
|
+
end
|
114
120
|
end
|
115
121
|
|
116
122
|
def enter_scope! name
|
117
|
-
|
118
|
-
|
119
|
-
|
123
|
+
case name
|
124
|
+
when :contrast
|
125
|
+
enter_contrast_scope!
|
126
|
+
when :deserialization
|
127
|
+
enter_deserialization_scope!
|
128
|
+
when :split
|
129
|
+
enter_split_scope!
|
130
|
+
else
|
131
|
+
raise NoMethodError, "Scope '#{ name.inspect }' is not registered as a scope."
|
132
|
+
end
|
120
133
|
end
|
121
134
|
|
122
135
|
def exit_scope! name
|
123
|
-
|
124
|
-
|
125
|
-
|
136
|
+
case name
|
137
|
+
when :contrast
|
138
|
+
exit_contrast_scope!
|
139
|
+
when :deserialization
|
140
|
+
exit_deserialization_scope!
|
141
|
+
when :split
|
142
|
+
exit_split_scope!
|
143
|
+
else
|
144
|
+
raise NoMethodError, "Scope '#{ name.inspect }' is not registered as a scope."
|
145
|
+
end
|
126
146
|
end
|
127
147
|
|
128
148
|
class << self
|
129
149
|
def valid_scope? scope_sym
|
130
150
|
Contrast::Agent::Scope::SCOPE_LIST.include? scope_sym
|
131
151
|
end
|
132
|
-
|
133
|
-
def ensure_valid_scope! scope_sym
|
134
|
-
unless valid_scope? scope_sym # rubocop:disable Style/GuardClause
|
135
|
-
with_contrast_scope do
|
136
|
-
raise NoMethodError, "Scope '#{ scope_sym.inspect }' is not registered as a scope."
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|
140
152
|
end
|
141
153
|
end
|
142
154
|
end
|
@@ -27,14 +27,22 @@ module Contrast
|
|
27
27
|
|
28
28
|
private
|
29
29
|
|
30
|
+
# Use the TracePoint from the :end event, meaning the completion of a definition of a Class or Module (or
|
31
|
+
# really the completion of that piece of a definition, as determined by an `end` statement since there could be
|
32
|
+
# definitions across multiple files) to carry out actions required on definition. This typically involves
|
33
|
+
# patching and usage analysis
|
34
|
+
#
|
35
|
+
# @param tracepoint_event [TracePoint] the TracePoint from the :end
|
30
36
|
def process tracepoint_event
|
31
37
|
with_contrast_scope do
|
32
|
-
|
33
|
-
|
38
|
+
# the Module or Class that was loaded during this event
|
34
39
|
loaded_module = tracepoint_event.self
|
40
|
+
# the file being loaded that contained this definition
|
35
41
|
path = tracepoint_event.path
|
36
42
|
return if path&.include?('contrast')
|
37
43
|
|
44
|
+
logger.trace('Received TracePoint end event', module: loaded_module, path: path)
|
45
|
+
|
38
46
|
Contrast::Agent.framework_manager.register_late_framework(loaded_module)
|
39
47
|
Contrast::Agent::Inventory::DependencyUsageAnalysis.instance.associate_file(path) if path
|
40
48
|
Contrast::Agent::Patching::Policy::Patcher.patch_specific_module(loaded_module)
|
@@ -43,7 +51,7 @@ module Contrast
|
|
43
51
|
end
|
44
52
|
Contrast::Agent::Assess::Policy::PolicyScanner.scan(tracepoint_event)
|
45
53
|
rescue StandardError => e
|
46
|
-
logger.error('Unable to complete TracePoint analysis', e, module: loaded_module)
|
54
|
+
logger.error('Unable to complete TracePoint analysis', e, module: loaded_module, path: path)
|
47
55
|
end
|
48
56
|
end
|
49
57
|
end
|
@@ -3,11 +3,13 @@
|
|
3
3
|
|
4
4
|
require 'contrast/extension/module'
|
5
5
|
require 'contrast/utils/object_share'
|
6
|
+
require 'contrast/utils/lru_cache'
|
6
7
|
|
7
8
|
module Contrast
|
8
9
|
module Utils
|
9
10
|
# Utility methods for exploring the complete space of Objects
|
10
11
|
class ClassUtil
|
12
|
+
@lru_cache = LRUCache.new
|
11
13
|
class << self
|
12
14
|
# some classes have had things prepended to them, like Marshal in Rails
|
13
15
|
# 5 and higher. Their ActiveSupport::MarshalWithAutoloading will break
|
@@ -47,27 +49,32 @@ module Contrast
|
|
47
49
|
# @param object [Object, nil] the entity to convert to a String
|
48
50
|
# @return [String] the human readable form of the String, as defined by
|
49
51
|
# https://bitbucket.org/contrastsecurity/assess-specifications/src/master/vulnerability/capture-snapshot.md
|
52
|
+
|
50
53
|
def to_contrast_string object
|
51
|
-
#
|
54
|
+
# After implementing the LRU Cache, we firstly need to check if already had that object cached
|
55
|
+
# and if we have it - we can return it directly
|
56
|
+
return @lru_cache[object.__id__] if @lru_cache.key? object.__id__
|
57
|
+
|
58
|
+
# Only treat object like a string if it actually is a string+
|
52
59
|
# some subclasses of String override string methods we depend on
|
53
|
-
if object.cs__class == String
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
60
|
+
@lru_cache[object.__id__] = if object.cs__class == String
|
61
|
+
cached = to_cached_string(object)
|
62
|
+
return cached if cached
|
63
|
+
|
64
|
+
object.dup
|
65
|
+
elsif object.nil?
|
66
|
+
Contrast::Utils::ObjectShare::NIL_STRING
|
67
|
+
elsif object.cs__is_a?(Symbol)
|
68
|
+
":#{ object }"
|
69
|
+
elsif object.cs__is_a?(Module) || object.cs__is_a?(Class)
|
70
|
+
"#{ object.cs__name }@#{ object.__id__ }"
|
71
|
+
elsif object.cs__is_a?(Regexp)
|
72
|
+
object.source
|
73
|
+
elsif use_to_s?(object)
|
74
|
+
object.to_s
|
75
|
+
else
|
76
|
+
"#{ object.cs__class.cs__name }@#{ object.__id__ }"
|
77
|
+
end
|
71
78
|
end
|
72
79
|
|
73
80
|
# The method const_defined? can cause autoload, which is bad for us.
|
@@ -9,40 +9,48 @@ module Contrast
|
|
9
9
|
module IOUtil
|
10
10
|
extend Contrast::Components::Logger::InstanceMethods
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
#
|
42
|
-
#
|
43
|
-
|
44
|
-
|
45
|
-
|
12
|
+
class << self
|
13
|
+
# We're only going to call rewind on things that we believe are safe to
|
14
|
+
# call it on. This method white lists those cases and returns false in
|
15
|
+
# all others.
|
16
|
+
def should_rewind? potential_io
|
17
|
+
return true if potential_io.is_a?(StringIO)
|
18
|
+
return false unless io?(potential_io)
|
19
|
+
|
20
|
+
should_rewind_io?(potential_io)
|
21
|
+
rescue StandardError => e
|
22
|
+
logger.debug('Encountered an issue determining if rewindable', e, module: potential_io.cs__class.cs__name)
|
23
|
+
false
|
24
|
+
end
|
25
|
+
|
26
|
+
# A class is IO if it is a decedent or delegate of IO
|
27
|
+
def io? object
|
28
|
+
return true if object.is_a?(IO)
|
29
|
+
|
30
|
+
# DelegateClass, which is a Delegator, defines __getobj__ as a way to
|
31
|
+
# get the object that the class wraps around (delegates to)
|
32
|
+
return false unless object.is_a?(Delegator)
|
33
|
+
|
34
|
+
object.__getobj__.is_a?(IO)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
# IO rewind cannot be used with streams such as pipes, ttys, and sockets or for ones which have been closed.
|
40
|
+
#
|
41
|
+
# @param io [IO] the input to check for the ability to rewind
|
42
|
+
# @return [Boolean] if the given IO can be rewound
|
43
|
+
def should_rewind_io? io
|
44
|
+
return false if io.closed?
|
45
|
+
return false if io.tty?
|
46
|
+
|
47
|
+
status = io.stat
|
48
|
+
return false unless status
|
49
|
+
return false if status.pipe?
|
50
|
+
return false if status.socket?
|
51
|
+
|
52
|
+
true
|
53
|
+
end
|
46
54
|
end
|
47
55
|
end
|
48
56
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'contrast/components/logger'
|
5
|
+
|
6
|
+
module Contrast
|
7
|
+
module Utils
|
8
|
+
# A LRU(Least Recently Used) Cache store.
|
9
|
+
class LRUCache
|
10
|
+
def initialize capacity = 500
|
11
|
+
raise StandardError 'Capacity must be bigger than 0' if capacity <= 0
|
12
|
+
|
13
|
+
@capacity = capacity
|
14
|
+
@cache = {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def [] key
|
18
|
+
val = @cache.delete(key)
|
19
|
+
@cache[key] = val if val
|
20
|
+
val
|
21
|
+
end
|
22
|
+
|
23
|
+
def []= key, value
|
24
|
+
@cache.delete(key)
|
25
|
+
@cache[key] = value
|
26
|
+
@cache.shift if @cache.size > @capacity
|
27
|
+
value # rubocop:disable Lint/Void
|
28
|
+
end
|
29
|
+
|
30
|
+
def keys
|
31
|
+
@cache.keys
|
32
|
+
end
|
33
|
+
|
34
|
+
def key? key
|
35
|
+
@cache.key?(key)
|
36
|
+
end
|
37
|
+
|
38
|
+
def values
|
39
|
+
@cache.values
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -38,7 +38,7 @@ module Contrast
|
|
38
38
|
return if node.children.all? { |child_node| child_node.type == :str }
|
39
39
|
new_content = +'('
|
40
40
|
idx = 0
|
41
|
-
while idx < node.children.
|
41
|
+
while idx < node.children.length
|
42
42
|
#node.children.each_with_index do |child_node, index|
|
43
43
|
child_node = node.children[idx]
|
44
44
|
# A begin node looks like #{some_code} in ruby, we do a substring
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: contrast-agent
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- galen.palmer@contrastsecurity.com
|
@@ -13,7 +13,7 @@ authors:
|
|
13
13
|
autorequire:
|
14
14
|
bindir: exe
|
15
15
|
cert_chain: []
|
16
|
-
date: 2021-
|
16
|
+
date: 2021-09-23 00:00:00.000000000 Z
|
17
17
|
dependencies:
|
18
18
|
- !ruby/object:Gem::Dependency
|
19
19
|
name: bundler
|
@@ -617,20 +617,20 @@ executables:
|
|
617
617
|
- contrast_service
|
618
618
|
extensions:
|
619
619
|
- ext/cs__common/extconf.rb
|
620
|
-
- ext/
|
621
|
-
- ext/cs__assess_marshal_module/extconf.rb
|
622
|
-
- ext/cs__assess_kernel/extconf.rb
|
623
|
-
- ext/cs__assess_basic_object/extconf.rb
|
624
|
-
- ext/cs__assess_string/extconf.rb
|
620
|
+
- ext/cs__assess_array/extconf.rb
|
625
621
|
- ext/cs__assess_regexp/extconf.rb
|
626
622
|
- ext/cs__protect_kernel/extconf.rb
|
623
|
+
- ext/cs__assess_marshal_module/extconf.rb
|
624
|
+
- ext/cs__assess_yield_track/extconf.rb
|
625
|
+
- ext/cs__assess_string_interpolation26/extconf.rb
|
626
|
+
- ext/cs__assess_fiber_track/extconf.rb
|
627
|
+
- ext/cs__assess_string/extconf.rb
|
628
|
+
- ext/cs__assess_hash/extconf.rb
|
629
|
+
- ext/cs__assess_kernel/extconf.rb
|
627
630
|
- ext/cs__contrast_patch/extconf.rb
|
628
|
-
- ext/
|
631
|
+
- ext/cs__assess_basic_object/extconf.rb
|
629
632
|
- ext/cs__assess_module/extconf.rb
|
630
|
-
- ext/
|
631
|
-
- ext/cs__assess_string_interpolation26/extconf.rb
|
632
|
-
- ext/cs__assess_array/extconf.rb
|
633
|
-
- ext/cs__assess_yield_track/extconf.rb
|
633
|
+
- ext/cs__assess_active_record_named/extconf.rb
|
634
634
|
extra_rdoc_files: []
|
635
635
|
files:
|
636
636
|
- ".clang-format"
|
@@ -1079,6 +1079,7 @@ files:
|
|
1079
1079
|
- lib/contrast/utils/invalid_configuration_util.rb
|
1080
1080
|
- lib/contrast/utils/io_util.rb
|
1081
1081
|
- lib/contrast/utils/job_servers_running.rb
|
1082
|
+
- lib/contrast/utils/lru_cache.rb
|
1082
1083
|
- lib/contrast/utils/object_share.rb
|
1083
1084
|
- lib/contrast/utils/os.rb
|
1084
1085
|
- lib/contrast/utils/preflight_util.rb
|