contrast-agent 6.15.2 → 7.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a2f94b8a7a87febf8c10b58cf5133081a6dc3183c158ad59c202921efc23753e
4
- data.tar.gz: 2e3fff601596655f725a4bea7a8b6f309a5f702557cfb009ad82b1d424da8d40
3
+ metadata.gz: bc98145df7f08bc47cbff0f0416a7b43852b8075c6806bd38fbbe0aa27d94adb
4
+ data.tar.gz: 60885ba415f59b893a5da6101ddc3b9d6deeac5a9d41bb2eb7c459291873b08f
5
5
  SHA512:
6
- metadata.gz: cd0a28ee1a7331401a4709e1aec63a44b272d9d93ba9e6dcebd47270078165b42e3955fe8d938311b10cae4ec60cfaa92d9bee088b3a6056a2461fb00c6a4ab8
7
- data.tar.gz: ba7ab7bebd769fd3057533da348a260e208bb622fe50aab3d0e68f8709413579bac258588680f04a65aa68ff4f5dbf0a2038d56fde7fd2ef2892a095e0e8e388
6
+ metadata.gz: 4a6449786512d444818087fed5d880c061b1108b8e9fbe64e4fd0f3657bac3b53ffb60806a7767a50a9c7a910b5e62e223d6af84be51d8ca9b6e4e5b5ae67d07
7
+ data.tar.gz: 4f2cb9c1435fbe5fdfbccbc3cc69ba3823de97f617bcff63493087a70a0551852dbe09f7699089cd22dfc509e57c39525420290813cd12ac92ee91164e2910bc
@@ -62,7 +62,7 @@ VALUE rb_fiber_yield_hook(int argc, const VALUE *argv) {
62
62
  return rb_fiber_yield_original(argc, argv);
63
63
  }
64
64
 
