contrast-agent 4.3.2 → 4.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (317) hide show
  1. checksums.yaml +4 -4
  2. data/.gitmodules +1 -1
  3. data/.simplecov +1 -1
  4. data/Gemfile +1 -1
  5. data/LICENSE.txt +1 -1
  6. data/Rakefile +2 -3
  7. data/exe/contrast_service +1 -1
  8. data/ext/build_funchook.rb +4 -4
  9. data/ext/cs__assess_active_record_named/cs__active_record_named.c +1 -1
  10. data/ext/cs__assess_active_record_named/extconf.rb +1 -1
  11. data/ext/cs__assess_array/cs__assess_array.c +1 -1
  12. data/ext/cs__assess_array/extconf.rb +1 -1
  13. data/ext/cs__assess_basic_object/cs__assess_basic_object.c +1 -1
  14. data/ext/cs__assess_basic_object/extconf.rb +1 -1
  15. data/ext/cs__assess_fiber_track/cs__assess_fiber_track.c +1 -1
  16. data/ext/cs__assess_fiber_track/extconf.rb +1 -1
  17. data/ext/cs__assess_hash/cs__assess_hash.c +4 -2
  18. data/ext/cs__assess_hash/extconf.rb +1 -1
  19. data/ext/cs__assess_kernel/cs__assess_kernel.c +1 -1
  20. data/ext/cs__assess_kernel/extconf.rb +1 -1
  21. data/ext/cs__assess_marshal_module/cs__assess_marshal_module.c +1 -1
  22. data/ext/cs__assess_marshal_module/extconf.rb +1 -1
  23. data/ext/cs__assess_module/cs__assess_module.c +1 -1
  24. data/ext/cs__assess_module/extconf.rb +1 -1
  25. data/ext/cs__assess_regexp/cs__assess_regexp.c +1 -1
  26. data/ext/cs__assess_regexp/extconf.rb +1 -1
  27. data/ext/cs__assess_string/cs__assess_string.c +1 -1
  28. data/ext/cs__assess_string/extconf.rb +1 -1
  29. data/ext/cs__assess_string_interpolation26/cs__assess_string_interpolation26.c +1 -1
  30. data/ext/cs__assess_string_interpolation26/extconf.rb +1 -1
  31. data/ext/cs__assess_yield_track/cs__assess_yield_track.c +1 -1
  32. data/ext/cs__assess_yield_track/extconf.rb +1 -1
  33. data/ext/cs__common/cs__common.c +5 -5
  34. data/ext/cs__common/cs__common.h +4 -4
  35. data/ext/cs__common/extconf.rb +1 -1
  36. data/ext/cs__contrast_patch/cs__contrast_patch.c +22 -25
  37. data/ext/cs__contrast_patch/extconf.rb +1 -1
  38. data/ext/cs__protect_kernel/cs__protect_kernel.c +1 -1
  39. data/ext/cs__protect_kernel/extconf.rb +1 -1
  40. data/ext/extconf_common.rb +2 -6
  41. data/lib/contrast-agent.rb +1 -1
  42. data/lib/contrast.rb +20 -1
  43. data/lib/contrast/agent.rb +6 -4
  44. data/lib/contrast/agent/assess.rb +2 -11
  45. data/lib/contrast/agent/assess/contrast_event.rb +54 -71
  46. data/lib/contrast/agent/assess/contrast_object.rb +7 -4
  47. data/lib/contrast/agent/assess/events/event_factory.rb +3 -2
  48. data/lib/contrast/agent/assess/events/source_event.rb +7 -2
  49. data/lib/contrast/agent/assess/finalizers/freeze.rb +1 -1
  50. data/lib/contrast/agent/assess/finalizers/hash.rb +33 -34
  51. data/lib/contrast/agent/assess/policy/dynamic_source_factory.rb +34 -16
  52. data/lib/contrast/agent/assess/policy/patcher.rb +11 -18
  53. data/lib/contrast/agent/assess/policy/policy.rb +1 -1
  54. data/lib/contrast/agent/assess/policy/policy_node.rb +26 -34
  55. data/lib/contrast/agent/assess/policy/policy_scanner.rb +1 -1
  56. data/lib/contrast/agent/assess/policy/preshift.rb +4 -2
  57. data/lib/contrast/agent/assess/policy/propagation_method.rb +32 -30
  58. data/lib/contrast/agent/assess/policy/propagation_node.rb +20 -9
  59. data/lib/contrast/agent/assess/policy/propagator.rb +1 -1
  60. data/lib/contrast/agent/assess/policy/propagator/append.rb +29 -14
  61. data/lib/contrast/agent/assess/policy/propagator/base.rb +1 -1
  62. data/lib/contrast/agent/assess/policy/propagator/center.rb +3 -2
  63. data/lib/contrast/agent/assess/policy/propagator/custom.rb +1 -1
  64. data/lib/contrast/agent/assess/policy/propagator/database_write.rb +22 -17
  65. data/lib/contrast/agent/assess/policy/propagator/insert.rb +4 -2
  66. data/lib/contrast/agent/assess/policy/propagator/keep.rb +1 -1
  67. data/lib/contrast/agent/assess/policy/propagator/match_data.rb +3 -2
  68. data/lib/contrast/agent/assess/policy/propagator/next.rb +1 -1
  69. data/lib/contrast/agent/assess/policy/propagator/prepend.rb +1 -1
  70. data/lib/contrast/agent/assess/policy/propagator/remove.rb +23 -19
  71. data/lib/contrast/agent/assess/policy/propagator/replace.rb +1 -1
  72. data/lib/contrast/agent/assess/policy/propagator/reverse.rb +1 -1
  73. data/lib/contrast/agent/assess/policy/propagator/select.rb +3 -13
  74. data/lib/contrast/agent/assess/policy/propagator/splat.rb +24 -14
  75. data/lib/contrast/agent/assess/policy/propagator/split.rb +18 -15
  76. data/lib/contrast/agent/assess/policy/propagator/substitution.rb +32 -22
  77. data/lib/contrast/agent/assess/policy/propagator/trim.rb +64 -45
  78. data/lib/contrast/agent/assess/policy/rewriter_patch.rb +7 -4
  79. data/lib/contrast/agent/assess/policy/source_method.rb +92 -81
  80. data/lib/contrast/agent/assess/policy/source_node.rb +1 -1
  81. data/lib/contrast/agent/assess/policy/source_validation/cross_site_validator.rb +8 -6
  82. data/lib/contrast/agent/assess/policy/source_validation/source_validation.rb +2 -4
  83. data/lib/contrast/agent/assess/policy/trigger/reflected_xss.rb +7 -3
  84. data/lib/contrast/agent/assess/policy/trigger/xpath.rb +7 -8
  85. data/lib/contrast/agent/assess/policy/trigger_method.rb +109 -76
  86. data/lib/contrast/agent/assess/policy/trigger_node.rb +33 -11
  87. data/lib/contrast/agent/assess/policy/trigger_validation/redos_validator.rb +60 -0
  88. data/lib/contrast/agent/assess/policy/trigger_validation/ssrf_validator.rb +3 -5
  89. data/lib/contrast/agent/assess/policy/trigger_validation/trigger_validation.rb +7 -5
  90. data/lib/contrast/agent/assess/policy/trigger_validation/xss_validator.rb +4 -13
  91. data/lib/contrast/agent/assess/properties.rb +1 -3
  92. data/lib/contrast/agent/assess/property/evented.rb +9 -6
  93. data/lib/contrast/agent/assess/property/tagged.rb +38 -20
  94. data/lib/contrast/agent/assess/property/updated.rb +1 -1
  95. data/lib/contrast/agent/assess/rule/provider.rb +1 -1
  96. data/lib/contrast/agent/assess/rule/provider/hardcoded_key.rb +12 -6
  97. data/lib/contrast/agent/assess/rule/provider/hardcoded_password.rb +5 -2
  98. data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +4 -6
  99. data/lib/contrast/agent/assess/tag.rb +1 -1
  100. data/lib/contrast/agent/assess/tracker.rb +2 -2
  101. data/lib/contrast/agent/at_exit_hook.rb +1 -1
  102. data/lib/contrast/agent/class_reopener.rb +4 -2
  103. data/lib/contrast/agent/deadzone/policy/deadzone_node.rb +1 -1
  104. data/lib/contrast/agent/deadzone/policy/policy.rb +7 -3
  105. data/lib/contrast/agent/disable_reaction.rb +2 -4
  106. data/lib/contrast/agent/exclusion_matcher.rb +6 -12
  107. data/lib/contrast/agent/inventory.rb +1 -2
  108. data/lib/contrast/agent/inventory/dependencies.rb +3 -1
  109. data/lib/contrast/agent/inventory/dependency_analysis.rb +1 -1
  110. data/lib/contrast/agent/inventory/dependency_usage_analysis.rb +35 -23
  111. data/lib/contrast/agent/inventory/policy/datastores.rb +1 -1
  112. data/lib/contrast/agent/inventory/policy/policy.rb +1 -1
  113. data/lib/contrast/agent/inventory/policy/trigger_node.rb +1 -1
  114. data/lib/contrast/agent/middleware.rb +111 -110
  115. data/lib/contrast/agent/module_data.rb +4 -4
  116. data/lib/contrast/agent/patching/policy/after_load_patch.rb +1 -1
  117. data/lib/contrast/agent/patching/policy/after_load_patcher.rb +9 -4
  118. data/lib/contrast/agent/patching/policy/method_policy.rb +7 -3
  119. data/lib/contrast/agent/patching/policy/module_policy.rb +15 -8
  120. data/lib/contrast/agent/patching/policy/patch.rb +23 -29
  121. data/lib/contrast/agent/patching/policy/patch_status.rb +8 -9
  122. data/lib/contrast/agent/patching/policy/patcher.rb +72 -64
  123. data/lib/contrast/agent/patching/policy/policy.rb +14 -21
  124. data/lib/contrast/agent/patching/policy/policy_node.rb +15 -5
  125. data/lib/contrast/agent/patching/policy/trigger_node.rb +26 -10
  126. data/lib/contrast/agent/protect/policy/applies_command_injection_rule.rb +2 -2
  127. data/lib/contrast/agent/protect/policy/applies_deserialization_rule.rb +2 -2
  128. data/lib/contrast/agent/protect/policy/applies_no_sqli_rule.rb +2 -2
  129. data/lib/contrast/agent/protect/policy/applies_path_traversal_rule.rb +3 -4
  130. data/lib/contrast/agent/protect/policy/applies_sqli_rule.rb +2 -2
  131. data/lib/contrast/agent/protect/policy/applies_xxe_rule.rb +6 -10
  132. data/lib/contrast/agent/protect/policy/policy.rb +1 -1
  133. data/lib/contrast/agent/protect/policy/rule_applicator.rb +6 -6
  134. data/lib/contrast/agent/protect/policy/trigger_node.rb +1 -1
  135. data/lib/contrast/agent/protect/rule.rb +1 -1
  136. data/lib/contrast/agent/protect/rule/base.rb +19 -33
  137. data/lib/contrast/agent/protect/rule/base_service.rb +10 -6
  138. data/lib/contrast/agent/protect/rule/cmd_injection.rb +15 -19
  139. data/lib/contrast/agent/protect/rule/default_scanner.rb +1 -1
  140. data/lib/contrast/agent/protect/rule/deserialization.rb +7 -14
  141. data/lib/contrast/agent/protect/rule/http_method_tampering.rb +4 -15
  142. data/lib/contrast/agent/protect/rule/no_sqli.rb +7 -3
  143. data/lib/contrast/agent/protect/rule/no_sqli/mongo_no_sql_scanner.rb +2 -4
  144. data/lib/contrast/agent/protect/rule/path_traversal.rb +6 -6
  145. data/lib/contrast/agent/protect/rule/sqli.rb +19 -13
  146. data/lib/contrast/agent/protect/rule/sqli/default_sql_scanner.rb +1 -1
  147. data/lib/contrast/agent/protect/rule/sqli/mysql_sql_scanner.rb +1 -1
  148. data/lib/contrast/agent/protect/rule/sqli/postgres_sql_scanner.rb +2 -2
  149. data/lib/contrast/agent/protect/rule/sqli/sqlite_sql_scanner.rb +1 -1
  150. data/lib/contrast/agent/protect/rule/unsafe_file_upload.rb +2 -2
  151. data/lib/contrast/agent/protect/rule/xss.rb +2 -2
  152. data/lib/contrast/agent/protect/rule/xxe.rb +6 -13
  153. data/lib/contrast/agent/protect/rule/xxe/entity_wrapper.rb +2 -3
  154. data/lib/contrast/agent/railtie.rb +1 -1
  155. data/lib/contrast/agent/reaction_processor.rb +12 -11
  156. data/lib/contrast/agent/request.rb +25 -24
  157. data/lib/contrast/agent/request_context.rb +25 -23
  158. data/lib/contrast/agent/request_handler.rb +1 -1
  159. data/lib/contrast/agent/response.rb +1 -1
  160. data/lib/contrast/agent/rewriter.rb +6 -4
  161. data/lib/contrast/agent/rule_set.rb +3 -3
  162. data/lib/contrast/agent/scope.rb +1 -1
  163. data/lib/contrast/agent/service_heartbeat.rb +3 -4
  164. data/lib/contrast/agent/static_analysis.rb +1 -1
  165. data/lib/contrast/agent/thread.rb +2 -2
  166. data/lib/contrast/agent/thread_watcher.rb +21 -6
  167. data/lib/contrast/agent/tracepoint_hook.rb +2 -2
  168. data/lib/contrast/agent/version.rb +2 -2
  169. data/lib/contrast/agent/worker_thread.rb +1 -1
  170. data/lib/contrast/api.rb +1 -1
  171. data/lib/contrast/api/communication.rb +1 -1
  172. data/lib/contrast/api/communication/connection_status.rb +1 -1
  173. data/lib/contrast/api/communication/messaging_queue.rb +19 -22
  174. data/lib/contrast/api/communication/response_processor.rb +13 -8
  175. data/lib/contrast/api/communication/service_lifecycle.rb +5 -3
  176. data/lib/contrast/api/communication/socket.rb +1 -1
  177. data/lib/contrast/api/communication/socket_client.rb +30 -35
  178. data/lib/contrast/api/communication/speedracer.rb +6 -10
  179. data/lib/contrast/api/communication/tcp_socket.rb +1 -1
  180. data/lib/contrast/api/communication/unix_socket.rb +1 -1
  181. data/lib/contrast/api/decorators.rb +3 -1
  182. data/lib/contrast/api/decorators/address.rb +1 -1
  183. data/lib/contrast/api/decorators/agent_startup.rb +58 -0
  184. data/lib/contrast/api/decorators/application_settings.rb +1 -1
  185. data/lib/contrast/api/decorators/application_startup.rb +57 -0
  186. data/lib/contrast/api/decorators/application_update.rb +1 -1
  187. data/lib/contrast/api/decorators/http_request.rb +1 -1
  188. data/lib/contrast/api/decorators/input_analysis.rb +1 -1
  189. data/lib/contrast/api/decorators/instrumentation_mode.rb +37 -0
  190. data/lib/contrast/api/decorators/library.rb +9 -7
  191. data/lib/contrast/api/decorators/library_usage_update.rb +1 -1
  192. data/lib/contrast/api/decorators/message.rb +4 -4
  193. data/lib/contrast/api/decorators/rasp_rule_sample.rb +1 -1
  194. data/lib/contrast/api/decorators/route_coverage.rb +16 -6
  195. data/lib/contrast/api/decorators/server_features.rb +1 -1
  196. data/lib/contrast/api/decorators/trace_event.rb +46 -16
  197. data/lib/contrast/api/decorators/trace_event_object.rb +2 -4
  198. data/lib/contrast/api/decorators/trace_event_signature.rb +1 -1
  199. data/lib/contrast/api/decorators/trace_taint_range.rb +1 -1
  200. data/lib/contrast/api/decorators/trace_taint_range_tags.rb +2 -7
  201. data/lib/contrast/api/decorators/user_input.rb +1 -1
  202. data/lib/contrast/components/agent.rb +16 -15
  203. data/lib/contrast/components/app_context.rb +11 -29
  204. data/lib/contrast/components/assess.rb +6 -11
  205. data/lib/contrast/components/config.rb +3 -2
  206. data/lib/contrast/components/contrast_service.rb +8 -9
  207. data/lib/contrast/components/heap_dump.rb +1 -1
  208. data/lib/contrast/components/interface.rb +4 -3
  209. data/lib/contrast/components/inventory.rb +1 -1
  210. data/lib/contrast/components/logger.rb +1 -1
  211. data/lib/contrast/components/protect.rb +11 -14
  212. data/lib/contrast/components/sampling.rb +55 -7
  213. data/lib/contrast/components/scope.rb +2 -1
  214. data/lib/contrast/components/settings.rb +29 -99
  215. data/lib/contrast/config.rb +1 -1
  216. data/lib/contrast/config/agent_configuration.rb +1 -1
  217. data/lib/contrast/config/application_configuration.rb +1 -1
  218. data/lib/contrast/config/assess_configuration.rb +1 -1
  219. data/lib/contrast/config/assess_rules_configuration.rb +2 -4
  220. data/lib/contrast/config/base_configuration.rb +5 -6
  221. data/lib/contrast/config/default_value.rb +1 -1
  222. data/lib/contrast/config/exception_configuration.rb +2 -6
  223. data/lib/contrast/config/heap_dump_configuration.rb +13 -7
  224. data/lib/contrast/config/inventory_configuration.rb +1 -1
  225. data/lib/contrast/config/logger_configuration.rb +2 -6
  226. data/lib/contrast/config/protect_configuration.rb +1 -1
  227. data/lib/contrast/config/protect_rule_configuration.rb +23 -1
  228. data/lib/contrast/config/protect_rules_configuration.rb +1 -1
  229. data/lib/contrast/config/root_configuration.rb +1 -1
  230. data/lib/contrast/config/ruby_configuration.rb +1 -1
  231. data/lib/contrast/config/sampling_configuration.rb +1 -1
  232. data/lib/contrast/config/server_configuration.rb +1 -1
  233. data/lib/contrast/config/service_configuration.rb +1 -1
  234. data/lib/contrast/configuration.rb +4 -15
  235. data/lib/contrast/delegators/input_analysis.rb +12 -0
  236. data/lib/contrast/extension/assess.rb +1 -1
  237. data/lib/contrast/extension/assess/array.rb +2 -7
  238. data/lib/contrast/extension/assess/erb.rb +2 -8
  239. data/lib/contrast/extension/assess/eval_trigger.rb +3 -11
  240. data/lib/contrast/extension/assess/exec_trigger.rb +4 -14
  241. data/lib/contrast/extension/assess/fiber.rb +3 -13
  242. data/lib/contrast/extension/assess/hash.rb +1 -1
  243. data/lib/contrast/extension/assess/kernel.rb +3 -10
  244. data/lib/contrast/extension/assess/marshal.rb +3 -11
  245. data/lib/contrast/extension/assess/regexp.rb +2 -7
  246. data/lib/contrast/extension/assess/string.rb +4 -2
  247. data/lib/contrast/extension/delegator.rb +1 -1
  248. data/lib/contrast/extension/inventory.rb +1 -1
  249. data/lib/contrast/extension/kernel.rb +5 -3
  250. data/lib/contrast/extension/module.rb +1 -1
  251. data/lib/contrast/extension/protect.rb +1 -1
  252. data/lib/contrast/extension/protect/kernel.rb +1 -1
  253. data/lib/contrast/extension/protect/psych.rb +1 -1
  254. data/lib/contrast/extension/thread.rb +1 -1
  255. data/lib/contrast/framework/base_support.rb +1 -1
  256. data/lib/contrast/framework/manager.rb +14 -17
  257. data/lib/contrast/framework/platform_version.rb +1 -1
  258. data/lib/contrast/framework/rack/patch/session_cookie.rb +6 -19
  259. data/lib/contrast/framework/rack/patch/support.rb +7 -5
  260. data/lib/contrast/framework/rack/support.rb +1 -1
  261. data/lib/contrast/framework/rails/patch/action_controller_live_buffer.rb +1 -1
  262. data/lib/contrast/framework/rails/patch/assess_configuration.rb +8 -3
  263. data/lib/contrast/framework/rails/patch/rails_application_configuration.rb +4 -4
  264. data/lib/contrast/framework/rails/patch/support.rb +5 -3
  265. data/lib/contrast/framework/rails/rewrite/action_controller_railties_helper_inherited.rb +5 -2
  266. data/lib/contrast/framework/rails/rewrite/active_record_attribute_methods_read.rb +3 -1
  267. data/lib/contrast/framework/rails/rewrite/active_record_named.rb +3 -1
  268. data/lib/contrast/framework/rails/rewrite/active_record_time_zone_inherited.rb +3 -1
  269. data/lib/contrast/framework/rails/support.rb +45 -46
  270. data/lib/contrast/framework/sinatra/support.rb +103 -42
  271. data/lib/contrast/funchook/funchook.rb +2 -6
  272. data/lib/contrast/logger/application.rb +13 -10
  273. data/lib/contrast/logger/format.rb +3 -6
  274. data/lib/contrast/logger/log.rb +36 -19
  275. data/lib/contrast/logger/request.rb +2 -3
  276. data/lib/contrast/logger/time.rb +1 -1
  277. data/lib/contrast/security_exception.rb +2 -2
  278. data/lib/contrast/tasks/config.rb +1 -1
  279. data/lib/contrast/tasks/service.rb +6 -2
  280. data/lib/contrast/utils/assess/sampling_util.rb +1 -1
  281. data/lib/contrast/utils/assess/tracking_util.rb +2 -3
  282. data/lib/contrast/utils/class_util.rb +18 -12
  283. data/lib/contrast/utils/duck_utils.rb +1 -1
  284. data/lib/contrast/utils/env_configuration_item.rb +1 -1
  285. data/lib/contrast/utils/hash_digest.rb +16 -24
  286. data/lib/contrast/utils/heap_dump_util.rb +104 -88
  287. data/lib/contrast/utils/invalid_configuration_util.rb +22 -13
  288. data/lib/contrast/utils/inventory_util.rb +1 -1
  289. data/lib/contrast/utils/io_util.rb +2 -2
  290. data/lib/contrast/utils/job_servers_running.rb +10 -5
  291. data/lib/contrast/utils/object_share.rb +1 -1
  292. data/lib/contrast/utils/os.rb +3 -2
  293. data/lib/contrast/utils/preflight_util.rb +1 -1
  294. data/lib/contrast/utils/resource_loader.rb +1 -1
  295. data/lib/contrast/utils/ruby_ast_rewriter.rb +3 -2
  296. data/lib/contrast/utils/sha256_builder.rb +1 -1
  297. data/lib/contrast/utils/stack_trace_utils.rb +1 -1
  298. data/lib/contrast/utils/string_utils.rb +1 -1
  299. data/lib/contrast/utils/tag_util.rb +1 -1
  300. data/lib/contrast/utils/thread_tracker.rb +1 -1
  301. data/lib/contrast/utils/timer.rb +1 -1
  302. data/resources/assess/policy.json +8 -11
  303. data/resources/deadzone/policy.json +7 -17
  304. data/ruby-agent.gemspec +66 -27
  305. data/service_executables/VERSION +1 -1
  306. data/service_executables/linux/contrast-service +0 -0
  307. data/service_executables/mac/contrast-service +0 -0
  308. data/sonar-project.properties +9 -0
  309. metadata +154 -156
  310. data/lib/contrast/agent/assess/rule.rb +0 -18
  311. data/lib/contrast/agent/assess/rule/base.rb +0 -52
  312. data/lib/contrast/agent/assess/rule/redos.rb +0 -67
  313. data/lib/contrast/agent/inventory/gemfile_digest_cache.rb +0 -38
  314. data/lib/contrast/common_agent_configuration.rb +0 -87
  315. data/lib/contrast/framework/sinatra/patch/base.rb +0 -83
  316. data/lib/contrast/framework/sinatra/patch/support.rb +0 -27
  317. data/lib/contrast/utils/prevent_serialization.rb +0 -52
