contrast-agent 3.10.2 → 3.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (388) hide show
  1. checksums.yaml +4 -4
  2. data/.dockerignore +0 -1
  3. data/.flayignore +1 -0
  4. data/.gitignore +1 -1
  5. data/.simplecov +5 -2
  6. data/Rakefile +31 -0
  7. data/ext/build_funchook.rb +13 -19
  8. data/ext/cs__assess_active_record_named/cs__active_record_named.c +12 -14
  9. data/ext/cs__assess_active_record_named/cs__active_record_named.h +1 -0
  10. data/ext/cs__assess_active_record_named/extconf.rb +3 -0
  11. data/ext/cs__assess_array/cs__assess_array.c +5 -6
  12. data/ext/cs__assess_array/cs__assess_array.h +1 -0
  13. data/ext/cs__assess_array/extconf.rb +3 -0
  14. data/ext/cs__assess_basic_object/cs__assess_basic_object.c +13 -11
  15. data/ext/cs__assess_basic_object/cs__assess_basic_object.h +2 -1
  16. data/ext/cs__assess_basic_object/extconf.rb +3 -0
  17. data/ext/cs__assess_fiber_track/cs__assess_fiber_track.c +6 -11
  18. data/ext/cs__assess_fiber_track/cs__assess_fiber_track.h +3 -4
  19. data/ext/cs__assess_fiber_track/extconf.rb +3 -0
  20. data/ext/cs__assess_hash/cs__assess_hash.c +40 -17
  21. data/ext/cs__assess_hash/cs__assess_hash.h +4 -6
  22. data/ext/cs__assess_hash/extconf.rb +3 -0
  23. data/ext/cs__assess_kernel/cs__assess_kernel.c +11 -9
  24. data/ext/cs__assess_kernel/cs__assess_kernel.h +1 -0
  25. data/ext/cs__assess_kernel/extconf.rb +3 -0
  26. data/ext/cs__assess_marshal_module/cs__assess_marshal_module.c +3 -6
  27. data/ext/cs__assess_marshal_module/extconf.rb +3 -0
  28. data/ext/cs__assess_module/cs__assess_module.c +16 -14
  29. data/ext/cs__assess_module/cs__assess_module.h +3 -0
  30. data/ext/cs__assess_module/extconf.rb +3 -0
  31. data/ext/cs__assess_regexp/cs__assess_regexp.c +13 -9
  32. data/ext/cs__assess_regexp/cs__assess_regexp.h +1 -0
  33. data/ext/cs__assess_regexp/extconf.rb +3 -0
  34. data/ext/cs__assess_string/cs__assess_string.c +5 -8
  35. data/ext/cs__assess_string/cs__assess_string.h +2 -1
  36. data/ext/cs__assess_string/extconf.rb +3 -0
  37. data/ext/cs__assess_string_interpolation26/cs__assess_string_interpolation26.c +3 -8
  38. data/ext/cs__assess_string_interpolation26/cs__assess_string_interpolation26.h +3 -3
  39. data/ext/cs__assess_string_interpolation26/extconf.rb +3 -0
  40. data/ext/cs__assess_yield_track/cs__assess_yield_track.c +1 -5
  41. data/ext/cs__assess_yield_track/cs__assess_yield_track.h +1 -2
  42. data/ext/cs__assess_yield_track/extconf.rb +3 -0
  43. data/ext/cs__common/cs__common.c +104 -1
  44. data/ext/cs__common/cs__common.h +37 -0
  45. data/ext/cs__common/extconf.rb +3 -16
  46. data/ext/cs__contrast_patch/cs__contrast_patch.h +1 -6
  47. data/ext/cs__contrast_patch/extconf.rb +3 -0
  48. data/ext/cs__protect_kernel/cs__protect_kernel.c +23 -12
  49. data/ext/cs__protect_kernel/cs__protect_kernel.h +1 -0
  50. data/ext/cs__protect_kernel/extconf.rb +3 -0
  51. data/ext/extconf_common.rb +3 -29
  52. data/lib/contrast.rb +4 -2
  53. data/lib/contrast/agent.rb +46 -31
  54. data/lib/contrast/agent/assess.rb +1 -11
  55. data/lib/contrast/agent/assess/contrast_event.rb +39 -224
  56. data/lib/contrast/agent/assess/events/event_factory.rb +25 -0
  57. data/lib/contrast/agent/assess/events/source_event.rb +79 -0
  58. data/lib/contrast/agent/assess/insulator.rb +0 -4
  59. data/lib/contrast/agent/assess/policy/dynamic_source_factory.rb +1 -1
  60. data/lib/contrast/agent/assess/policy/patcher.rb +6 -2
  61. data/lib/contrast/agent/assess/policy/policy_node.rb +5 -106
  62. data/lib/contrast/agent/assess/policy/policy_scanner.rb +2 -2
  63. data/lib/contrast/agent/assess/policy/preshift.rb +1 -1
  64. data/lib/contrast/agent/assess/policy/propagation_method.rb +69 -35
  65. data/lib/contrast/agent/assess/policy/propagation_node.rb +7 -2
  66. data/lib/contrast/agent/assess/policy/propagator.rb +1 -0
  67. data/lib/contrast/agent/assess/policy/propagator/base.rb +1 -1
  68. data/lib/contrast/agent/assess/policy/propagator/custom.rb +1 -1
  69. data/lib/contrast/agent/assess/policy/propagator/database_write.rb +1 -3
  70. data/lib/contrast/agent/assess/policy/propagator/insert.rb +1 -4
  71. data/lib/contrast/agent/assess/policy/propagator/match_data.rb +88 -0
  72. data/lib/contrast/agent/assess/policy/propagator/remove.rb +6 -11
  73. data/lib/contrast/agent/assess/policy/propagator/select.rb +35 -22
  74. data/lib/contrast/agent/assess/policy/propagator/split.rb +28 -8
  75. data/lib/contrast/agent/assess/policy/propagator/substitution.rb +6 -4
  76. data/lib/contrast/agent/assess/policy/propagator/trim.rb +6 -10
  77. data/lib/contrast/agent/assess/policy/rewriter_patch.rb +37 -26
  78. data/lib/contrast/agent/assess/policy/source_method.rb +21 -22
  79. data/lib/contrast/agent/assess/policy/source_node.rb +0 -15
  80. data/lib/contrast/agent/assess/policy/trigger/reflected_xss.rb +90 -0
  81. data/lib/contrast/agent/assess/policy/trigger/xpath.rb +57 -0
  82. data/lib/contrast/agent/assess/policy/trigger_method.rb +29 -52
  83. data/lib/contrast/agent/assess/policy/trigger_node.rb +23 -11
  84. data/lib/contrast/agent/assess/policy/trigger_validation/ssrf_validator.rb +2 -31
  85. data/lib/contrast/agent/assess/properties.rb +4 -380
  86. data/lib/contrast/agent/assess/property/evented.rb +78 -0
  87. data/lib/contrast/agent/assess/property/tagged.rb +339 -0
  88. data/lib/contrast/agent/assess/rule/base.rb +1 -20
  89. data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +6 -7
  90. data/lib/contrast/agent/assess/rule/redos.rb +4 -5
  91. data/lib/contrast/agent/assess/tag.rb +51 -26
  92. data/lib/contrast/agent/at_exit_hook.rb +18 -13
  93. data/lib/contrast/agent/class_reopener.rb +23 -8
  94. data/lib/contrast/agent/deadzone/policy/policy.rb +2 -2
  95. data/lib/contrast/agent/disable_reaction.rb +3 -4
  96. data/lib/contrast/agent/exclusion_matcher.rb +9 -50
  97. data/lib/contrast/agent/inventory/policy/datastores.rb +53 -0
  98. data/lib/contrast/agent/inventory/policy/policy.rb +1 -1
  99. data/lib/contrast/agent/middleware.rb +95 -266
  100. data/lib/contrast/agent/module_data.rb +2 -1
  101. data/lib/contrast/agent/patching/policy/after_load_patch.rb +13 -3
  102. data/lib/contrast/agent/patching/policy/after_load_patcher.rb +59 -47
  103. data/lib/contrast/agent/patching/policy/method_policy.rb +3 -3
  104. data/lib/contrast/agent/patching/policy/module_policy.rb +0 -25
  105. data/lib/contrast/agent/patching/policy/patch.rb +97 -23
  106. data/lib/contrast/agent/patching/policy/patcher.rb +28 -30
  107. data/lib/contrast/agent/patching/policy/policy.rb +10 -10
  108. data/lib/contrast/agent/patching/policy/policy_node.rb +5 -13
  109. data/lib/contrast/agent/patching/policy/trigger_node.rb +2 -5
  110. data/lib/contrast/agent/protect/policy/applies_command_injection_rule.rb +63 -0
  111. data/lib/contrast/agent/protect/policy/applies_deserialization_rule.rb +52 -0
  112. data/lib/contrast/agent/protect/policy/applies_no_sqli_rule.rb +68 -0
  113. data/lib/contrast/agent/protect/policy/applies_path_traversal_rule.rb +117 -0
  114. data/lib/contrast/agent/protect/policy/applies_sqli_rule.rb +54 -0
  115. data/lib/contrast/agent/protect/policy/applies_xxe_rule.rb +129 -0
  116. data/lib/contrast/agent/protect/policy/policy.rb +6 -6
  117. data/lib/contrast/agent/protect/policy/rule_applicator.rb +51 -0
  118. data/lib/contrast/agent/protect/rule.rb +0 -5
  119. data/lib/contrast/agent/protect/rule/base.rb +38 -68
  120. data/lib/contrast/agent/protect/rule/base_service.rb +4 -2
  121. data/lib/contrast/agent/protect/rule/cmd_injection.rb +12 -15
  122. data/lib/contrast/agent/protect/rule/default_scanner.rb +0 -13
  123. data/lib/contrast/agent/protect/rule/deserialization.rb +2 -0
  124. data/lib/contrast/agent/protect/rule/http_method_tampering.rb +4 -9
  125. data/lib/contrast/agent/protect/rule/no_sqli.rb +4 -4
  126. data/lib/contrast/agent/protect/rule/path_traversal.rb +6 -10
  127. data/lib/contrast/agent/protect/rule/sqli.rb +5 -4
  128. data/lib/contrast/agent/protect/rule/unsafe_file_upload.rb +2 -0
  129. data/lib/contrast/agent/protect/rule/xss.rb +2 -0
  130. data/lib/contrast/agent/protect/rule/xxe.rb +11 -4
  131. data/lib/contrast/agent/railtie.rb +3 -8
  132. data/lib/contrast/agent/reaction_processor.rb +7 -7
  133. data/lib/contrast/agent/request.rb +93 -339
  134. data/lib/contrast/agent/request_context.rb +27 -30
  135. data/lib/contrast/agent/request_handler.rb +35 -0
  136. data/lib/contrast/agent/response.rb +22 -100
  137. data/lib/contrast/agent/rewriter.rb +22 -10
  138. data/lib/contrast/agent/rule_set.rb +49 -0
  139. data/lib/contrast/agent/scope.rb +1 -7
  140. data/lib/contrast/agent/service_heartbeat.rb +9 -12
  141. data/lib/contrast/agent/static_analysis.rb +41 -0
  142. data/lib/contrast/agent/thread.rb +1 -1
  143. data/lib/contrast/agent/thread_watcher.rb +49 -0
  144. data/lib/contrast/agent/tracepoint_hook.rb +1 -5
  145. data/lib/contrast/agent/version.rb +1 -1
  146. data/lib/contrast/agent/worker_thread.rb +24 -0
  147. data/lib/contrast/api.rb +4 -6
  148. data/lib/contrast/api/communication.rb +20 -0
  149. data/lib/contrast/api/communication/connection_status.rb +41 -0
  150. data/lib/contrast/api/communication/messaging_queue.rb +79 -0
  151. data/lib/contrast/api/communication/response_processor.rb +77 -0
  152. data/lib/contrast/api/communication/service_lifecycle.rb +61 -0
  153. data/lib/contrast/api/communication/socket.rb +45 -0
  154. data/lib/contrast/api/communication/socket_client.rb +76 -0
  155. data/lib/contrast/api/communication/speedracer.rb +111 -0
  156. data/lib/contrast/api/communication/tcp_socket.rb +31 -0
  157. data/lib/contrast/api/communication/unix_socket.rb +27 -0
  158. data/lib/contrast/api/decorators.rb +24 -0
  159. data/lib/contrast/api/decorators/address.rb +60 -0
  160. data/lib/contrast/api/decorators/application_settings.rb +41 -0
  161. data/lib/contrast/api/decorators/application_update.rb +57 -0
  162. data/lib/contrast/api/decorators/http_request.rb +139 -0
  163. data/lib/contrast/api/decorators/input_analysis.rb +17 -0
  164. data/lib/contrast/api/decorators/message.rb +75 -0
  165. data/lib/contrast/api/decorators/rasp_rule_sample.rb +28 -0
  166. data/lib/contrast/api/decorators/route_coverage.rb +57 -0
  167. data/lib/contrast/api/decorators/server_features.rb +24 -0
  168. data/lib/contrast/api/decorators/trace_event.rb +99 -0
  169. data/lib/contrast/api/decorators/trace_event_object.rb +57 -0
  170. data/lib/contrast/api/decorators/trace_event_signature.rb +46 -0
  171. data/lib/contrast/api/decorators/trace_taint_range.rb +51 -0
  172. data/lib/contrast/api/decorators/trace_taint_range_tags.rb +109 -0
  173. data/lib/contrast/api/decorators/user_input.rb +40 -0
  174. data/lib/contrast/components/agent.rb +34 -24
  175. data/lib/contrast/components/app_context.rb +39 -39
  176. data/lib/contrast/components/assess.rb +25 -15
  177. data/lib/contrast/components/config.rb +11 -14
  178. data/lib/contrast/components/contrast_service.rb +23 -71
  179. data/lib/contrast/components/heap_dump.rb +12 -8
  180. data/lib/contrast/components/interface.rb +16 -23
  181. data/lib/contrast/components/inventory.rb +5 -1
  182. data/lib/contrast/components/logger.rb +3 -68
  183. data/lib/contrast/components/protect.rb +40 -4
  184. data/lib/contrast/components/sampling.rb +22 -11
  185. data/lib/contrast/components/scope.rb +2 -52
  186. data/lib/contrast/components/settings.rb +36 -23
  187. data/lib/contrast/config/base_configuration.rb +1 -0
  188. data/lib/contrast/config/default_value.rb +1 -0
  189. data/lib/contrast/config/protect_rule_configuration.rb +0 -14
  190. data/lib/contrast/config/protect_rules_configuration.rb +0 -1
  191. data/lib/contrast/configuration.rb +2 -2
  192. data/lib/contrast/{extensions/ruby_core → extension}/assess.rb +12 -16
  193. data/lib/contrast/extension/assess/array.rb +77 -0
  194. data/lib/contrast/{extensions/ruby_core → extension}/assess/assess_extension.rb +28 -24
  195. data/lib/contrast/{extensions/ruby_core → extension}/assess/erb.rb +0 -8
  196. data/lib/contrast/extension/assess/eval_trigger.rb +78 -0
  197. data/lib/contrast/{extensions/ruby_core → extension}/assess/exec_trigger.rb +7 -9
  198. data/lib/contrast/extension/assess/fiber.rb +113 -0
  199. data/lib/contrast/extension/assess/hash.rb +39 -0
  200. data/lib/contrast/extension/assess/kernel.rb +110 -0
  201. data/lib/contrast/extension/assess/regexp.rb +84 -0
  202. data/lib/contrast/{extensions/ruby_core → extension}/assess/string.rb +19 -11
  203. data/lib/contrast/{extensions/ruby_core → extension}/delegator.rb +0 -0
  204. data/lib/contrast/{extensions/ruby_core → extension}/inventory.rb +2 -3
  205. data/lib/contrast/extension/kernel.rb +54 -0
  206. data/lib/contrast/{extensions/ruby_core → extension}/module.rb +0 -0
  207. data/lib/contrast/{extensions/ruby_core → extension}/protect.rb +2 -2
  208. data/lib/contrast/extension/protect/kernel.rb +44 -0
  209. data/lib/contrast/{extensions/ruby_core → extension}/protect/psych.rb +1 -1
  210. data/lib/contrast/{extensions/ruby_core → extension}/thread.rb +0 -0
  211. data/lib/contrast/framework/base_support.rb +28 -19
  212. data/lib/contrast/framework/manager.rb +57 -15
  213. data/lib/contrast/framework/platform_version.rb +1 -0
  214. data/lib/contrast/framework/rack/patch/session_cookie.rb +126 -0
  215. data/lib/contrast/framework/rack/patch/support.rb +24 -0
  216. data/lib/contrast/framework/rack/support.rb +22 -0
  217. data/lib/contrast/framework/rails/patch/action_controller_live_buffer.rb +41 -0
  218. data/lib/contrast/framework/rails/patch/assess_configuration.rb +102 -0
  219. data/lib/contrast/framework/rails/patch/rails_application_configuration.rb +31 -0
  220. data/lib/contrast/framework/rails/patch/support.rb +67 -0
  221. data/lib/contrast/framework/rails/rewrite/action_controller_railties_helper_inherited.rb +34 -0
  222. data/lib/contrast/framework/rails/rewrite/active_record_attribute_methods_read.rb +39 -0
  223. data/lib/contrast/framework/rails/rewrite/active_record_named.rb +73 -0
  224. data/lib/contrast/framework/rails/rewrite/active_record_time_zone_inherited.rb +33 -0
  225. data/lib/contrast/framework/rails/support.rb +86 -0
  226. data/lib/contrast/framework/sinatra/patch/base.rb +83 -0
  227. data/lib/contrast/framework/sinatra/patch/support.rb +27 -0
  228. data/lib/contrast/framework/sinatra/support.rb +98 -0
  229. data/lib/contrast/funchook/funchook.rb +45 -0
  230. data/lib/contrast/logger/application.rb +80 -0
  231. data/lib/contrast/logger/format.rb +51 -0
  232. data/lib/contrast/logger/log.rb +149 -0
  233. data/lib/contrast/logger/time.rb +50 -0
  234. data/lib/contrast/tasks/config.rb +54 -0
  235. data/lib/contrast/tasks/service.rb +3 -13
  236. data/lib/contrast/utils/assess/sampling_util.rb +4 -9
  237. data/lib/contrast/utils/assess/tracking_util.rb +51 -20
  238. data/lib/contrast/utils/boolean_util.rb +2 -2
  239. data/lib/contrast/utils/class_util.rb +24 -3
  240. data/lib/contrast/utils/gemfile_reader.rb +7 -5
  241. data/lib/contrast/utils/hash_digest.rb +13 -13
  242. data/lib/contrast/utils/heap_dump_util.rb +12 -11
  243. data/lib/contrast/utils/invalid_configuration_util.rb +3 -19
  244. data/lib/contrast/utils/inventory_util.rb +4 -9
  245. data/lib/contrast/utils/io_util.rb +1 -11
  246. data/lib/contrast/utils/job_servers_running.rb +6 -4
  247. data/lib/contrast/utils/object_share.rb +1 -29
  248. data/lib/contrast/utils/os.rb +16 -28
  249. data/lib/contrast/utils/stack_trace_utils.rb +85 -182
  250. data/lib/contrast/utils/string_utils.rb +18 -2
  251. data/lib/contrast/utils/tag_util.rb +12 -2
  252. data/lib/contrast/utils/thread_tracker.rb +1 -14
  253. data/lib/contrast/utils/timer.rb +1 -57
  254. data/resources/assess/policy.json +42 -71
  255. data/resources/inventory/policy.json +2 -2
  256. data/resources/protect/policy.json +15 -15
  257. data/ruby-agent.gemspec +14 -7
  258. data/service_executables/VERSION +1 -1
  259. data/service_executables/linux/contrast-service +0 -0
  260. data/service_executables/mac/contrast-service +0 -0
  261. metadata +153 -164
  262. data/ext/cs__assess_regexp_track/cs__assess_regexp_track.c +0 -63
  263. data/ext/cs__assess_regexp_track/cs__assess_regexp_track.h +0 -29
  264. data/ext/cs__assess_regexp_track/extconf.rb +0 -2
  265. data/funchook/Makefile +0 -29
  266. data/funchook/autom4te.cache/output.0 +0 -4976
  267. data/funchook/autom4te.cache/requests +0 -78
  268. data/funchook/autom4te.cache/traces.0 +0 -364
  269. data/funchook/config.log +0 -490
  270. data/funchook/config.status +0 -1016
  271. data/funchook/configure +0 -4976
  272. data/funchook/src/Makefile +0 -70
  273. data/funchook/src/config.h +0 -101
  274. data/funchook/src/config.h.in +0 -100
  275. data/funchook/src/decoder.o +0 -0
  276. data/funchook/src/distorm.o +0 -0
  277. data/funchook/src/funchook.o +0 -0
  278. data/funchook/src/funchook_io.o +0 -0
  279. data/funchook/src/funchook_syscall.o +0 -0
  280. data/funchook/src/funchook_unix.o +0 -0
  281. data/funchook/src/funchook_x86.o +0 -0
  282. data/funchook/src/instructions.o +0 -0
  283. data/funchook/src/insts.o +0 -0
  284. data/funchook/src/libfunchook.so +0 -0
  285. data/funchook/src/mnemonics.o +0 -0
  286. data/funchook/src/operands.o +0 -0
  287. data/funchook/src/os_func.o +0 -0
  288. data/funchook/src/os_func_unix.o +0 -0
  289. data/funchook/src/prefix.o +0 -0
  290. data/funchook/src/printf_base.o +0 -0
  291. data/funchook/src/textdefs.o +0 -0
  292. data/funchook/src/wstring.o +0 -0
  293. data/funchook/test/Makefile +0 -43
  294. data/funchook/test/funchook_test +0 -0
  295. data/funchook/test/libfunchook_test.so +0 -0
  296. data/funchook/test/test_main.o +0 -0
  297. data/funchook/test/x86_64_test.o +0 -0
  298. data/lib/contrast/agent/assess/adjusted_span.rb +0 -25
  299. data/lib/contrast/agent/assess/frozen_properties.rb +0 -41
  300. data/lib/contrast/agent/assess/rule/csrf.rb +0 -66
  301. data/lib/contrast/agent/assess/rule/csrf/csrf_action.rb +0 -28
  302. data/lib/contrast/agent/assess/rule/csrf/csrf_applicator.rb +0 -73
  303. data/lib/contrast/agent/assess/rule/csrf/csrf_watcher.rb +0 -132
  304. data/lib/contrast/agent/assess/rule/response_scanning_rule.rb +0 -47
  305. data/lib/contrast/agent/assess/rule/response_watcher.rb +0 -36
  306. data/lib/contrast/agent/assess/rule/watcher.rb +0 -36
  307. data/lib/contrast/agent/feature_state.rb +0 -376
  308. data/lib/contrast/agent/logger_manager.rb +0 -116
  309. data/lib/contrast/agent/protect/rule/csrf.rb +0 -118
  310. data/lib/contrast/agent/protect/rule/csrf/csrf_evaluator.rb +0 -103
  311. data/lib/contrast/agent/protect/rule/csrf/csrf_token_injector.rb +0 -85
  312. data/lib/contrast/agent/settings_state.rb +0 -152
  313. data/lib/contrast/agent/socket_client.rb +0 -128
  314. data/lib/contrast/api/connection_status.rb +0 -49
  315. data/lib/contrast/api/socket.rb +0 -43
  316. data/lib/contrast/api/speedracer.rb +0 -184
  317. data/lib/contrast/api/tcp_socket.rb +0 -31
  318. data/lib/contrast/api/unix_socket.rb +0 -25
  319. data/lib/contrast/delegators.rb +0 -9
  320. data/lib/contrast/delegators/application_update.rb +0 -32
  321. data/lib/contrast/extensions/framework/rack/cookie.rb +0 -24
  322. data/lib/contrast/extensions/framework/rack/request.rb +0 -24
  323. data/lib/contrast/extensions/framework/rack/response.rb +0 -23
  324. data/lib/contrast/extensions/framework/rails/action_controller_railties_helper_inherited.rb +0 -20
  325. data/lib/contrast/extensions/framework/rails/active_record.rb +0 -26
  326. data/lib/contrast/extensions/framework/rails/active_record_named.rb +0 -53
  327. data/lib/contrast/extensions/framework/rails/active_record_time_zone_inherited.rb +0 -21
  328. data/lib/contrast/extensions/framework/rails/buffer.rb +0 -28
  329. data/lib/contrast/extensions/framework/rails/configuration.rb +0 -27
  330. data/lib/contrast/extensions/framework/sinatra/base.rb +0 -59
  331. data/lib/contrast/extensions/ruby_core/assess/array.rb +0 -59
  332. data/lib/contrast/extensions/ruby_core/assess/basic_object.rb +0 -15
  333. data/lib/contrast/extensions/ruby_core/assess/fiber.rb +0 -124
  334. data/lib/contrast/extensions/ruby_core/assess/hash.rb +0 -22
  335. data/lib/contrast/extensions/ruby_core/assess/kernel.rb +0 -95
  336. data/lib/contrast/extensions/ruby_core/assess/module.rb +0 -14
  337. data/lib/contrast/extensions/ruby_core/assess/regexp.rb +0 -206
  338. data/lib/contrast/extensions/ruby_core/assess/tilt_template_trigger.rb +0 -73
  339. data/lib/contrast/extensions/ruby_core/assess/xpath_library_trigger.rb +0 -40
  340. data/lib/contrast/extensions/ruby_core/eval_trigger.rb +0 -52
  341. data/lib/contrast/extensions/ruby_core/inventory/datastores.rb +0 -37
  342. data/lib/contrast/extensions/ruby_core/protect/applies_command_injection_rule.rb +0 -72
  343. data/lib/contrast/extensions/ruby_core/protect/applies_deserialization_rule.rb +0 -60
  344. data/lib/contrast/extensions/ruby_core/protect/applies_no_sqli_rule.rb +0 -83
  345. data/lib/contrast/extensions/ruby_core/protect/applies_path_traversal_rule.rb +0 -123
  346. data/lib/contrast/extensions/ruby_core/protect/applies_sqli_rule.rb +0 -65
  347. data/lib/contrast/extensions/ruby_core/protect/applies_xxe_rule.rb +0 -143
  348. data/lib/contrast/extensions/ruby_core/protect/kernel.rb +0 -30
  349. data/lib/contrast/framework/rails_support.rb +0 -88
  350. data/lib/contrast/framework/sinatra_application_helper.rb +0 -49
  351. data/lib/contrast/framework/sinatra_support.rb +0 -94
  352. data/lib/contrast/framework/view_technologies_descriptor.rb +0 -20
  353. data/lib/contrast/internal_exception.rb +0 -8
  354. data/lib/contrast/utils/cache.rb +0 -69
  355. data/lib/contrast/utils/comment_range.rb +0 -19
  356. data/lib/contrast/utils/data_store_util.rb +0 -23
  357. data/lib/contrast/utils/environment_util.rb +0 -81
  358. data/lib/contrast/utils/performs_logging.rb +0 -152
  359. data/lib/contrast/utils/rack_assess_session_cookie.rb +0 -104
  360. data/lib/contrast/utils/rails_assess_configuration.rb +0 -95
  361. data/lib/contrast/utils/random_util.rb +0 -22
  362. data/lib/contrast/utils/service_response_util.rb +0 -110
  363. data/lib/contrast/utils/service_sender_util.rb +0 -106
  364. data/lib/contrast/utils/sinatra_helper.rb +0 -55
  365. data/resources/csrf/inject.js +0 -44
  366. data/resources/factory-bot-spec/spec_helper.rb +0 -30
  367. data/resources/rubocops/kernel/catch_cop.rb +0 -37
  368. data/resources/rubocops/kernel/require_cop.rb +0 -37
  369. data/resources/rubocops/kernel/require_relative_cop.rb +0 -33
  370. data/resources/rubocops/module/autoload_cop.rb +0 -37
  371. data/resources/rubocops/module/const_defined_cop.rb +0 -37
  372. data/resources/rubocops/module/const_get_cop.rb +0 -37
  373. data/resources/rubocops/module/const_set_cop.rb +0 -37
  374. data/resources/rubocops/module/constants_cop.rb +0 -37
  375. data/resources/rubocops/module/name_cop.rb +0 -37
  376. data/resources/rubocops/object/class_cop.rb +0 -37
  377. data/resources/rubocops/object/freeze_cop.rb +0 -37
  378. data/resources/rubocops/object/frozen_cop.rb +0 -37
  379. data/resources/rubocops/object/is_a_cop.rb +0 -37
  380. data/resources/rubocops/object/method_cop.rb +0 -37
  381. data/resources/rubocops/object/respond_to_cop.rb +0 -37
  382. data/resources/rubocops/object/singleton_class_cop.rb +0 -37
  383. data/resources/rubocops/regexp/spelling_cop.rb +0 -44
  384. data/resources/rubocops/thread/new_cop.rb +0 -39
  385. data/resources/ruby-spec/ancestors_spec.rb +0 -70
  386. data/resources/ruby-spec/modulo_spec.rb +0 -831
  387. data/resources/ruby-spec/parameters_spec.rb +0 -261
  388. data/resources/ruby-spec/ruby_spec_spec_helper.rb +0 -35
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 820720cd5c39b14ced3612d327179d48901c63fc196a9f8c99716d35f53115e4
4
- data.tar.gz: b7a25f4bb481df7bade588d2d7cf7cc70024176d48b9c76a0b65bed99bc49e78
3
+ metadata.gz: 64a4e6fe5f8f75e8ab4bb911e696330a10e1a3edb95c027a03dd0b8704e23f3e
4
+ data.tar.gz: f031d456741cb0d955030805efd73f8cb2495ca7c927a15121c5ef88a6d86ec7
5
5
  SHA512:
