contrast-agent 4.10.0 → 4.11.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|