@@ -1,6 +1,8 @@
1
- # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
1
+ # Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
+ return unless RUBY_VERSION < '2.6.0' # TODO: RUBY-714 remove guard w/ EOL of 2.5
5
+
4
6
  require 'contrast/components/interface'
5
7
 
6
8
  module Contrast
@@ -1,6 +1,8 @@
1
- # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
1
+ # Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
+ return unless RUBY_VERSION < '2.6.0' # TODO: RUBY-714 remove guard w/ EOL of 2.5
5
+
4
6
  module Contrast
5
7
  module Framework
6
8
  module Rails
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
1
+ # Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'contrast/api/dtm.pb'
@@ -27,8 +27,8 @@ module Contrast
27
27
 
28
28
  def application_name
29
29
  app_class = ::Rails.application.cs__class
30
- # Rails version 6.0.0 deprecated Rails::Application#parent_name, in Rails 6.1.0 that method will be removed entirely
31
- # and instead we need to use parent_module_name
30
+ # Rails version 6.0.0 deprecated Rails::Application#parent_name, in Rails 6.1.0 that method will be removed
31
+ # entirely and instead we need to use parent_module_name
32
32
  return app_class.parent_module_name if Gem::Version.new(::Rails.version) >= RAILS_MODULE_NAME_VERSION
33
33
 