6
- metadata.gz: 24a2efa0ed4aab95794c773220f90895a584fc60c8eac499d9789e1e0c9138d4ea12cc33a482227ceb7226e03a9b98801b37070d60f93dc92f84f54636b3ff43
7
- data.tar.gz: 5d7ee9d12c77e0c5242b31f0b4f09efec75b969ef02b9c6ec915d9ae06dc393824b9de1f0cbb40ea7aef1aa4b9793550564e70a4d7448ba8f5485930ccd1fbeb
6
+ metadata.gz: e2fac539c17b2cb20ab407f6ded931316f97529073907a3f03ee7ef8774a2e18a597d5c47406e44cb86111338e7d31170399543a1778bb7154eaf618b4e03635
7
+ data.tar.gz: 44e2552f7ee995f73514c62b10002096fcf8f462bdbc573cceb623f9a42786c2421d16490962a9575d777a792fd9ea459d41630e2de9cf60e55c61ecc0fb8403
@@ -4,7 +4,6 @@ docker/
4
4
  code-deploy/
5
5
 
6
6
  Jenkinsfile
7
- bitbucket-pipelines.yml
8
7
  docker-compose.yml
9
8
  .rubocop.yml
10
9
  .travis.yml
@@ -0,0 +1 @@
1
+ ./lib/contrast/api/*_pb.rb
data/.gitignore CHANGED
@@ -52,7 +52,7 @@ contrast-agent-*.gem
52
52
  service_executables/*-*
53
53
 
54
54
  # Generated Protobuf files
55
- /lib/contrast/api/*_pb.rb
55
+ /lib/contrast/api/*.pb.rb
56
56
 
57
57
  # IDE stuff
58
58
  tags
data/.simplecov CHANGED
@@ -1,4 +1,7 @@
1
- SimpleCov.minimum_coverage 92.30
1
+ # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ SimpleCov.minimum_coverage line: 94.75
2
5
  SimpleCov.start do
3
6
  add_filter '/spec/'
4
- end
7
+ end
data/Rakefile CHANGED
@@ -1,9 +1,13 @@
1
1
  # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
+ $stdout.sync = true
5
+
4
6
  require 'bundler/gem_tasks'
5
7
  require 'rspec/core/rake_task'
6
8
  require 'rake/extensiontask'
9
+ load 'protobuf/tasks/compile.rake'
10
+ require 'fileutils'
7
11
 
8
12
  CLOBBER << 'shared_libraries/*'
9
13
 
@@ -13,3 +17,30 @@ Dir['ext/cs__*'].each do |extension|
13
17
  ext.lib_dir = "lib/#{ name }"
14
18
  end
15
19
  end
20
+
21
+ task :contrast_pb_compile do
22
+ # do some stuff before compile
23
+
24
+ # Invoke the protobuf compile task with your sensible defaults
25
+ ::Rake::Task['protobuf:compile'].invoke('lib',
26
+ './agent-service-api/protobuf ./agent-service-api/protobuf/dtm.proto',
27
+ 'lib/contrast/api',
28
+ nil)
29
+
30
+ ::Rake::Task['protobuf:compile'].reenable
31
+
32
+ ::Rake::Task['protobuf:compile'].invoke('lib',
33
+ './agent-service-api/protobuf ./agent-service-api/protobuf/settings.proto',
34
+ 'lib/contrast/api',
35
+ nil)
36
+
37
+ ['dtm.pb.rb', 'settings.pb.rb'].each do |target_file|
38
+ target_path = File.absolute_path(File.join(__dir__, "./lib/contrast/api/#{ target_file }"))
39
+ unless File.exist?(target_path)
40
+ puts "File not found #{ target_path }"
41
+ exit 1
42
+ end
43
+ end
44
+
45
+ puts 'Protobuf copied successfully'
46
+ end
@@ -31,15 +31,15 @@ unless find_header('funchook.h', ext_path)
31
31
  end
32
32
 
33
33
  SOURCE_PATHS = [
34
- File.join('include', 'funchook.h'),
35
- File.join('src', 'libfunchook.dylib'),
36
- File.join('src', 'libfunchook.so')
34
+ File.join('include', 'funchook.h'),
35
+ File.join('src', 'libfunchook.dylib'),
36
+ File.join('src', 'libfunchook.so')
37
37
  ].freeze
38
38
 
39
39
  TARGET_PATHS = ([
40
- File.expand_path(File.join(File.expand_path(__dir__), '..', 'shared_libraries')),
41
- File.expand_path(__dir__)
42
- ] + (bundler_install_target_paths)).freeze
40
+ File.expand_path(File.join(File.expand_path(__dir__), '..', 'shared_libraries')),
41
+ File.expand_path(__dir__)
42
+ ] + bundler_install_target_paths).freeze
43
43
 
44
44
  puts 'Copying required files'
45
45
 
@@ -51,20 +51,14 @@ unless find_header('funchook.h', ext_path)
51
51
  end
52
52
 
53
53
  TARGET_PATHS.each do |target_path|
54
- begin
55
- unless File.writable?(target_path)
56
- puts "Unable to copy into #{target_path} - directory not writable"
57
- next
58
- end
59
- puts "Copying #{ source_file_path } into #{ target_path }"
60
- FileUtils.cp(source_file_path, target_path)
61
- rescue
62
- puts "Error while copying #{source_file} to #{target_path}"
54
+ unless File.writable?(target_path)
55
+ puts "Unable to copy into #{ target_path } - directory not writable"
56
+ next
63
57
  end
58
+ puts "Copying #{ source_file_path } into #{ target_path }"
59
+ FileUtils.cp(source_file_path, target_path)
60
+ rescue StandardError
61
+ puts "Error while copying #{ source_file } to #{ target_path }"
64
62
  end
65
63
  end
66
64
  end
67
-
68
-
69
-
70
- have_header('funchook.h', ext_path)
@@ -3,6 +3,7 @@
3
3
 
4
4
  #include "cs__active_record_named.h"
5
5
  #include <ruby.h>
6
+ #include "../cs__common/cs__common.h"
6
7
 
7
8
  VALUE contrast_assess_active_record_scope(const int argc, const VALUE *argv,
8
9
  const VALUE self) {
@@ -18,7 +19,7 @@ VALUE contrast_assess_active_record_scope(const int argc, const VALUE *argv,
18
19
  */