65
- int install_fiber_hooks() {
65
+ int install_fiber_hooks(void) {
66
66
  rb_fiber_new_original = rb_fiber_new;
67
67
  patch_via_funchook(&rb_fiber_new_original, &rb_fiber_new_hook);
68
68
 
@@ -28,6 +28,6 @@ VALUE rb_fiber_new_hook(VALUE (*func)(ANYARGS), VALUE obj);
28
28
 
29
29
  VALUE rb_fiber_yield_hook(int argc, const VALUE *argv);
30
30
 
31
- static int install_fiber_hooks();
31
+ static int install_fiber_hooks(void);
32
32
 
33
33
  void Init_cs__assess_fiber_track(void);
@@ -115,23 +115,4 @@ void Init_cs__assess_module(void) {
115
115
 
116
116
  contrast_register_patch("Module", "module_eval",
117
117
  contrast_assess_module_module_eval);
118
- /*
119
- * We patch these for better ancestors handling, and only for older ruby
120
- * versions.
121
- */
122
- // if (rb_ver_below_three()) {
123
- /*
124
- * `included` is a private method. We should make it public, patch it,
125
- * and make our new method public
126
- */
127
- // contrast_register_patch("Module", "included",
128
- // contrast_assess_module_included);
129
- /*
130
- * The `prepend` patch may actually be the issue, if we're not properly
131
- * passing along the call/context. It could be that my attempt to fix
132
- * `included` left this section unreachable.
133
- */
134
- // contrast_register_patch("Module", "prepend",
135
- // contrast_assess_module_prepend);
136
- // }
137
118
  }
@@ -1,4 +1,4 @@
1
- #include "../cs__common/cs__common.h";
1
+ #include "../cs__common/cs__common.h"
2
2
  #include "ruby.h"
3
3
  #include <ruby/re.h>
4
4
 
@@ -28,8 +28,12 @@ void patch_via_funchook(void *original_function, void *hook_function) {
28
28
 
29
29
  void *funchook_lib_handle;
30
30
  void *funchook_reference, *(*funchook_create)(void);
31
+ /* This variables are used to load the funchook dylib */
32
+ #pragma GCC diagnostic ignored "-Wunused-but-set-variable"
33
+ #pragma GCC diagnostic push
31
34
  int prepareResult, (*funchook_prepare)(void *, void **, void *);
32
35
  int installResult, (*funchook_install)(void *, int);
36
+ #pragma GCC diagnostic pop
33
37
 
34
38
  funchook_lib_handle =
35
39
  dlopen(StringValueCStr(funchook_path), RTLD_NOW | RTLD_GLOBAL);
@@ -55,7 +59,7 @@ void contrast_alias_method(const VALUE target, const char *to,
55
59
  ID2SYM(rb_intern(to)), ID2SYM(rb_intern(from)));
56
60
  }
57
61
 
58
- VALUE contrast_patcher() {
62
+ VALUE contrast_patcher(void) {
59
63
  return patcher;
60
64
  }
61
65
 
@@ -102,7 +106,7 @@ VALUE contrast_check_and_register_instance_patch(const char *module_name,
102
106
  VALUE(c_fn)(const int, VALUE *,
103
107
  const VALUE)) {
104
108
 
105
- VALUE object, method, is_prepended, patch_type;
109
+ VALUE object, method, is_prepended;
106
110
  /* check if method is prepended */
107
111
  object = rb_const_get(rb_cObject, rb_intern(module_name));
108
112
  method = ID2SYM(rb_intern(method_name));
@@ -119,7 +123,7 @@ VALUE contrast_check_and_register_instance_patch(const char *module_name,
119
123
  }
120
124
  }
121
125
 
122
- static VALUE
126
+ VALUE
123
127
  _contrast_register_patch(const char *module_name, const char *method_name,
124
128
  VALUE(c_fn)(const int, VALUE *, const VALUE),
125
129
  patch_impl patch) {
@@ -175,13 +179,6 @@ _contrast_register_patch(const char *module_name, const char *method_name,
175
179
  return SYM2ID(underlying_method_name);
176
180
  }
177
181
 
178
- int rb_ver_below_three() {
179
- int ruby_version =
180
- FIX2INT(rb_funcall(rb_const_get(rb_cObject, rb_intern("RUBY_VERSION")),
181
- rb_intern("to_i"), 0));
182
- return ruby_version < 3;
183
- }
184
-
185
182
  /* used for direct check on object: String.cs__prepended? *args */
186
183
  extern VALUE contrast_check_prepended(VALUE self, VALUE method_name,
187
184
  VALUE is_instance) {
@@ -200,17 +197,18 @@ extern VALUE contrast_lookout_prepended(VALUE self, VALUE object_name,
200
197
  return result;
201
198
  }
202
199
 
203
- static VALUE _contrast_check_prepended(VALUE object, VALUE method_name,
200
+ VALUE _contrast_check_prepended(VALUE object, VALUE method_name,
204
201
  VALUE is_instance) {
205
- VALUE entry, ancestors, object_idx, entry_methods;
202
+ VALUE entry, ancestors, entry_methods;
206
203
  VALUE result = Qfalse;
207
- int i;
208
- int y;
204
+ VALUE object_idx = Qnil;
205
+ long y;
206
+ unsigned long i;
209
207
 
210
208
  /* get self ancestors */
211
209
  ancestors = rb_mod_ancestors(object);
212
210
  /* get the size of the array */
213
- int length = RARRAY_LEN(ancestors);
211
+ unsigned long length = RARRAY_LEN(ancestors);
214
212
  /* Locate self in ancestors: */
215
213
  for (i = 0; i < length; ++i) {
216
214
  entry = rb_ary_entry(ancestors, i);
@@ -226,14 +224,14 @@ static VALUE _contrast_check_prepended(VALUE object, VALUE method_name,
226
224
  for (i = 0; i < object_idx; ++i) {
227
225
  entry = rb_ary_entry(ancestors, i);
228
226
  if (is_instance == Qtrue) {
229
- entry_methods = rb_class_instance_methods(1, entry, entry);
227
+ entry_methods = rb_class_instance_methods(1UL, &entry, entry);
230
228
  } else {
231
- entry_methods = rb_obj_singleton_methods(1, entry, entry);
229
+ entry_methods = rb_obj_singleton_methods(1UL, &entry, entry);
232
230
  }
233
231
 
234
232
  /* Loop through the instance/singleton methods of the prepended modules
235
233
  */
236
- int entry_methods_length = RARRAY_LEN(entry_methods);
234
+ long entry_methods_length = RARRAY_LEN(entry_methods);
237
235
  for (y = 0; y <= entry_methods_length; ++y) {
238
236
  if (rb_ary_entry(entry_methods, y) == method_name) {
239
237
  result = Qtrue;
@@ -244,6 +242,7 @@ static VALUE _contrast_check_prepended(VALUE object, VALUE method_name,
244
242
  break;
245
243
  }
246
244
  }
245
+
247
246
  return result;
248
247
  }
249
248
 
@@ -10,6 +10,9 @@ typedef enum {
10
10
  IMPL_PREPEND_SINGLETON,
11
11
  } patch_impl;
12
12
 
13
+ /* the unused variable warning is triggered for gcc only */
14
+ #pragma GCC diagnostic ignored "-Wunused-variable"
15
+ #pragma GCC diagnostic push
13
16
  static VALUE cs__send_method;
14
17
  static VALUE cs__alias_method_sym;
15
18
 
@@ -34,14 +37,7 @@ static VALUE rb_sym_alias_instance;
34
37
  static VALUE rb_sym_alias_singleton;
35
38
  static VALUE rb_sym_prepend_instance;
36
39
  static VALUE rb_sym_prepend_singleton;
37
-
38
- /*
39
- * Check if ruby version is < 3.0.0.
40
- * We are using this for handling ancestors of included modules.
41
- * Since this is fixed after Ruby 3.0.0 we should remove this after
42
- * dropping support for older versions, as no longer needed.
43
- */
44
- int rb_ver_below_three();
40
+ #pragma GCC diagnostic pop
45
41
 
46
42
  void patch_via_funchook(void *original_function, void *hook_function);
47
43
 
@@ -73,11 +69,11 @@ VALUE contrast_register_prepend_patch(const char *module_name,
73
69
  VALUE(c_fn)(const int, VALUE *,
74
70
  const VALUE));
75
71
 
76
- static VALUE _contrast_register_patch(const char *module_name, const char *method_name,
72
+ VALUE _contrast_register_patch(const char *module_name, const char *method_name,
77
73
  VALUE(c_fn)(const int, VALUE *, const VALUE),
78
74
  patch_impl patch_impl);
79
75
 
80
- static VALUE _contrast_check_prepended(VALUE self, VALUE method_name, VALUE is_instance);
76
+ VALUE _contrast_check_prepended(VALUE self, VALUE method_name, VALUE is_instance);
81
77
 
82
78
  extern VALUE contrast_check_prepended(VALUE self, VALUE method_name, VALUE is_instance);
83
79
 
@@ -90,7 +86,7 @@ VALUE contrast_check_and_register_instance_patch(const char *module_name,
90
86
  VALUE(c_fn)(const int, VALUE *,
91
87
  const VALUE));
92
88
 
93
- VALUE contrast_patcher();
89
+ VALUE contrast_patcher(void);
94
90
 
95
91
  void Init_cs__common(void);
96
92
 
@@ -97,8 +97,6 @@ VALUE rescue_func(VALUE arg1) {
97
97
  */
98
98
  exception = rb_errinfo();
99
99
  rb_exc_raise(exception);
100
-
101
- return Qnil;
102
100
  }
103
101
 
104
102
  /**
@@ -109,17 +107,18 @@ VALUE rescue_func(VALUE arg1) {
109
107
  *
110
108
  **/
111
109
  VALUE contrast_patch_call_ensure(const VALUE *args) {
112
- // we do not need to ensure that post patch is called if no error was thrown
110
+ /* we do not need to ensure that post patch is called if no error was thrown */
113
111
  if (!RTEST(rb_errinfo())) {
114
112
  return Qnil;
115
113
  }
116
114
 
117
115
  int argc;
118
- VALUE object, preshift, method_policy, method;
116
+ VALUE object, preshift, method_policy;
119
117
  VALUE *argv;
118
+ /* VALUE method; */
120
119
 
121
120
  object = args[0];
122
- method = args[1];
121
+ /* method = args[1]; */
123
122
  argc = NUM2INT(args[2]);
124
123
  argv = (VALUE *)args[3];
125
124
  method_policy = args[4];
@@ -137,8 +136,8 @@ VALUE ensure_wrapper(const VALUE *args) {
137
136
  original_args = (VALUE)args[1];
138
137
  ensure_args = (VALUE)args[2];
139
138
 
140
- // this ensure if being treated as a rescue due to issues surrounding
141
- // Kernel#throw
139
+ /* this ensure if being treated as a rescue due to issues surrounding
140
+ Kernel#throw */
142
141
  return rb_ensure(original_method, original_args, contrast_patch_call_ensure,
143
142
  (VALUE)ensure_args);
144
143
  }
@@ -154,7 +153,7 @@ VALUE contrast_call_super(const VALUE *args) {
154
153
 
155
154
  VALUE contrast_run_patches(const VALUE *wrapped_args) {
156
155
  VALUE impl, method, method_policy, object, original_args, original_ret,
157
- preshift, transformed_ret;
156
+ preshift;
158
157
  int argc;
159
158
  VALUE *argv;
160
159
  VALUE ensure_args[6];
@@ -257,9 +256,15 @@ VALUE contrast_ensure_function(const VALUE method_policy) {
257
256
 
258
257
  VALUE contrast_patch_dispatch(const int argc, const VALUE *argv,
259
258
  const patch_impl impl, const VALUE object) {
259
+ /*
260
+ * Silence the known variable unused warning detected by compiler.
261
+ * Since this Variable is set by cases and we check if it is set or not.
262
+ * To disalbe this remove the -Wno-maybe-uninitialized flag.
263
+ */
264
+
260
265
  VALUE cs__method, known, method, method_policy;
261
266
  VALUE original_args[4];
262
- int do_contrast, nested_scope;
267
+ long do_contrast, nested_scope;
263
268
 
264
269
  /* Do Contrast analysis, unless our subsequent checks tell us no. */
265
270
  do_contrast = 1;
@@ -369,6 +374,8 @@ call_original:
369
374
  case IMPL_PREPEND_SINGLETON:
370
375
  return contrast_call_super(original_args);
371
376
  };
377
+
378
+ return Qfalse;
372
379
  }
373
380
 
374
381
  VALUE contrast_alias_instance_patch(const int argc, const VALUE *argv,
@@ -490,21 +497,6 @@ VALUE contrast_patch_prepend(const VALUE self, const VALUE originalModule,
490
497
  }
491
498
  rb_prepend_module(originalModule, module);
492
499
 
493
- if (rb_ver_below_three()) {
494
- VALUE module_at;
495
- VALUE rb_incl_in_mod_ary =
496
- rb_funcall(originalModule, rb_intern("included_in"), 0);
497
- if (RB_TYPE_P(rb_incl_in_mod_ary, T_ARRAY)) {
498
- int i = 0;
499
- int size = RARRAY_LEN(rb_incl_in_mod_ary);
500
- for (i = 0; i < size; ++i) {
501
- module_at = rb_ary_entry(rb_incl_in_mod_ary, i);
502
- if (RB_TYPE_P(module_at, T_MODULE)) {
503
- rb_include_module(module_at, module);
504
- }
505
- }
506
- }
507
- }
508
500
  return Qtrue;
509
501
  }
510
502
 
@@ -2,18 +2,97 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'mkmf'
5
+ require 'rbconfig'
5
6
  require_relative '../lib/contrast/agent/version'
6
7
 
8
+ # The mkmf.rb file uses all passed flags from Ruby configuration (RbConfig::CONFIG) on
9
+ # Ruby build time. Problem with Clang and GCC is that it do not keep up with c89 and finds
10
+ # error on including <ryby.h> as not allowing inline variables.
11
+ #
12
+ # Ruby inlining is a C99 feature that is allowed to be used, because the Ruby configure script
13
+ # can work around the absence of the inline feature with a simple #define:
14
+ #
15
+ # ifndef __cplusplus
16
+ # define inline
17
+ # endif
18
+ #
19
+ # There is difference between using c89 and gnu89, as the latter is extended version of the
20
+ # 1989 standard allowing features like // comments for example. This makes the use of the
21
+ # gnu not favorable since it will skip some checks and would make wholes in the c89 standard
22
+ # support.
23
+ #
24
+ # We can directly append the CFLAGS we need with ENV variable used to create the makefile.
25
+ # MAKEFILE_CONFIG is extension of the RbConfig::CONFIG used to build the Ruby itself.
26
+ # So if we try to run c89 on clang it will brake because of detecting errors from external
27
+ # library used - Ruby itself build with different standard as it seems. This means the
28
+ # Ruby must be compiled beforehand with the compiler forced to C89.
29
+ #
30
+ # This makes the C dialect of choice to be gnu89 with strict pedantic warnings reported as errors,
31
+ # and making the compiler configurable by flags:
32
+ STANDARD_FLAGS = '-std=gnu89'
33
+ CLANG = 'clang'
34
+
35
+ # TODO: RUBY-999999 Add -pedantic flag, remove all warning flags and see to it that as many as possible become obsolete.
36
+ # Note: Adding -pedantic could raise <ruby.h> warnings, and we are not in control of that code.
37
+ # e.g. error: '_Bool' is a C99 extension [-Werror,-Wc99-extensions] ; empty macros and etc.
38
+ #
39
+ # -Wno-int-conversion => Passing VALUEs as function args but required as unsigned long parameters.
40
+ # -Werror => report all warnings as errors
41
+ # -Wshorten-64-to-32 => is recognized by clang but not in gcc.
42
+ # Use alternative if viable. [Wno-narrowing]
43
+ # -Wno-maybe-uninitialized is used by clang but not gcc
44
+ #
45
+ # Note: Clang supports old style function definition e.g. void func () {}
46
+ # but the gcc is not.
47
+ # make sure to add parameters type => void func (void) {}.
48
+ # All Changes must be tested against both clang and gcc.
49
+ WARNING_FLAGS = %w[
50
+ -Wno-language-extension-token -Wno-incompatible-function-pointer-types
51
+ -Wno-declaration-after-statement -Wno-variadic-macros -Wno-int-conversion
52
+ -Wno-incompatible-pointer-types -Wno-narrowing
53
+ ].freeze # rubocop:disable Security/Object/Freeze
54
+
55
+ # Flags that are only recognized by gcc:
56
+ GCC_FLAGS = %w[-Wno-maybe-uninitialized].freeze # rubocop:disable Security/Object/Freeze
57
+
58
+ # Extend $CFLAGS passed directly to compiler in ruby mkmf
59
+ def extend_cflags
60
+ $CFLAGS += " #{ [STANDARD_FLAGS, WARNING_FLAGS].flatten.join(' ') }"
61
+ # Extend with GCC specific flags:
62
+ unless RbConfig::MAKEFILE_CONFIG['CC'].downcase.include?(CLANG) ||
63
+ RbConfig::MAKEFILE_CONFIG['CPP'].downcase.include?(CLANG) ||
64
+ RbConfig::CONFIG['CC'].downcase.include?(CLANG)
65
+
66
+ $CFLAGS += " #{ GCC_FLAGS.flatten.join(' ') }"
67
+ end
68
+ end
69
+
7
70
  def make!
8
71
  create_makefile("#{ $TO_MAKE }/#{ $TO_MAKE }")
9
72
  end
10
73
 
74
+ # -----------------------------------------------------------------------
75
+ # | MOVING CODE BELLOW THIS SECTION MAY BRAKE MAKEFILE. ORDER MATTERS! |
76
+ # ----------------------------------------------------------------------
77
+
11
78
  def ext_path
12
79
  # __dir__ is relative to the file you're reading.
13
80
  # this file you're reading is presently within $APP_ROOT/ext/.
14
81
  __dir__
15
82
  end
16
83
 
84
+ # We need to first build funchook which relies on ext_path method. This enables the require of
85
+ # funchook.h file. Then we can pass CFLAGS and extend makefile flags and invoke make!
17
86
  require_relative './build_funchook'
18
87
 
88
+ # Extended flags are mainly tested with clang and gcc. Experience with other compilers may vary.
89
+ # To that end if something brakes on client side we must have a mechanism to go back to previous
90
+ # non strict gnu89 standard and be able to maintain the build.
91
+ # We can disable newly added changes with this setting CONTRAST_USE_C89=false.
92
+ extend_cflags unless ENV['CONTRAST__USE_GNU89'] == 'false'
93
+
94
+ # use same C compiler if set.
95
+ RbConfig::CONFIG['CC'] = RbConfig::MAKEFILE_CONFIG['CC'] = ENV['CC'] if ENV['CC']
96
+
97
+ # Generate Makefile.
19
98
  make!
@@ -91,6 +91,7 @@ module Contrast
91
91
  process_source(source_node, value, source_data, source_type, source_name, *args)
92
92
  end
93
93
  end
94
+ nil
94
95
  rescue StandardError => e
95
96
  logger.warn('Unable to apply source', e, node_id: source_node.id)
96
97
  end
@@ -33,8 +33,8 @@ module Contrast
33
33
  # Parse the given controller and route from a Rack based application framework in order to create an instance
34
34
  # of this class
35
35
  #
36
- # @param final_controller [Grape::API, Sinatra::Base] the controller responsible for the definition of the
37
- # entrypoint of the route actively being executed
36
+ # @param final_controller [Class<Grape::API>, Class<Sinatra::Base>] the controller responsible for the
37
+ # definition of the entrypoint of the route actively being executed
38
38
  # @param method [String] the HTTP request method of the route actively being executed
39
39
  # @param route_pattern [Grape::Router::Route, Mustermann::Sinatra] the pattern to which the url maps
40
40
  # @param url [String] the literal url of the route actively being executed
@@ -32,7 +32,8 @@ module Contrast
32
32
  FORBIDDEN_NO_ACTION_MSG = 'Report access was forbidden because the supplied credentials failed ' \
33
33
  'to authenticate the Agent'
34
34
  UNPROCESSABLE_ENTITY_MSG = 'Reporter received Unprocessable Entity response. Disabling permanently.'
35
- RETRY_AFTER_MSG = "There are too many requests of this type being sent by this Agent. #{ SUSPEND_MSG }"
35
+ RETRY_AFTER_MSG = 'There are too many requests of this type being sent by this Agent. ' \
36
+ "#{ SUSPEND_MSG }".cs__freeze
36
37
 
37
38
  def last_response_code
38
39
  @_last_response_code ||= ''
@@ -135,6 +135,8 @@ module Contrast
135
135
  @observed_route = Contrast::Agent::Reporting::ObservedRoute.new
136
136
  reporting_route = Contrast::Agent.framework_manager.get_route_information(@request)
137
137
  append_to_observed_route(reporting_route)
138
+ rescue StandardError => e
139
+ logger.error('Unable to determine current route', e)
138
140
  end
139
141
  end
140
142
  end
@@ -3,6 +3,6 @@
3
3
 
4
4
  module Contrast
5
5
  module Agent
6
- VERSION = '6.15.2'
6
+ VERSION = '7.0.0'
7
7
  end
8
8
  end
@@ -18,7 +18,7 @@ module Contrast
18
18
  include Contrast::Config::BaseConfiguration
19
19
 
20
20
  CANON_NAME = 'api'
21
- PROXY_NAME = "#{ CANON_NAME }.proxy"
21
+ PROXY_NAME = "#{ CANON_NAME }.proxy".cs__freeze
22
22
  CONFIG_VALUES = %w[api_key user_name service_key url].cs__freeze
23
23
 
24
24
  # @return [String]
@@ -16,7 +16,7 @@ module Contrast
16
16
 
17
17
  SPEC_KEY = :disabled_rules.cs__freeze
18
18
  CANON_NAME = 'assess.rules'
19
- NAME_PREFIX = "#{ CONTRAST }.#{ CANON_NAME }"
19
+ NAME_PREFIX = "#{ CONTRAST }.#{ CANON_NAME }".cs__freeze
20
20
 
21
21
  # @return [Array, nil] list of disabled assess rules
22
22
  attr_accessor :disabled_rules
@@ -103,7 +103,7 @@ module Contrast
103
103
  include Contrast::Config::BaseConfiguration
104
104
 
105
105
  CANON_NAME = 'assess.sampling'
106
- NAME_PREFIX = "#{ CONTRAST }.#{ CANON_NAME }"
106
+ NAME_PREFIX = "#{ CONTRAST }.#{ CANON_NAME }".cs__freeze
107
107
  CONFIG_VALUES = %w[enable baseline request_frequency response_frequency window_ms].cs__freeze
108
108
 
109
109
  # @return [Integer, nil]
@@ -67,30 +67,39 @@ module Contrast
67
67
  # Given the current request - return a RouteCoverage object
68
68
 
69
69
  # @param request [Contrast::Agent::Request] a contrast tracked request.
70
- # @param controller [::Sinatra::Base] optionally use this controller instead of global ::Sinatra::Base.
70
+ # @param _controller [::Sinatra::Base] optionally use this controller instead of global ::Sinatra::Base.
71
71
  # @return [Contrast::Agent::Reporting::RouteCoverage, nil] a Dtm describing the route
72
72
  # matched to the request if a match was found.
73
- def current_route_coverage request, controller = ::Sinatra::Base, full_route = nil
74
- return unless sinatra_controller?(controller)
75
-
73
+ def current_route_coverage request, _controller = ::Sinatra::Base, full_route = nil
76
74
  method = request.env[::Rack::REQUEST_METHOD] # GET, PUT, POST, etc...
77
-
75
+ route = _cleaned_route(request)
78
76
  # Find route match--checking superclasses if necessary.
79
- final_controller, route_pattern = _route_recurse(controller, method, _cleaned_route(request))
80
- return unless final_controller && route_pattern
77
+ sinatra_controllers.each do |potential_controller|
78
+ next unless sinatra_controller?(potential_controller)
79
+
80
+ next if potential_controller.nil? || potential_controller.cs__class == NilClass
81
81
 
82
- full_route ||= request.env[::Rack::PATH_INFO]
82
+ route_patterns = potential_controller.routes.fetch(method) { [] }.
83
+ map(&:first)
84
+ route_pattern = route_patterns.find do |matcher|
85
+ matcher.params(route) # ::Mustermann::Sinatra match.
86
+ end
87
+ next unless route_pattern
83
88
 
84
- new_route_coverage = Contrast::Agent::Reporting::RouteCoverage.new
85
- new_route_coverage.attach_rack_based_data(final_controller, method, route_pattern, full_route)
86
- new_route_coverage
89
+ full_route ||= request.env[::Rack::PATH_INFO]
90
+ new_route_coverage = Contrast::Agent::Reporting::RouteCoverage.new
91
+ new_route_coverage.attach_rack_based_data(potential_controller, method, route_pattern, full_route)
92
+ return new_route_coverage
93
+ end
94
+ nil
87
95
  end
88
96
 
89
97
  # Search object space for sinatra controllers--any class that subclasses ::Sinatra::Base.
90
98
  #
91
- # @return [Array<::Sinatra::Base>] sinatra controlelrs
99
+ # @return [Array<Class<::Sinatra::Base>>] sinatra controlelrs
92
100
  def sinatra_controllers
93
- [::Sinatra::Base] + ObjectSpace.each_object(Class).select { |clazz| sinatra_controller?(clazz) }
101
+ @_sinatra_controllers ||=
102
+ [::Sinatra::Base] + ObjectSpace.each_object(Class).select { |clazz| sinatra_controller?(clazz) }
94
103
  end
95
104
 
96
105
  def retrieve_request env
@@ -112,31 +121,6 @@ module Contrast
112
121
 
113
122
  private
114
123
 
115
- # Given a controller and a route to match against, find the route_pattern and class that will serve the
116
- # route. This is recursive as Sinatra's routing is recursive from subclass to super.
117
- #
118
- # @param controller [Sinatra::Base, #routes] a Sinatra application.
119
- # @param method [::Rack::REQUEST_METHOD] GET, POST, PUT, etc...
120
- # @param route [String] the relative route passed from Rack.
121
- # @return [Array[Sinatra::Base, Mustermann::Sinatra], nil] Either the controller that
122
- # will handle the route along with the route pattern or nil if no match.
123
- def _route_recurse controller, method, route
124
- return if controller.nil? || controller.cs__class == NilClass
125
-
126
- route_patterns = controller.routes.fetch(method) { [] }.
127
- map(&:first)
128
- route_pattern = route_patterns&.find do |matcher|
129
- matcher.params(route) # ::Mustermann::Sinatra match.
130
- end
131
-
132
- return controller, route_pattern if route_pattern
133
-
134
- # Check routes defined in superclass if present.
135
- return unless controller.superclass&.instance_variable_get(:@routes)
136
-
137
- _route_recurse(controller.superclass, method, route)
138
- end
139
-
140
124
  # Get route and do some cleanup matching that of Sinatra::Base#process_route.
141
125
  #
142
126
  # @param request [Contrast::Agent::Request] a contrast tracked request.
@@ -44,14 +44,15 @@ module Contrast
44
44
  update(route.signature)
45
45
  if (observation = route.observations[0])
46
46
  update(observation.verb)
47
+ else
48
+ update(request.request_method)
47
49
  end
48
- return
49
- end
50
-
51
- return unless request ||= context&.request
50
+ else
51
+ return unless request ||= context&.request
52
52
 
53
- update(request.normalized_uri) # the normalized URL used to access the method in the route.
54
- update(request.request_method) # The HTTP method used in the request
53
+ update(request.normalized_uri) # the normalized URL used to access the method in the route.
54
+ update(request.request_method)
55
+ end
55
56
  end
56
57
 
57
58
  # Update to CRC checksum the event source name and source type.
@@ -11,12 +11,12 @@ module Contrast
11
11
  module MiddlewareUtils
12
12
  private
13
13
 
14
- # TODO: RUBY-1609 update this part of the method for Ruby Version and Year
15
- LANGUAGE_DEPRECATION_VERSION = '2.7'
16
- LANGUAGE_DEPRECATION_YEAR = '2023'
14
+ LANGUAGE_DEPRECATION_VERSION = '3.0'
15
+ LANGUAGE_DEPRECATION_YEAR = '2024'
17
16
  LANGUAGE_DEPRECATION_WARNING =
18
17
  "[Contrast Security] [DEPRECATION] Support for Ruby #{ LANGUAGE_DEPRECATION_VERSION } will be removed in " \
19
- "April #{ LANGUAGE_DEPRECATION_YEAR }. Please contact Customer Support prior if you require continued support."
18
+ "April #{ LANGUAGE_DEPRECATION_YEAR }. Please contact Customer Support prior if you require continued" \
19
+ 'support.'.cs__freeze
20
20
 
21
21
  def setup_agent
22
22
  # Generate new config file if one is not already created:
@@ -55,9 +55,9 @@ module Contrast
55
55
  EMPTY_HASH = {}.freeze
56
56
 
57
57
  # RegExps
58
- DIGIT_REGEXP = /[[:digit:]]/.freeze
59
- WHITE_SPACE_REGEXP = /\s/.freeze
60
- NOT_WHITE_SPACE_REGEXP = /[^\s]/.freeze
58
+ DIGIT_REGEXP = /[[:digit:]]/
59
+ WHITE_SPACE_REGEXP = /\s/
60
+ NOT_WHITE_SPACE_REGEXP = /[^\s]/
61
61
 
62
62
  # Messages
63
63
  OVERRIDE_MESSAGE = 'A security filter prevented original response from being returned.'
data/lib/contrast.rb CHANGED
@@ -102,19 +102,3 @@ if RUBY_VERSION >= '3.0.0' && RUBY_VERSION < '3.1.0'
102
102
  Class.alias_method(:prepend, :cs__orig_prepend)
103
103
  Class.remove_method(:cs__orig_prepend)
104
104
  end
105
-
106
- if RUBY_VERSION < '3.0.0'
107
- # Better handles ancestors for older ruby versions.
108
- # This is called from C, tread lightly.
109
- class Module
110
- @_included_in = []
111
- # Returns array with modules including this instance
112
- def included_in
113
- @_included_in ||= [] unless cs__frozen?
114
- end
115
-
116
- def self.included_in
117
- @_included_in ||= [] unless cs__frozen?
118
- end
119
- end
120
- end
data/ruby-agent.gemspec CHANGED
@@ -51,7 +51,7 @@ end
51
51
  def self.add_frameworks spec
52
52
  spec.add_development_dependency 'grape', '~> 1.5', '>= 1.5.2'
53
53
  spec.add_development_dependency 'rack-protection', '>= 2'
54
- spec.add_development_dependency 'rails', '~> 7'
54
+ spec.add_development_dependency 'rails', '>= 6', '~> 7'
55
55
  spec.add_development_dependency 'sinatra', '>= 2'
56
56
  end
57
57
 
@@ -80,7 +80,7 @@ def self.add_specs spec
80
80
  spec.add_development_dependency 'rspec', '~> 3.0'
81
81
  spec.add_development_dependency 'rspec-benchmark'
82
82
  spec.add_development_dependency 'rspec_junit_formatter', '0.3.0'
83
- spec.add_development_dependency 'rspec-rails', '5.0'
83
+ spec.add_development_dependency 'rspec-rails', '6.0'
84
84
  spec.add_development_dependency 'tzinfo-data' # Alpine rspec-rails requirement.
85
85
  spec.add_development_dependency 'warning'
86
86
  spec.add_development_dependency 'typhoeus', '~> 1.4'
@@ -102,11 +102,7 @@ end
102
102
 
103
103
  # Dependencies not mocked out during RSpec that we test real code of, beyond just frameworks.
104
104
  def self.add_tested_gems spec
105
- if RUBY_VERSION < '3.0.0'
106
- spec.add_development_dependency 'async', '~> 1.30.3'
107
- else
108
- spec.add_development_dependency 'async'
109
- end
105
+ spec.add_development_dependency 'async'
110
106
  spec.add_development_dependency 'execjs'
111
107
  spec.add_development_dependency 'rhino'
112
108
  spec.add_development_dependency 'sqlite3'
@@ -181,7 +177,7 @@ Gem::Specification.new do |spec|
181
177
  'Testing and Protection.'
182
178
  spec.homepage = 'https://www.contrastsecurity.com'
183
179
  spec.license = 'CONTRAST SECURITY (see license file)'
184
- spec.required_ruby_version = ['>= 2.7.0', '< 3.3.0']
180
+ spec.required_ruby_version = ['>= 3.0.0', '< 3.3.0']
185
181
 
186
182
  spec.bindir = 'exe'
187
183
  # Keep cs__common first, it handles funchook.h right now.
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: 6.15.2
4
+ version: 7.0.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: 2023-02-22 00:00:00.000000000 Z
16
+ date: 2023-04-03 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: bundler
@@ -277,6 +277,9 @@ dependencies:
277
277
  name: rails
278
278
  requirement: !ruby/object:Gem::Requirement
279
279
  requirements:
280
+ - - ">="
281
+ - !ruby/object:Gem::Version
282
+ version: '6'
280
283
  - - "~>"
281
284
  - !ruby/object:Gem::Version
282
285
  version: '7'
@@ -284,6 +287,9 @@ dependencies:
284
287
  prerelease: false
285
288
  version_requirements: !ruby/object:Gem::Requirement
286
289
  requirements:
290
+ - - ">="
291
+ - !ruby/object:Gem::Version
292
+ version: '6'
287
293
  - - "~>"
288
294
  - !ruby/object:Gem::Version
289
295
  version: '7'
@@ -305,16 +311,16 @@ dependencies:
305
311
  name: async
306
312
  requirement: !ruby/object:Gem::Requirement
307
313
  requirements:
308
- - - "~>"
314
+ - - ">="
309
315
  - !ruby/object:Gem::Version
310
- version: 1.30.3
316
+ version: '0'
311
317
  type: :development
312
318
  prerelease: false
313
319
  version_requirements: !ruby/object:Gem::Requirement
314
320
  requirements:
315
- - - "~>"
321
+ - - ">="
316
322
  - !ruby/object:Gem::Version
317
- version: 1.30.3
323
+ version: '0'
318
324
  - !ruby/object:Gem::Dependency
319
325
  name: execjs
320
326
  requirement: !ruby/object:Gem::Requirement
@@ -531,14 +537,14 @@ dependencies:
531
537
  requirements:
532
538
  - - '='
533
539
  - !ruby/object:Gem::Version
534
- version: '5.0'
540
+ version: '6.0'
535
541
  type: :development
536
542
  prerelease: false
537
543
  version_requirements: !ruby/object:Gem::Requirement
538
544
  requirements:
539
545
  - - '='
540
546
  - !ruby/object:Gem::Version
541
- version: '5.0'
547
+ version: '6.0'
542
548
  - !ruby/object:Gem::Dependency
543
549
  name: tzinfo-data
544
550
  requirement: !ruby/object:Gem::Requirement
@@ -678,22 +684,22 @@ email:
678
684
  executables: []
679
685
  extensions:
680
686
  - ext/cs__common/extconf.rb
681
- - ext/cs__assess_marshal_module/extconf.rb
682
- - ext/cs__assess_yield_track/extconf.rb
683
- - ext/cs__scope/extconf.rb
684
- - ext/cs__assess_kernel/extconf.rb
685
687
  - ext/cs__assess_array/extconf.rb
686
- - ext/cs__os_information/extconf.rb
687
- - ext/cs__assess_string/extconf.rb
688
+ - ext/cs__assess_basic_object/extconf.rb
689
+ - ext/cs__assess_fiber_track/extconf.rb
688
690
  - ext/cs__assess_hash/extconf.rb
689
- - ext/cs__assess_regexp/extconf.rb
691
+ - ext/cs__assess_kernel/extconf.rb
692
+ - ext/cs__assess_marshal_module/extconf.rb
690
693
  - ext/cs__assess_module/extconf.rb
694
+ - ext/cs__assess_regexp/extconf.rb
695
+ - ext/cs__assess_string/extconf.rb
691
696
  - ext/cs__assess_string_interpolation/extconf.rb
692
- - ext/cs__tests/extconf.rb
693
697
  - ext/cs__assess_test/extconf.rb
694
- - ext/cs__assess_fiber_track/extconf.rb
695
- - ext/cs__assess_basic_object/extconf.rb
698
+ - ext/cs__assess_yield_track/extconf.rb
696
699
  - ext/cs__contrast_patch/extconf.rb
700
+ - ext/cs__os_information/extconf.rb
701
+ - ext/cs__scope/extconf.rb
702
+ - ext/cs__tests/extconf.rb
697
703
  extra_rdoc_files: []
698
704
  files:
699
705
  - ".clang-format"
@@ -1342,7 +1348,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
1342
1348
  requirements:
1343
1349
  - - ">="
1344
1350
  - !ruby/object:Gem::Version
1345
- version: 2.7.0
1351
+ version: 3.0.0
1346
1352
  - - "<"
1347
1353
  - !ruby/object:Gem::Version
1348
1354
  version: 3.3.0
@@ -1352,7 +1358,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
1352
1358
  - !ruby/object:Gem::Version
1353
1359
  version: '0'
1354
1360
  requirements: []
1355
- rubygems_version: 3.1.6
1361
+ rubygems_version: 3.2.33
1356
1362
  signing_key:
1357
1363
  specification_version: 4
1358
1364
  summary: Contrast Security's agent for rack-based applications.