34
34
  app_class.parent_name
@@ -47,32 +47,34 @@ module Contrast
47
47
  end
48
48
 
49
49
  # Find the current route, based on the provided Request wrapper
50
+ #
50
51
  # @param request[Contrast::Agent::Request]
51
52
  # @return [Contrast::Api::Dtm::RouteCoverage]
52
53
  def current_route request
53
54
  return unless ::Rails.cs__respond_to?(:application)
54
55
 
55
- # returns array of arrays [[match_data, path_parameters, route]], sorted by
56
- # precedence
57
- # match_data: ActionDispatch::Journey::Path::Pattern::MatchData
58
- # path_parameters: hash of various things
59
- # route: ActionDispatch::Journey::Route
60
- full_routes = ::Rails.application.routes.router.send(:find_routes, request.rack_request)
61
- return if full_routes.empty?
56
+ match, _params, route, path = get_full_route(request.rack_request)
62
57
 
63
- full_route = full_routes[0]
58
+ original_url = request.rack_request.path_info
64
59
 
65
- # the route is directly implemented within the application
66
- if direct_route?(full_route)
67
- route = full_route[2] # route w/ highest precedence
68
- Contrast::Api::Dtm::RouteCoverage.from_action_dispatch_journey(route)
69
- else
70
- engine_route(full_route, request)
60
+ # Route is either the final rails route, or a router that points to a Sinatra controller.
61
+ if Contrast::Framework::Sinatra::Support.sinatra_controller?(route.app.app)
62
+ # Create a request copied from current request, but with the base path removed from path_info.
63
+ new_req = ::ActionDispatch::Request.new(request.env)
64
+ new_req.path_info = new_req.path_info.gsub((path << match).join, '')
65
+
66
+ return Contrast::Framework::Sinatra::Support.current_route(new_req, route.app.app, original_url)
71
67
  end