19
20
  VALUE new_body, ret;
20
21
  VALUE new_args[3];
21
- new_body = rb_funcall(self, rb_sym_assess_rewrite, 2, argv[0], argv[1]);
22
+ new_body = rb_funcall(active_record_named, rb_sym_assess_rewrite, 3, self, argv[0], argv[1]);
22
23
  new_args[0] = argv[0];
23
24
  if (NIL_P(new_body)) {
24
25
  new_args[1] = argv[1];
@@ -31,17 +32,14 @@ VALUE contrast_assess_active_record_scope(const int argc, const VALUE *argv,
31
32
  }
32
33
 
33
34
  void Init_cs__assess_active_record_named(void) {
34
- rb_sym_assess_rewrite = rb_intern("_cs__rewrite");
35
- rb_sym_assess_scope = rb_intern("cs__patched_scope");
36
-
37
- VALUE active_record_module = rb_define_module("ActiveRecord");
38
- VALUE scoping_module =
39
- rb_define_module_under(active_record_module, "Scoping");
40
- VALUE named_module = rb_define_module_under(scoping_module, "Named");
41
- VALUE class_methods_module =
42
- rb_define_module_under(named_module, "ClassMethods");
43
-
44
- contrast_alias_method(class_methods_module, "cs__patched_scope", "scope");
45
- rb_define_method(class_methods_module, "scope",
46
- contrast_assess_active_record_scope, -1);
35
+ VALUE framework, rails, rewrite;
36
+ framework = rb_define_module_under(contrast, "Framework");
37
+ rails = rb_define_module_under(framework, "Rails");
38
+ rewrite = rb_define_module_under(rails, "Rewrite");
39
+ active_record_named = rb_define_class_under(rewrite, "ActiveRecordNamed", rb_cObject);
40
+ rb_sym_assess_rewrite = rb_intern("rewrite");
41
+ rb_sym_assess_scope = contrast_register_patch("ActiveRecord::Scoping::Named::ClassMethods",
42
+ "scope",
43
+ contrast_assess_active_record_scope);
47
44
  }
45
+
@@ -1,5 +1,6 @@
1
1
  #include <ruby.h>
2
2
 
3
+ static VALUE active_record_named;
3
4
  static VALUE rb_sym_assess_rewrite;
4
5
  static VALUE rb_sym_assess_scope;
5
6
 
@@ -1,2 +1,5 @@
1
+ # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
1
4
  $TO_MAKE = File.basename(__dir__)
2
5
  require_relative '../extconf_common'
@@ -23,16 +23,15 @@ static VALUE contrast_assess_array_join(const int argc, const VALUE *argv,
23
23
  /* Finally, default to empty String. Implicit since nil.to_s is ''*/
24
24
 
25
25
  result = rb_funcall2(ary, rb_sym_assess_array_join, argc, argv);
26
- result = rb_funcall(ary, rb_sym_assess_track_array_join, 2, sep, result);
26
+ result = rb_funcall(array_propagator, rb_sym_assess_track_array_join, 3, ary, sep, result);
27
27
 
28
28
  return result;
29
29
  }
30
30
 
31
31
  void Init_cs__assess_array(void) {
32
- rb_sym_assess_array_join = rb_intern("cs__patched_join");
32
+ array_propagator = rb_define_class_under(core_assess, "ArrayPropagator", rb_cObject);
33
33
  rb_sym_assess_track_array_join = rb_intern("cs__track_join");
34
-
35
- VALUE array_class = rb_define_class("Array", rb_cObject);
36
- contrast_alias_method(array_class, "cs__patched_join", "join");
37
- rb_define_method(array_class, "join", contrast_assess_array_join, -1);
34
+ rb_sym_assess_array_join = contrast_register_patch("Array",
35
+ "join",
36
+ contrast_assess_array_join);
38
37
  }
@@ -1,5 +1,6 @@
1
1
  #include <ruby.h>
2
2
 
3
+ static VALUE array_propagator;
3
4
  static VALUE rb_sym_assess_array_join;
4
5
  static VALUE rb_sym_assess_track_array_join;
5
6
 
@@ -1,2 +1,5 @@
1
+ # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
1
4
  $TO_MAKE = File.basename(__dir__)
2
5
  require_relative '../extconf_common'
@@ -5,14 +5,9 @@
5
5
  #include "../cs__common/cs__common.h"
6
6
  #include <ruby.h>
7
7
 
8
- void contrast_assess_instance_eval_trigger_check(VALUE module, VALUE source,
8
+ void contrast_assess_instance_eval_trigger_check(VALUE self, VALUE source,
9
9
  VALUE ret) {
10
- VALUE has_trigger_check =
11
- rb_respond_to(rb_cBasicObject, instance_trigger_check_method);
12
- if (has_trigger_check) {
13
- rb_funcall(rb_cBasicObject, instance_trigger_check_method, 2, source,
14
- ret);
15
- }
10
+ rb_funcall(basic_eval_trigger, instance_trigger_check_method, 3, self, source, ret);
16
11
  }
17
12
 
18
13
  VALUE
@@ -41,10 +36,17 @@ contrast_assess_basic_object_instance_eval(const int argc, const VALUE *argv,
41
36
  }
42
37
 
43
38
  void Init_cs__assess_basic_object(void) {
39
+ basic_eval_trigger = rb_define_class_under(core_assess, "EvalTrigger", rb_cObject);
44
40
  instance_trigger_check_method = rb_intern("instance_eval_trigger_check");
45
41
 
46
- contrast_alias_method(rb_cBasicObject, "cs__patched_instance_eval",
47
- "instance_eval");
48
- rb_define_method(rb_cBasicObject, "instance_eval",
49
- contrast_assess_basic_object_instance_eval, -1);
42
+ /* We don't keep a reference to the underlying method.
43
+ * Instead, we call rb_obj_instance_eval directly.
44
+ * This should work an overwhelming majority of the time,
45
+ * but if someone else patched BasicObject#instance_eval,
46
+ * IDK if this is intentional... noting it. -ajm
47
+ */
48
+ contrast_register_patch("BasicObject",
49
+ "instance_eval",
50
+ contrast_assess_basic_object_instance_eval);
51
+
50
52
  }
@@ -1,6 +1,7 @@
1
1
  #include <ruby.h>
2
2
 
3
- /* Contrast::Agent::Patching::Policy::Patcher */
3
+ /* Contrast::Extension::Assess::EvalTrigger */
4
+ static VALUE basic_eval_trigger;
4
5
  static VALUE instance_trigger_check_method;
5
6
 
6
7
  void contrast_alias_method(const VALUE target, const char *to,
@@ -1,2 +1,5 @@
1
+ # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
1
4
  $TO_MAKE = File.basename(__dir__)
2
5
  require_relative '../extconf_common'
@@ -2,7 +2,7 @@
2
2
  * https://www.contrastsecurity.com/enduser-terms-0317a for more details. */
3
3
 
4
4
  #include "cs__assess_fiber_track.h"
5
- #include <funchook.h>
5
+ #include "../cs__common/cs__common.h"
6
6
  #include <ruby.h>
7
7
 
8
8
  VALUE rb_fiber_new_hook(VALUE (*func)(ANYARGS), VALUE obj) {
@@ -44,7 +44,7 @@ VALUE rb_fiber_new_hook(VALUE (*func)(ANYARGS), VALUE obj) {
44
44
  VALUE enumerator_method = ID2SYM(enum_ptr->meth);
45
45
  /* e.g.: 1..100, #each_value. Should reflect #inspect on the enum. */
46
46
 
47
- rb_funcall(fiber_class, track_rb_fiber_new, 5, fiber, obj,
47
+ rb_funcall(fiber_propagator, track_rb_fiber_new, 5, fiber, obj,
48
48
  enumerator_method, underlying, calling_method);
49
49
  }
50
50
 
@@ -56,29 +56,24 @@ VALUE rb_fiber_yield_hook(int argc, const VALUE *argv) {
56
56
  VALUE yielding_fiber = rb_fiber_current();
57
57
 
58
58
  /* propagate from yielding_fiber -> result */
59
- rb_funcall(fiber_class, track_rb_fiber_yield, 3, yielding_fiber,
59
+ rb_funcall(fiber_propagator, track_rb_fiber_yield, 3, yielding_fiber,
60
60
  calling_method, *argv);
61
61
 
62
62
  return rb_fiber_yield_original(argc, argv);
63
63
  }
64
64
 
65
65
  int install_fiber_hooks() {
66
- funchook_t *funchook = funchook_create();
67
-
68
66
  rb_fiber_new_original = rb_fiber_new;
69
- funchook_prepare(funchook, (void **)&rb_fiber_new_original,
70
- rb_fiber_new_hook);
67
+ patch_via_funchook(&rb_fiber_new_original, &rb_fiber_new_hook);
71
68
 
72
69
  rb_fiber_yield_original = rb_fiber_yield;
73
- funchook_prepare(funchook, (void **)&rb_fiber_yield_original,
74
- rb_fiber_yield_hook);
70
+ patch_via_funchook(&rb_fiber_yield_original, &rb_fiber_yield_hook);
75
71
 
76
- funchook_install(funchook, 0);
77
72
  return 0;
78
73
  }
79
74
 
80
75
  void Init_cs__assess_fiber_track(void) {
81
- fiber_class = rb_define_class("Fiber", rb_cObject);
76
+ fiber_propagator = rb_define_class_under(core_assess, "FiberPropagator", rb_cObject);
82
77
  track_rb_fiber_new = rb_intern("track_rb_fiber_new");
83
78
  track_rb_fiber_yield = rb_intern("track_rb_fiber_yield");
84
79
  rb_sym_next = rb_intern("next");
@@ -1,16 +1,15 @@
1
- #include <funchook.h>
2
1
  #include <ruby.h>
3
2
 
4
3
  static VALUE rb_sym_next;
5
- static VALUE fiber_class;
4
+ static VALUE fiber_propagator;
6
5
  static VALUE track_rb_fiber_new;
7
6
  static VALUE track_rb_fiber_yield;
8
7
 
9
8
  VALUE rb_fiber_new(VALUE (*func)(ANYARGS), VALUE obj);
10
- VALUE *(*rb_fiber_new_original)(VALUE (*func)(ANYARGS), VALUE obj);
9
+ VALUE (*rb_fiber_new_original)(VALUE (*func)(ANYARGS), VALUE obj);
11
10
 
12
11
  VALUE rb_fiber_yield(int argc, const VALUE *argv);
13
- VALUE *(*rb_fiber_yield_original)(int argc, const VALUE *argv);
12
+ VALUE (*rb_fiber_yield_original)(int argc, const VALUE *argv);
14
13
 
15
14
  /* If you call `#next` on an enumerator object, that enumerator object
16
15
  * instantiates a fiber and runs its given proc inside of that fiber.
@@ -1,2 +1,5 @@
1
+ # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
1
4
  $TO_MAKE = File.basename(__dir__)
2
5
  require_relative '../extconf_common'
@@ -5,7 +5,14 @@
5
5
  #include "../cs__common/cs__common.h"
6
6
  #include <ruby.h>
7
7
 
8
- static VALUE contrast_assess_hash_bracket_get(const int argc, VALUE *argv,
8
+ /* Hashes can be constructed thusly):
9
+ * irb(main):001:0> Hash[:a, :b]
10
+ * => {:a=>:b}
11
+ *
12
+ * This method instruments that unique bracket-construction style
13
+ * of initializing a hash.
14
+ */
15
+ static VALUE contrast_assess_hash_bracket_constructor(const int argc, VALUE *argv,
9
16
  const VALUE hash) {
10
17
  VALUE result;
11
18
 
@@ -14,14 +21,14 @@ static VALUE contrast_assess_hash_bracket_get(const int argc, VALUE *argv,
14
21
  int i;
15
22
  for (i = 0; i < argc; i++) {
16
23
  argv[i] =
17
- rb_funcall(hash, rb_sym_assess_hash_dup_and_freeze, 1, argv[i]);
24
+ rb_funcall(hash_propagator, rb_sym_assess_hash_dup_and_freeze, 1, argv[i]);
18
25
  }
19
26
  /* Hash[ key, value, ... ] -> new_hash */
20
27
  } else if (argc > 1) {
21
28
  int i;
22
29
  for (i = 0; i < argc; i += 2) {
23
30
  argv[i] =
24
- rb_funcall(hash, rb_sym_assess_hash_dup_and_freeze, 1, argv[i]);
31
+ rb_funcall(hash_propagator, rb_sym_assess_hash_dup_and_freeze, 1, argv[i]);
25
32
  }
26
33
  }
27
34
 
@@ -29,36 +36,52 @@ static VALUE contrast_assess_hash_bracket_get(const int argc, VALUE *argv,
29
36
  * String keys
30
37
  * # Hash[ object ] -> new_hash
31
38
  */
32
- result = rb_funcall2(hash, rb_sym_assess_hash_brackets, argc, argv);
39
+ result = rb_funcall2(hash, rb_sym_assess_hash_bracket_constructor, argc, argv);
33
40
 
34
41
  return result;
35
42
  }
36
43
 
44
+ /* Hashes, when keyed with a string, will dup & freeze that string.
45
+ * This is resource-efficient, but inconvenient for instrumentation.
46
+ */
37
47
  static VALUE contrast_assess_hash_bracket_set(const int argc, VALUE *argv,
38
48
  const VALUE hash) {
39
49
  VALUE result;
40
- VALUE key;
41
-
42
- key = rb_funcall2(hash, rb_sym_assess_hash_bracket_set, argc, argv);
43
- argv[0] = key;
50
+ /* Current name (assess_hash_bracket_set).
51
+ * It doesn't set anything on the hash.
52
+ * It takes the arg that /would/ have been the key, and preemptively
53
+ * calls #dup and then #freeze, and then gives you that key.
54
+ *
55
+ * We intentionally don't enter Contrast scope for this patch.
56
+ * #dup instruments the string, and #freeze gets the hash to accept
57
+ * the key directly, without calling its own #dup/#freeze.
58
+ * (That naturally happens in C-land, our instrumentation is in Ruby,
59
+ * so our patches to #dup don't take effect within Hash#[]= unless we
60
+ * specifically do this instrumentation.
61
+ * We haven't revisited this approach since we started more extensively
62
+ * hooking public C functions.)
63
+ */
64
+ if(argc > 0) {
65
+ argv[0] = rb_funcall(hash_propagator, rb_sym_assess_hash_dup_and_freeze, 1, argv[0]);
66
+ }
67
+ /* This is the underlying assignment, w/ our instrumented key. */
44
68
  result = rb_funcall2(hash, rb_sym_assess_hash_bracket_equals, argc, argv);
45
69
 
46
70
  return result;
47
71
  }
48
72
 
49
73
  void Init_cs__assess_hash(void) {
74
+ hash_propagator = rb_define_class_under(core_assess, "HashPropagator", rb_cObject);
50
75
  rb_sym_assess_hash_dup_and_freeze = rb_intern("cs__duplicate_and_freeze");
51
- rb_sym_assess_hash_brackets = rb_intern("cs__patched_[]");
52
- rb_sym_assess_hash_bracket_set = rb_intern("cs__bracket_set");
53
- rb_sym_assess_hash_bracket_equals = rb_intern("cs__patched_[]=");
54
76
 
55
77
  VALUE hash_class = rb_define_class("Hash", rb_cObject);
56
- array_class = rb_define_class("Array", rb_cObject);
57
78
 
58
- VALUE singleton = rb_singleton_class(hash_class);
59
- contrast_alias_method(singleton, "cs__patched_[]", "[]");
60
- rb_define_method(singleton, "[]", contrast_assess_hash_bracket_get, -1);
79
+ rb_sym_assess_hash_bracket_constructor = contrast_register_singleton_patch("Hash",
80
+ "[]",
81
+ contrast_assess_hash_bracket_constructor);
82
+
83
+ rb_sym_assess_hash_bracket_equals = contrast_register_patch("Hash",
84
+ "[]=",
85
+ contrast_assess_hash_bracket_set);
61
86
 
62
- contrast_alias_method(hash_class, "cs__patched_[]=", "[]=");
63
- rb_define_method(hash_class, "[]=", contrast_assess_hash_bracket_set, -1);
64
87
  }