68
+
69
+ Contrast::Api::Dtm::RouteCoverage.from_action_dispatch_journey(route, original_url)
72
70
  rescue StandardError => _e
73
71
  nil
74
72
  end
75
73
 
74
+ # Copy a request for modification.
75
+ #
76
+ # @param [::ActionDispatch::Request] original env.
77
+ # @return [::ActionDispatch::Request] a copy of original env with rails env merged.
76
78
  def retrieve_request env
77
79
  rails_env = ::Rails.application.env_config.merge(env)
78
80
  ::ActionDispatch::Request.new(rails_env || env)
@@ -87,37 +89,34 @@ module Contrast
87
89
 
88
90
  private
89
91
 
90
- # route is not mounted within an engine
91
- def direct_route? full_route
92
- full_route[2]&.app&.cs__class == ActionDispatch::Routing::RouteSet::Dispatcher ||
93
- (full_route[2].cs__class == ActionDispatch::Journey::Route && full_route[2]&.app&.cs__class == ActionDispatch::Routing::Mapper::Constraints)
92
+ # Determine if route is a Rails engine route.
93
+ #
94
+ # @param [Object] app or route that points to a ::Rails::Engine
95
+ # @return [bool] whether the router is an engine or not.
96
+ def engine_route? route
97
+ route.app.is_a?(::ActionDispatch::Routing::Mapper::Constraints) && route.app.app < ::Rails::Engine
94
98
  end
95
99
 
96
- def engine_route full_route, request
97
- engine_route = full_route[2] # supposed route - but actually an Engine mount point
98
- return unless engine_route
99
-
100
- engine_mount_name = engine_route.name
101
- return unless engine_mount_name
102
-
103
- engine_path_segments = request.rack_request.path_info.split(engine_mount_name)
104
- return if engine_path_segments.empty?
105
-
106
- path_within_engine = engine_path_segments[-1]
107
- return unless path_within_engine
108
-
109
- engine_router = engine_route.app&.app&.routes&.router
110
- return unless engine_router
111
-
112
- # Get all routes regardless of http method
113
- matching_routes = engine_router.send(:filter_routes, path_within_engine)
114
- return unless matching_routes
115
-
116
- # filter for current http method
117
- reportable_routes = engine_router.send(:match_routes, matching_routes, request.rack_request)
118
- return if reportable_routes.empty?
119
-
120
- Contrast::Api::Dtm::RouteCoverage.from_action_dispatch_journey(reportable_routes[0])
100
+ # Recursively get final route traversing engines as required.
101
+ #
102
+ # @param request [::Rack::Request] the rack request as will be handed to rails controller.
103
+ # @param top_router [::ActionDispatch::Journer::Router] the current router relative to the previous.
104
+ # @param path [Array<String>] the chunks of path that have been seen.
105
+ # @return [Array<array>] the final set of rails route classes.
106
+ def get_full_route request, top_router = ::Rails.application.routes.router, path = []
107
+ return if (route_matches = top_router.send(:find_routes, request)).empty?
108
+
109
+ match, params, route = route_matches.first
110
+
111
+ # If the current routing node points to a sub-app (::Rais::Engine), dive deeper.
112
+ # Have sub-app route the remainder of the url.
113
+ if engine_route?(route)
114
+ new_req = retrieve_request request.env
115
+ new_req.path_info = new_req.path_info.gsub(match.to_s, '')
116
+ get_full_route(new_req, route.app.app.routes.router, path << match.to_s)
117
+ else
118
+ [match, params, route, path]
119
+ end
121
120
  end
122
121
 
123
122
  # Rails engine routes need to be detected by inspecting Engine class route set
@@ -1,8 +1,7 @@
1
- # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
1
+ # Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'contrast/framework/base_support'
5
- require 'contrast/framework/sinatra/patch/support'
6
5
 
7
6
  module Contrast
8
7
  module Framework
@@ -10,7 +9,6 @@ module Contrast
10
9
  # Used when Sinatra is present to define framework specific behavior
11
10
  class Support
12
11
  extend Contrast::Framework::BaseSupport
13
- extend Contrast::Framework::Sinatra::Patch::Support
14
12
  class << self
15
13
  def detection_class
16
14
  'Sinatra'
@@ -21,44 +19,74 @@ module Contrast
21
19
  end
22
20
 
23
21
  def application_name
24
- return unless app_class
25
-
26
- app_class.cs__class.cs__name
22
+ app_class&.cs__name
27
23
  end
28
24
 
29
25
  def application_root
30
- return unless app_class
31
-
32
- app_class.root
26
+ app_instance&.root
33
27
  end
34
28
 
35
29
  def server_type
36
30
  'sinatra'
37
31
  end
38
32
 
39
- # Iterate over every class that extends Sinatra::Base, pull out its routes
40
- # (array of arrays with Mustermann::Sinatra as [][0]) and convert them into
41
- # Contrast::Api::Dtm::RouteCoverage
33
+ # Given an object, determine if it is a Sinatra controller with routes.
34
+ #
35
+ # @param app [Object] suspected Sinatra app.
36
+ # @return [Boolean]
37
+ def sinatra_controller? app
38
+ # Sinatra is loaded?
39
+ return false unless defined?(::Sinatra) && defined?(::Sinatra::Base)
40
+ # App is a subclass of or actually is ::Sinatra::Base.
41
+ return false unless (app.cs__respond_to?(:<) && app < ::Sinatra::Base) || app == ::Sinatra::Base
42
+
43
+ # App has routes.
44
+ !app.routes.empty?
45
+ end
46
+
47
+ # Find all classes that subclass ::Sinatra::Base. Gather their routes.
48
+ #
49
+ # @return [Array<Contrast::Api::Dtm::RouteCoverage>] the routes found as Dtms.
42
50
  def collect_routes
51
+ return Contrast::Utils::ObjectShare::EMPTY_ARRAY unless defined?(::Sinatra) && defined?(::Sinatra::Base)
52
+
43
53
  routes = []
44
- controllers = sinatra_controllers
45
- controllers.each do |clazz|
46
- class_routes = sinatra_class_routes(clazz)
47
- next unless class_routes
48
-
49
- class_routes.each_pair do |method, list|
50
- # item: [ Mustermann::Sinatra, [], Proc]
51
- list.each do |item|
52
- routes << Contrast::Api::Dtm::RouteCoverage.from_sinatra_route(clazz, method, item[0])
54
+ sinatra_controllers.each do |controller|
55
+ controller.routes.each_pair do |method, route_triplets|
56
+ # Sinatra stores its routes as a triplet: [Mustermann::Sinatra, [], Proc]
57
+ route_triplets.map(&:first).each do |route_pattern|
58
+ routes << Contrast::Api::Dtm::RouteCoverage.from_sinatra_route(controller, method, route_pattern)
53
59
  end
54
60
  end
55
61
  end
56
62
  routes
57
63
  end
58
64
 
59
- # TODO: RUBY-763
60
- def current_route _request
61
- nil
65
+ # Given the current request return a RouteCoverage dtm.
66
+ #
67
+ # @param request [Contrast::Agent::Request] a contrast tracked request.
68
+ # @param controller [::Sinatra::Base] optionally use this controller instead of global ::Sinatra::Base.
69
+ # @return [Contrast::Api::Dtm::RouteCoverage, nil] a Dtm describing the route
70
+ # matched to the request if a match was found.
71
+ def current_route request, controller = ::Sinatra::Base, full_route = nil
72
+ return unless sinatra_controller?(controller)
73
+
74
+ method = request.env[::Rack::REQUEST_METHOD] # GET, PUT, POST, etc...
75
+
76
+ # Find route match--checking superclasses if necessary.
77
+ final_controller, route_pattern = _route_recurse(controller, method, _cleaned_route(request))
78
+ return unless !final_controller.nil? && !route_pattern.nil?
79
+
80
+ full_route ||= request.path_info
81
+
82
+ Contrast::Api::Dtm::RouteCoverage.from_sinatra_route(final_controller, method, route_pattern, full_route)
83
+ end
84
+
85
+ # Search object space for sinatra controllers--any class that subclasses ::Sinatra::Base.
86
+ #
87
+ # @return [Array<::Sinatra::Base>] sinatra controlelrs
88
+ def sinatra_controllers
89
+ [::Sinatra::Base] + ObjectSpace.each_object(Class).select { |clazz| sinatra_controller?(clazz) }
62
90
  end
63
91
 
64
92
  def retrieve_request env
@@ -67,30 +95,63 @@ module Contrast
67
95
 
68
96
  private
69
97
 
70
- def app_class
71
- return unless defined?(::Sinatra) && defined?(::Sinatra::Base)
72
-
73
- @_app_class ||= begin
74
- sinatra_layers = ObjectSpace.each_object(::Sinatra::Base).to_a
75
- result_layer = sinatra_layers.find { |layer| layer.app.nil? }
76
- result_layer
98
+ # Given a controller and a route to match against, find the route_pattern and class that will serve the
99
+ # route. This is recursive as Sinatra's routing is recursive from subclass to super.
100
+ #
101
+ # @param controller [Sinatra::Base, #routes] a Sinatra application.
102
+ # @param method [::Rack::REQUEST_METHOD] GET, POST, PUT, etc...
103
+ # @param method [String] the relative route passed from Rack.
104
+ # @return [Array[Sinatra::Base, Mustermann::Sinatra], nil] Either the controller that
105
+ # will handle the route along with the route pattern or nil if no match.
106
+ def _route_recurse controller, method, route
107
+ return if controller.nil? || controller.cs__class == NilClass
108
+
109
+ route_patterns = controller.routes.fetch(method, []).map(&:first)
110
+ route_pattern = route_patterns&.find do |matcher|
111
+ matcher.params(route) # ::Mustermann::Sinatra match.
77
112
  end
113
+
114
+ return controller, route_pattern if route_pattern
115
+
116
+ # Check routes defined in superclass if present.
117
+ return unless controller.superclass&.instance_variable_get(:@routes)
118
+
119
+ _route_recurse(controller.superclass, method, route)
78
120
  end
79
121
 
80
- # Iterate over every class that extends Sinatra::Base, pull out its routes
81
- # (array of arrays with Mustermann::Sinatra as [][0]) and convert them into
82
- # Contrast::Api::Dtm::RouteCoverage
83
- def sinatra_controllers
84
- return [] unless defined?(::Sinatra) && defined?(::Sinatra::Base)
122
+ # Get route and do some cleanup matching that of Sinatra::Base#process_route.
123
+ #
124
+ # @param request [Contrast::Agent::Request] a contrast tracked request.
125
+ # @return [String] the extracted and cleaned relative route.
126
+ def _cleaned_route request
127
+ settings = ::Sinatra::Base.settings
128
+ route = request.env[::Rack::PATH_INFO]
129
+ return '/' if route.empty? && !settings.empty_path_info?
130
+
131
+ !settings.strict_paths? && route.end_with?('/') ? route[0..-2] : route
132
+ end
85
133
 
86
- Contrast::Utils::ClassUtil.descendants(::Sinatra::Base)
134
+ # Almost an alias to app_instance.
135
+ #
136
+ # @return [::Sinatra::Base] the current controller class as routed by Rack.
137
+ def app_class
138
+ return unless defined?(::Sinatra) && defined?(::Sinatra::Base)
139
+
140
+ app_instance.cs__class
87
141
  end
88
142
 
89
- def sinatra_class_routes controller
90
- controller.instance_variable_get(:@routes) if controller.instance_variable_defined?(:@routes)
91
- rescue StandardError
92
- logger.trace('Sinatra controller found with no route instances', module: controller)
93
- nil
143
+ # Search the object space for the controller handling this request which will be
144
+ # the class inheriting from ::Sinatra::Base with @app=nil since it is the final servicer
145
+ # in the request/middleware chain.
146
+ #
147
+ # @return [::Sinatra::Base] the current controller as routed by Rack.
148
+ def app_instance
149
+ return unless defined?(::Sinatra) && defined?(::Sinatra::Base)
150
+
151
+ @_app_instance ||= begin
152
+ sinatra_layers = ObjectSpace.each_object(::Sinatra::Base).to_a
153
+ sinatra_layers.find { |layer| layer.app.nil? }
154
+ end
94
155
  end
95
156
  end
96
157
  end
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
1
+ # Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'contrast/components/interface'
@@ -12,11 +12,7 @@ module Funchook
12
12
  ACCEPTABLE_FILES = %w[libfunchook.dylib libfunchook.so].cs__freeze
13
13
 
14
14
  # Top level agent directories that should have the funchook libraries
15
- SEARCH_DIRS = [
16
- File.join('ext'),
17
- File.join('shared_libraries'),
18
- File.join('funchook', 'src')
19
- ].cs__freeze
15
+ SEARCH_DIRS = [File.join('ext'), File.join('shared_libraries'), File.join('funchook', 'src')].cs__freeze
20
16
 
21
17
  AGENT_ROOT = File.join(__dir__, '..', '..', '..')
22
18
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
1
+ # Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'contrast/components/interface'
@@ -16,10 +16,8 @@ module Contrast
16
16
  def application_environment
17
17
  return unless info?
18
18
 
19
- info('Process environment information',
20
- p_id: Process.pid,
21
- pp_id: Process.ppid,
22
- agent_version: Contrast::Agent::VERSION)
19
+ info('Process environment information', p_id: Process.pid, pp_id: Process.ppid,
20
+ agent_version: Contrast::Agent::VERSION)
23
21
  ENV.each do |env_key, env_value|
24
22
  env_key = env_key.to_s
25
23
  next unless ENV_KEYS.include?(env_key) ||
@@ -35,7 +33,9 @@ module Contrast
35
33
 
36
34
  loggable = CONFIG.loggable
37
35
  info('Current configuration', configuration: loggable)
38
- env_keys = ENV.keys.select { |env_key| env_key&.to_s&.start_with?(Contrast::Components::Config::CONTRAST_ENV_MARKER) }
36
+ env_keys = ENV.keys.select do |env_key|
37
+ env_key&.to_s&.start_with?(Contrast::Components::Config::CONTRAST_ENV_MARKER)
38
+ end
39
39
  env_items = env_keys.map { |env_key| Contrast::Utils::EnvConfigurationItem.new(env_key, nil) }
40
40
  env_translations = env_items.each_with_object({}) do |conversion, hash|
41
41
  hash[conversion.key] = conversion.dot_path_array.join('.')
@@ -52,7 +52,10 @@ module Contrast
52
52
  end
53
53
 
54
54
  FRAMEWORKS = %w[rails sinatra grape].cs__freeze
55
- WEB_SERVERS = %w[agoo falcon hoof iodine mongrel mongrel2 passenger puma rack skinny thin trinidad unicorn webrick yarn].cs__freeze
55
+ WEB_SERVERS = %w[
56
+ agoo falcon hoof iodine mongrel mongrel2 passenger puma rack skinny thin trinidad unicorn
57
+ webrick yarn
58
+ ].cs__freeze
56
59
  LIBRARIES = %w[excon json mongo moped mysql nokogiri oga ox pg psych sqlite3 typhoeus yaml].cs__freeze
57
60
  def log_specific_libraries
58
61
  FRAMEWORKS.each(&cs__method(:log_gem_data))
@@ -67,6 +70,7 @@ module Contrast
67
70
 
68
71
  Gem.loaded_specs.each_pair do |_name, gem_spec|
69
72
  debug('Gem loaded',
73
+ # rubocop:disable Security/Module/Name -- gems builtin.
70
74
  gem_name: gem_spec.name,
71
75
  gem_version: gem_spec.version.to_s)
72
76
  end
@@ -76,9 +80,8 @@ module Contrast
76
80
  gem_spec = Gem.loaded_specs[gem_name]
77
81
  return unless gem_spec
78
82
 
79
- info('Gem loaded',
80
- gem_name: gem_spec.name,
81
- gem_version: gem_spec.version.to_s)
83
+ info('Gem loaded', gem_name: gem_spec.name, gem_version: gem_spec.version.to_s)
84
+ # rubocop:enable Security/Module/Name
82
85
  end
83
86
  end
84
87
  end
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
1
+ # Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'ougai'
@@ -43,9 +43,7 @@ module Contrast
43
43
  def thread_hash
44
44
  hash = LOG_TRACKER.get(:logging_hash)
45
45
  unless hash
46
- hash = {
47
- thread_id: Thread.current.object_id
48
- }
46
+ hash = { thread_id: Thread.current.object_id }
49
47
  LOG_TRACKER.set(:logging_hash, hash)
50
48
  end
51
49
  hash
@@ -53,8 +51,7 @@ module Contrast
53
51
 
54
52
  NO_REQUEST_HASH = { request_id: -1 }.cs__freeze
55
53
  def request_hash
56
- @request_tracker_defined ||= defined?(Contrast::Agent) &&
57
- defined?(Contrast::Agent::REQUEST_TRACKER)
54
+ @request_tracker_defined ||= defined?(Contrast::Agent) && defined?(Contrast::Agent::REQUEST_TRACKER)
58
55
  return NO_REQUEST_HASH unless @request_tracker_defined
59
56
 
60
57
  Contrast::Agent::REQUEST_TRACKER&.current&.logging_hash || NO_REQUEST_HASH