contrast-agent 5.3.0 → 6.1.1

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 (306) hide show
  1. checksums.yaml +4 -4
  2. data/.simplecov +1 -1
  3. data/Rakefile +1 -1
  4. data/ext/build_funchook.rb +3 -3
  5. data/ext/cs__assess_array/cs__assess_array.c +7 -0
  6. data/ext/cs__assess_basic_object/cs__assess_basic_object.c +24 -6
  7. data/ext/cs__assess_fiber_track/cs__assess_fiber_track.c +1 -1
  8. data/ext/cs__assess_hash/cs__assess_hash.c +3 -4
  9. data/ext/cs__assess_kernel/cs__assess_kernel.c +1 -2
  10. data/ext/cs__assess_marshal_module/cs__assess_marshal_module.c +26 -12
  11. data/ext/cs__assess_module/cs__assess_module.c +1 -1
  12. data/ext/cs__assess_regexp/cs__assess_regexp.c +15 -2
  13. data/ext/cs__assess_regexp/cs__assess_regexp.h +2 -0
  14. data/ext/cs__assess_string/cs__assess_string.c +21 -1
  15. data/ext/cs__assess_test/cs__assess_test.h +9 -0
  16. data/ext/cs__assess_test/cs__assess_tests.c +22 -0
  17. data/ext/cs__assess_test/extconf.rb +5 -0
  18. data/ext/cs__common/cs__common.c +113 -11
  19. data/ext/cs__common/cs__common.h +29 -5
  20. data/ext/cs__contrast_patch/cs__contrast_patch.c +55 -44
  21. data/ext/cs__os_information/cs__os_information.c +13 -10
  22. data/ext/cs__scope/cs__scope.c +146 -97
  23. data/ext/cs__tests/cs__tests.c +12 -0
  24. data/ext/cs__tests/cs__tests.h +3 -0
  25. data/ext/cs__tests/extconf.rb +5 -0
  26. data/ext/extconf_common.rb +1 -1
  27. data/lib/contrast/agent/assess/contrast_object.rb +16 -16
  28. data/lib/contrast/agent/assess/events/source_event.rb +17 -19
  29. data/lib/contrast/agent/assess/finalizers/hash.rb +4 -2
  30. data/lib/contrast/agent/assess/policy/policy.rb +9 -10
  31. data/lib/contrast/agent/assess/policy/policy_node.rb +58 -36
  32. data/lib/contrast/agent/assess/policy/policy_node_utils.rb +51 -0
  33. data/lib/contrast/agent/assess/policy/policy_scanner.rb +2 -16
  34. data/lib/contrast/agent/assess/policy/preshift.rb +8 -2
  35. data/lib/contrast/agent/assess/policy/propagation_method.rb +48 -14
  36. data/lib/contrast/agent/assess/policy/propagation_node.rb +2 -3
  37. data/lib/contrast/agent/assess/policy/propagator/base.rb +1 -1
  38. data/lib/contrast/agent/assess/policy/propagator/buffer.rb +119 -0
  39. data/lib/contrast/agent/assess/policy/propagator/database_write.rb +1 -1
  40. data/lib/contrast/agent/assess/policy/propagator/keep.rb +19 -4
  41. data/lib/contrast/agent/assess/policy/propagator/remove.rb +18 -2
  42. data/lib/contrast/agent/assess/policy/propagator/splat.rb +17 -3
  43. data/lib/contrast/agent/assess/policy/propagator/split.rb +17 -21
  44. data/lib/contrast/agent/assess/policy/propagator/substitution.rb +1 -1
  45. data/lib/contrast/agent/assess/policy/propagator/substitution_utils.rb +1 -1
  46. data/lib/contrast/agent/assess/policy/propagator/trim.rb +2 -2
  47. data/lib/contrast/agent/assess/policy/propagator.rb +1 -0
  48. data/lib/contrast/agent/assess/policy/source_method.rb +7 -7
  49. data/lib/contrast/agent/assess/policy/source_node.rb +1 -1
  50. data/lib/contrast/agent/assess/policy/trigger_method.rb +11 -17
  51. data/lib/contrast/agent/assess/policy/trigger_node.rb +16 -16
  52. data/lib/contrast/agent/assess/policy/trigger_validation/redos_validator.rb +1 -1
  53. data/lib/contrast/agent/assess/property/evented.rb +2 -2
  54. data/lib/contrast/agent/assess/property/tagged.rb +3 -3
  55. data/lib/contrast/agent/assess/rule/provider/hardcoded_key.rb +6 -8
  56. data/lib/contrast/agent/assess/rule/provider/hardcoded_password.rb +6 -7
  57. data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +12 -7
  58. data/lib/contrast/agent/assess/rule/response/auto_complete_rule.rb +1 -1
  59. data/lib/contrast/agent/assess/rule/response/base_rule.rb +13 -6
  60. data/lib/contrast/agent/assess/rule/response/body_rule.rb +3 -3
  61. data/lib/contrast/agent/assess/rule/response/cache_control_header_rule.rb +66 -43
  62. data/lib/contrast/agent/assess/rule/response/click_jacking_header_rule.rb +4 -4
  63. data/lib/contrast/agent/assess/rule/response/csp_header_insecure_rule.rb +6 -6
  64. data/lib/contrast/agent/assess/rule/response/csp_header_missing_rule.rb +4 -4
  65. data/lib/contrast/agent/assess/rule/response/hsts_header_rule.rb +4 -4
  66. data/lib/contrast/agent/assess/rule/response/parameters_pollution_rule.rb +1 -1
  67. data/lib/contrast/agent/assess/rule/response/x_content_type_header_rule.rb +4 -4
  68. data/lib/contrast/agent/assess/rule/response/x_xss_protection_header_rule.rb +3 -4
  69. data/lib/contrast/agent/assess/tag.rb +13 -14
  70. data/lib/contrast/agent/at_exit_hook.rb +12 -1
  71. data/lib/contrast/agent/deadzone/policy/deadzone_node.rb +0 -7
  72. data/lib/contrast/agent/deadzone/policy/policy.rb +0 -6
  73. data/lib/contrast/agent/exclusion_matcher.rb +3 -3
  74. data/lib/contrast/agent/inventory/database_config.rb +10 -3
  75. data/lib/contrast/agent/middleware.rb +10 -5
  76. data/lib/contrast/agent/patching/policy/after_load_patch.rb +3 -5
  77. data/lib/contrast/agent/patching/policy/after_load_patcher.rb +2 -2
  78. data/lib/contrast/agent/patching/policy/method_policy_extend.rb +4 -4
  79. data/lib/contrast/agent/patching/policy/patch.rb +20 -19
  80. data/lib/contrast/agent/patching/policy/patch_status.rb +10 -3
  81. data/lib/contrast/agent/patching/policy/patcher.rb +4 -4
  82. data/lib/contrast/agent/patching/policy/policy.rb +13 -15
  83. data/lib/contrast/agent/patching/policy/policy_node.rb +32 -21
  84. data/lib/contrast/agent/patching/policy/trigger_node.rb +1 -1
  85. data/lib/contrast/agent/protect/exploitable_collection.rb +38 -0
  86. data/lib/contrast/agent/protect/input_analyzer/input_analyzer.rb +132 -75
  87. data/lib/contrast/agent/protect/policy/applies_no_sqli_rule.rb +4 -3
  88. data/lib/contrast/agent/protect/policy/applies_path_traversal_rule.rb +3 -3
  89. data/lib/contrast/agent/protect/policy/applies_xxe_rule.rb +1 -1
  90. data/lib/contrast/agent/protect/policy/rule_applicator.rb +4 -4
  91. data/lib/contrast/agent/protect/rule/base.rb +53 -9
  92. data/lib/contrast/agent/protect/rule/base_service.rb +31 -12
  93. data/lib/contrast/agent/protect/rule/cmd_injection.rb +23 -3
  94. data/lib/contrast/agent/protect/rule/cmdi/cmdi_input_classification.rb +83 -0
  95. data/lib/contrast/agent/protect/rule/cmdi/cmdi_worth_watching.rb +64 -0
  96. data/lib/contrast/agent/protect/rule/default_scanner.rb +2 -1
  97. data/lib/contrast/agent/protect/rule/deserialization.rb +18 -7
  98. data/lib/contrast/agent/protect/rule/http_method_tampering/http_method_tampering_input_classification.rb +96 -0
  99. data/lib/contrast/agent/protect/rule/http_method_tampering.rb +72 -46
  100. data/lib/contrast/agent/protect/rule/no_sqli/no_sqli_input_classification.rb +231 -0
  101. data/lib/contrast/agent/protect/rule/no_sqli.rb +28 -2
  102. data/lib/contrast/agent/protect/rule/path_traversal.rb +13 -3
  103. data/lib/contrast/agent/protect/rule/sqli/sqli_input_classification.rb +18 -54
  104. data/lib/contrast/agent/protect/rule/sqli/sqli_worth_watching.rb +2 -5
  105. data/lib/contrast/agent/protect/rule/sqli.rb +16 -23
  106. data/lib/contrast/agent/protect/rule/unsafe_file_upload/unsafe_file_upload_input_classification.rb +82 -0
  107. data/lib/contrast/agent/protect/rule/unsafe_file_upload/unsafe_file_upload_matcher.rb +45 -0
  108. data/lib/contrast/agent/protect/rule/unsafe_file_upload.rb +42 -0
  109. data/lib/contrast/agent/protect/rule/xss.rb +17 -0
  110. data/lib/contrast/agent/protect/rule/xxe/entity_wrapper.rb +14 -13
  111. data/lib/contrast/agent/protect/rule/xxe.rb +25 -3
  112. data/lib/contrast/agent/reaction_processor.rb +1 -1
  113. data/lib/contrast/agent/reporting/attack_result/attack_result.rb +63 -0
  114. data/lib/contrast/agent/reporting/attack_result/rasp_rule_sample.rb +52 -0
  115. data/lib/contrast/agent/reporting/attack_result/response_type.rb +29 -0
  116. data/lib/contrast/agent/reporting/attack_result/user_input.rb +87 -0
  117. data/lib/contrast/agent/reporting/masker/masker.rb +243 -0
  118. data/lib/contrast/agent/reporting/masker/masker_utils.rb +62 -0
  119. data/lib/contrast/agent/reporting/report.rb +2 -0
  120. data/lib/contrast/agent/reporting/reporter.rb +29 -22
  121. data/lib/contrast/agent/reporting/reporter_heartbeat.rb +49 -0
  122. data/lib/contrast/agent/reporting/reporting_events/agent_startup.rb +34 -0
  123. data/lib/contrast/agent/reporting/reporting_events/application_activity.rb +51 -0
  124. data/lib/contrast/agent/reporting/reporting_events/application_defend_activity.rb +96 -0
  125. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_activity.rb +70 -0
  126. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample.rb +182 -0
  127. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample_activity.rb +56 -0
  128. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample_stack.rb +22 -0
  129. data/lib/contrast/agent/reporting/reporting_events/application_defend_attacker_activity.rb +70 -0
  130. data/lib/contrast/agent/reporting/reporting_events/application_inventory.rb +13 -5
  131. data/lib/contrast/agent/reporting/reporting_events/application_inventory_activity.rb +60 -0
  132. data/lib/contrast/agent/reporting/reporting_events/application_reporting_event.rb +27 -0
  133. data/lib/contrast/agent/reporting/reporting_events/application_startup.rb +44 -0
  134. data/lib/contrast/agent/reporting/reporting_events/application_startup_instrumentation.rb +27 -0
  135. data/lib/contrast/agent/reporting/reporting_events/application_update.rb +7 -12
  136. data/lib/contrast/agent/reporting/reporting_events/discovered_route.rb +1 -1
  137. data/lib/contrast/agent/reporting/reporting_events/finding.rb +10 -4
  138. data/lib/contrast/agent/reporting/reporting_events/finding_event.rb +2 -4
  139. data/lib/contrast/agent/reporting/reporting_events/finding_event_object.rb +3 -3
  140. data/lib/contrast/agent/reporting/reporting_events/library_usage_observation.rb +5 -5
  141. data/lib/contrast/agent/reporting/reporting_events/observed_library_usage.rb +6 -2
  142. data/lib/contrast/agent/reporting/reporting_events/observed_route.rb +16 -12
  143. data/lib/contrast/agent/reporting/reporting_events/poll.rb +6 -2
  144. data/lib/contrast/agent/reporting/reporting_events/preflight.rb +10 -8
  145. data/lib/contrast/agent/reporting/reporting_events/preflight_message.rb +8 -11
  146. data/lib/contrast/agent/reporting/reporting_events/reporting_event.rb +2 -1
  147. data/lib/contrast/agent/reporting/reporting_events/route_coverage.rb +8 -6
  148. data/lib/contrast/agent/reporting/reporting_events/server_activity.rb +12 -20
  149. data/lib/contrast/agent/reporting/reporting_events/server_reporting_event.rb +27 -0
  150. data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +17 -27
  151. data/lib/contrast/agent/reporting/reporting_utilities/build_preflight.rb +38 -0
  152. data/lib/contrast/agent/reporting/reporting_utilities/dtm_message.rb +8 -0
  153. data/lib/contrast/agent/reporting/reporting_utilities/endpoints.rb +6 -0
  154. data/lib/contrast/agent/reporting/reporting_utilities/headers.rb +1 -2
  155. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +29 -13
  156. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +64 -76
  157. data/lib/contrast/agent/reporting/reporting_utilities/reporting_storage.rb +1 -1
  158. data/lib/contrast/agent/reporting/reporting_utilities/response.rb +17 -7
  159. data/lib/contrast/agent/reporting/reporting_utilities/response_extractor.rb +100 -0
  160. data/lib/contrast/agent/reporting/reporting_utilities/response_handler.rb +75 -13
  161. data/lib/contrast/agent/reporting/reporting_utilities/response_handler_mode.rb +63 -0
  162. data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +163 -122
  163. data/lib/contrast/agent/reporting/settings/application_settings.rb +10 -1
  164. data/lib/contrast/agent/reporting/settings/assess.rb +5 -5
  165. data/lib/contrast/agent/reporting/settings/assess_server_feature.rb +7 -35
  166. data/lib/contrast/agent/reporting/settings/exclusions.rb +3 -3
  167. data/lib/contrast/agent/reporting/settings/protect.rb +21 -6
  168. data/lib/contrast/agent/reporting/settings/protect_server_feature.rb +6 -6
  169. data/lib/contrast/agent/reporting/settings/reaction.rb +3 -3
  170. data/lib/contrast/agent/reporting/settings/sampling.rb +36 -0
  171. data/lib/contrast/agent/reporting/settings/sensitive_data_masking.rb +110 -0
  172. data/lib/contrast/agent/reporting/settings/sensitive_data_masking_rule.rb +58 -0
  173. data/lib/contrast/agent/reporting/settings/server_features.rb +2 -2
  174. data/lib/contrast/agent/request.rb +5 -5
  175. data/lib/contrast/agent/request_context.rb +25 -21
  176. data/lib/contrast/agent/request_context_extend.rb +12 -25
  177. data/lib/contrast/agent/request_handler.rb +7 -3
  178. data/lib/contrast/agent/response.rb +2 -0
  179. data/lib/contrast/agent/rule_set.rb +2 -2
  180. data/lib/contrast/agent/scope.rb +1 -1
  181. data/lib/contrast/agent/service_heartbeat.rb +6 -48
  182. data/lib/contrast/agent/static_analysis.rb +1 -1
  183. data/lib/contrast/agent/telemetry/base.rb +155 -0
  184. data/lib/contrast/agent/telemetry/events/event.rb +35 -0
  185. data/lib/contrast/agent/telemetry/events/exceptions/obfuscate.rb +119 -0
  186. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_base.rb +59 -0
  187. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_event.rb +44 -0
  188. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_message.rb +115 -0
  189. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_message_exception.rb +83 -0
  190. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_stack_frame.rb +64 -0
  191. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exceptions.rb +20 -0
  192. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exceptions_report.rb +30 -0
  193. data/lib/contrast/agent/telemetry/events/metric_event.rb +28 -0
  194. data/lib/contrast/agent/telemetry/events/startup_metrics_event.rb +123 -0
  195. data/lib/contrast/agent/thread_watcher.rb +52 -68
  196. data/lib/contrast/agent/version.rb +1 -1
  197. data/lib/contrast/agent/worker_thread.rb +8 -0
  198. data/lib/contrast/agent.rb +4 -3
  199. data/lib/contrast/api/communication/messaging_queue.rb +29 -12
  200. data/lib/contrast/api/communication/response_processor.rb +7 -10
  201. data/lib/contrast/api/communication/service_lifecycle.rb +1 -1
  202. data/lib/contrast/api/communication/socket.rb +1 -1
  203. data/lib/contrast/api/communication/socket_client.rb +1 -1
  204. data/lib/contrast/api/communication/speedracer.rb +3 -3
  205. data/lib/contrast/api/decorators/activity.rb +33 -0
  206. data/lib/contrast/api/decorators/address.rb +1 -1
  207. data/lib/contrast/api/decorators/agent_startup.rb +10 -9
  208. data/lib/contrast/api/decorators/application_settings.rb +1 -1
  209. data/lib/contrast/api/decorators/application_startup.rb +4 -4
  210. data/lib/contrast/api/decorators/http_request.rb +1 -1
  211. data/lib/contrast/api/decorators/response_type.rb +17 -0
  212. data/lib/contrast/api/decorators.rb +1 -0
  213. data/lib/contrast/components/agent.rb +1 -1
  214. data/lib/contrast/components/app_context.rb +0 -4
  215. data/lib/contrast/components/assess.rb +14 -0
  216. data/lib/contrast/components/base.rb +1 -1
  217. data/lib/contrast/components/config.rb +19 -28
  218. data/lib/contrast/components/contrast_service.rb +13 -1
  219. data/lib/contrast/components/protect.rb +2 -2
  220. data/lib/contrast/components/sampling.rb +8 -12
  221. data/lib/contrast/components/settings.rb +151 -19
  222. data/lib/contrast/config/agent_configuration.rb +34 -41
  223. data/lib/contrast/config/api_configuration.rb +16 -75
  224. data/lib/contrast/config/api_proxy_configuration.rb +9 -48
  225. data/lib/contrast/config/application_configuration.rb +24 -95
  226. data/lib/contrast/config/assess_configuration.rb +21 -76
  227. data/lib/contrast/config/assess_rules_configuration.rb +13 -38
  228. data/lib/contrast/config/base_configuration.rb +11 -76
  229. data/lib/contrast/config/certification_configuration.rb +15 -68
  230. data/lib/contrast/config/exception_configuration.rb +15 -59
  231. data/lib/contrast/config/heap_dump_configuration.rb +19 -73
  232. data/lib/contrast/config/inventory_configuration.rb +11 -55
  233. data/lib/contrast/config/logger_configuration.rb +8 -41
  234. data/lib/contrast/config/protect_configuration.rb +23 -10
  235. data/lib/contrast/config/protect_rule_configuration.rb +23 -37
  236. data/lib/contrast/config/protect_rules_configuration.rb +39 -43
  237. data/lib/contrast/config/request_audit_configuration.rb +16 -55
  238. data/lib/contrast/config/root_configuration.rb +71 -14
  239. data/lib/contrast/config/ruby_configuration.rb +14 -47
  240. data/lib/contrast/config/sampling_configuration.rb +12 -65
  241. data/lib/contrast/config/server_configuration.rb +13 -45
  242. data/lib/contrast/config/service_configuration.rb +18 -54
  243. data/lib/contrast/configuration.rb +25 -17
  244. data/lib/contrast/extension/assess/array.rb +1 -1
  245. data/lib/contrast/extension/assess/erb.rb +1 -1
  246. data/lib/contrast/extension/assess/marshal.rb +1 -1
  247. data/lib/contrast/extension/assess/string.rb +20 -1
  248. data/lib/contrast/extension/extension.rb +2 -2
  249. data/lib/contrast/extension/module.rb +0 -1
  250. data/lib/contrast/framework/base_support.rb +8 -8
  251. data/lib/contrast/framework/grape/support.rb +3 -3
  252. data/lib/contrast/framework/manager.rb +7 -7
  253. data/lib/contrast/framework/manager_extend.rb +1 -1
  254. data/lib/contrast/framework/rack/patch/session_cookie.rb +1 -1
  255. data/lib/contrast/framework/rails/patch/action_controller_live_buffer.rb +14 -3
  256. data/lib/contrast/framework/rails/patch/assess_configuration.rb +3 -3
  257. data/lib/contrast/framework/rails/patch/rails_application_configuration.rb +1 -1
  258. data/lib/contrast/framework/rails/patch/support.rb +14 -46
  259. data/lib/contrast/framework/rails/support.rb +2 -2
  260. data/lib/contrast/framework/sinatra/support.rb +1 -1
  261. data/lib/contrast/logger/aliased_logging.rb +94 -0
  262. data/lib/contrast/logger/application.rb +1 -5
  263. data/lib/contrast/logger/cef_log.rb +15 -15
  264. data/lib/contrast/logger/format.rb +1 -1
  265. data/lib/contrast/logger/log.rb +8 -8
  266. data/lib/contrast/tasks/config.rb +100 -4
  267. data/lib/contrast/tasks/service.rb +2 -2
  268. data/lib/contrast/utils/assess/object_store.rb +36 -0
  269. data/lib/contrast/utils/assess/propagation_method_utils.rb +6 -0
  270. data/lib/contrast/utils/assess/tracking_util.rb +4 -4
  271. data/lib/contrast/utils/class_util.rb +9 -22
  272. data/lib/contrast/utils/findings.rb +3 -3
  273. data/lib/contrast/utils/hash_digest.rb +6 -7
  274. data/lib/contrast/utils/head_dump_utils_extend.rb +1 -1
  275. data/lib/contrast/utils/input_classification.rb +73 -0
  276. data/lib/contrast/utils/invalid_configuration_util.rb +2 -2
  277. data/lib/contrast/utils/log_utils.rb +7 -5
  278. data/lib/contrast/utils/lru_cache.rb +1 -1
  279. data/lib/contrast/utils/metrics_hash.rb +1 -1
  280. data/lib/contrast/utils/middleware_utils.rb +15 -14
  281. data/lib/contrast/utils/net_http_base.rb +5 -5
  282. data/lib/contrast/utils/object_share.rb +2 -1
  283. data/lib/contrast/utils/os.rb +1 -6
  284. data/lib/contrast/utils/patching/policy/patch_utils.rb +6 -7
  285. data/lib/contrast/utils/request_utils.rb +2 -2
  286. data/lib/contrast/utils/response_utils.rb +18 -33
  287. data/lib/contrast/utils/sha256_builder.rb +4 -4
  288. data/lib/contrast/utils/stack_trace_utils.rb +31 -13
  289. data/lib/contrast/utils/telemetry.rb +22 -7
  290. data/lib/contrast/utils/telemetry_client.rb +28 -16
  291. data/lib/contrast/utils/telemetry_hash.rb +41 -0
  292. data/lib/contrast/utils/telemetry_identifier.rb +18 -3
  293. data/lib/contrast/utils/timer.rb +1 -1
  294. data/lib/contrast.rb +9 -0
  295. data/resources/assess/policy.json +99 -1
  296. data/resources/deadzone/policy.json +0 -86
  297. data/ruby-agent.gemspec +10 -9
  298. data/service_executables/VERSION +1 -1
  299. data/service_executables/linux/contrast-service +0 -0
  300. data/service_executables/mac/contrast-service +0 -0
  301. metadata +99 -29
  302. data/lib/contrast/agent/metric_telemetry_event.rb +0 -26
  303. data/lib/contrast/agent/startup_metrics_telemetry_event.rb +0 -121
  304. data/lib/contrast/agent/telemetry.rb +0 -137
  305. data/lib/contrast/agent/telemetry_event.rb +0 -33
  306. data/lib/contrast/utils/exclude_key.rb +0 -20
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bfca6df4def9f2366f7a92651aa9cd2fc40f3ced6784228844d8025cee5a4850
4
- data.tar.gz: b66b10e1d892adee985f070963e08945fd9dd4faf641f4f06a8372683129facd
3
+ metadata.gz: e548b3df856f888229a5125c351404c3f5b04fcd7ecb5c91937f480ce91c9d42
4
+ data.tar.gz: 00c6ee55996e75602d1b80da133a362d3205cb5ef5de0f5c1a35b214528fea2a
5
5
  SHA512:
6
- metadata.gz: '08a6989482a82249d3fb906b2f79788e03d5c5ffa03973beabe591292fa780cd2bd3a6f459e8b7eedf58181a729720da0e95b1afa069e8869511b6ff4338625d'
7
- data.tar.gz: b460cad0b10b3355bfafa3be8c49ba41d0174e5a5d0524bbab273cf51c3d9fed6348027b9658dd3dadddcace9012f0ce119566f46899ee71f8712aebf56a98bf
6
+ metadata.gz: ad8d0f64dc798a22072e977cf0ff83ba47df54a3f24802386a52d2d338f365a02cac5db943868a55ecdf7641e44384f580e55e5d1b05a78522e88c5244013346
7
+ data.tar.gz: 804a464d38a9e023da53ce82009573571a6197c9f3f00642988457ac32b8ecc8631ea0a3cfd8bc678918df8afbb1cb24c51fa79dff1fe8fb278c5e966bff74e1
data/.simplecov CHANGED
@@ -1,7 +1,7 @@
1
1
  # Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
- SimpleCov.minimum_coverage line: 95
4
+ SimpleCov.minimum_coverage(line: 94)
5
5
  SimpleCov.start do
6
6
  add_filter '/spec/'
7
7
  enable_coverage :branch
data/Rakefile CHANGED
@@ -13,7 +13,7 @@ CLOBBER << 'shared_libraries/*'
13
13
 
14
14
  Dir['ext/cs__*'].each do |extension|
15
15
  name = extension.split('/')[1]
16
- Rake::ExtensionTask.new name do |ext|
16
+ Rake::ExtensionTask.new(name) do |ext|
17
17
  ext.lib_dir = "lib/#{ name }"
18
18
  end
19
19
  end
@@ -52,13 +52,13 @@ unless find_header('funchook.h', ext_path)
52
52
 
53
53
  TARGET_PATHS.each do |target_path|
54
54
  unless File.writable?(target_path)
55
- puts "Unable to copy into #{ target_path } - directory not writable"
55
+ puts("Unable to copy into #{ target_path } - directory not writable")
56
56
  next
57
57
  end
58
- puts "Copying #{ source_file_path } into #{ target_path }"
58
+ puts("Copying #{ source_file_path } into #{ target_path }")
59
59
  FileUtils.cp(source_file_path, target_path)
60
60
  rescue StandardError
61
- puts "Error while copying #{ source_file } to #{ target_path }"
61
+ puts("Error while copying #{ source_file } to #{ target_path }")
62
62
  end
63
63
  end
64
64
  end
@@ -22,7 +22,9 @@ static VALUE contrast_assess_array_join(const int argc, const VALUE *argv,
22
22
  }
23
23
  /* Finally, default to empty String. Implicit since nil.to_s is ''*/
24
24
 
25
+ /* call the Array.join but patched one */
25
26
  result = rb_funcall2(ary, rb_sym_assess_array_join, argc, argv);
27
+ /* call the Contrast::Extensions::Assess::ArrayPropagator#cs__track_join */
26
28
  result = rb_funcall(array_propagator, rb_sym_assess_track_array_join, 3,
27
29
  ary, sep, result);
28
30
 
@@ -33,6 +35,11 @@ void Init_cs__assess_array(void) {
33
35
  array_propagator =
34
36
  rb_define_class_under(core_assess, "ArrayPropagator", rb_cObject);
35
37
  rb_sym_assess_track_array_join = rb_intern("cs__track_join");
38
+ /*
39
+ * Here we need to check before using the alias or prepend spec
40
+ * This patch is happening here, we register the cs__track_join
41
+ * method of the Array propagator, and call it here from Ruby.
42
+ */
36
43
  rb_sym_assess_array_join =
37
44
  contrast_register_patch("Array", "join", contrast_assess_array_join);
38
45
  }
@@ -3,8 +3,24 @@
3
3
 
4
4
  #include "cs__assess_basic_object.h"
5
5
  #include "../cs__common/cs__common.h"
6
+ #include "../cs__scope/cs__scope.h"
6
7
  #include <ruby.h>
7
8
 
9
+ /*
10
+ * Source code of instance_eval:
11
+ *
12
+ * static VALUE
13
+ * rb_obj_instance_eval_internal(int argc, const VALUE *argv, VALUE self)
14
+ * {
15
+ * VALUE klass = singleton_class_for_eval(self);
16
+ * return specific_eval(argc, argv, klass, self, RB_PASS_CALLED_KEYWORDS);
17
+ * }
18
+ */
19
+
20
+ VALUE contrast_check_and_register_instance_patch(
21
+ const char *module_name, const char *method_name,
22
+ VALUE(c_fn)(const int, VALUE *, const VALUE));
23
+
8
24
  void contrast_assess_instance_eval_trigger_check(VALUE self, VALUE source,
9
25
  VALUE ret) {
10
26
  rb_funcall(basic_eval_trigger, instance_trigger_check_method, 3, self,
@@ -19,19 +35,21 @@ contrast_assess_basic_object_instance_eval(const int argc, const VALUE *argv,
19
35
  return rb_obj_instance_eval(argc, argv, self);
20
36
  }
21
37
 
22
- int nested_scope =
23
- RTEST(rb_funcall(contrast_patcher(), rb_sym_in_scope, 0));
38
+ VALUE nested_scope = inst_methods_in_cntr_scope(contrast_patcher(), 0);
24
39
 
25
- rb_funcall(contrast_patcher(), rb_sym_enter_scope, 0);
40
+ /* Enter scope */
41
+ inst_methods_enter_cntr_scope(contrast_patcher(), 0);
26
42
 
43
+ /* Call the source: */
27
44
  VALUE ret = rb_obj_instance_eval(argc, argv, self);
28
45
 
29
- if (!nested_scope && argc > 0) {
46
+ if (nested_scope == Qfalse && argc > 0) {
30
47
  VALUE data = argv[0];
31
48
  contrast_assess_instance_eval_trigger_check(self, data, ret);
32
49
  }
33
50
 
34
- rb_funcall(contrast_patcher(), rb_sym_exit_scope, 0);
51
+ /* Exit scope */
52
+ inst_methods_exit_cntr_scope(contrast_patcher(), 0);
35
53
 
36
54
  return ret;
37
55
  }
@@ -47,6 +65,6 @@ void Init_cs__assess_basic_object(void) {
47
65
  * but if someone else patched BasicObject#instance_eval,
48
66
  * IDK if this is intentional... noting it. -ajm
49
67
  */
50
- contrast_register_patch("BasicObject", "instance_eval",
68
+ contrast_check_and_register_instance_patch("BasicObject", "instance_eval",
51
69
  contrast_assess_basic_object_instance_eval);
52
70
  }
@@ -30,7 +30,7 @@ VALUE rb_fiber_new_hook(VALUE (*func)(ANYARGS), VALUE obj) {
30
30
  ID meth;
31
31
  };
32
32
 
33
- /* underlying object is first entry in Enumerator struct def.
33
+ /* underlying object is first entry in Enumerator struct def.
34
34
  * that's all statically defined w/in enumerator.c, so we can't
35
35
  * reference the data types and be safe about it. (yippee.)
36
36
  * we cut out the TypedData_Get_Struct middleman & just go for it.
@@ -17,7 +17,6 @@ static VALUE contrast_assess_hash_bracket_constructor(const int argc,
17
17
  const VALUE hash) {
18
18
  VALUE result;
19
19
 
20
-
21
20
  /* Array of Arrays: Hash[ [ [key, value], ... ] ] -> new_hash */
22
21
  if (RB_TYPE_P(argv[0], T_ARRAY)) {
23
22
  int i;
@@ -34,13 +33,13 @@ static VALUE contrast_assess_hash_bracket_constructor(const int argc,
34
33
  }
35
34
  }
36
35
 
37
- const VALUE * argv_final = argv;
36
+ const VALUE *argv_final = argv;
38
37
  /* unhandled case - shouldn't need it since issue is only unfrozen
39
38
  * String keys
40
39
  * # Hash[ object ] -> new_hash
41
40
  */
42
- result =
43
- rb_funcall2(hash, rb_sym_assess_hash_bracket_constructor, argc, argv_final);
41
+ result = rb_funcall2(hash, rb_sym_assess_hash_bracket_constructor, argc,
42
+ argv_final);
44
43
 
45
44
  return result;
46
45
  }
@@ -9,8 +9,7 @@
9
9
  VALUE
10
10
  contrast_patched_kernel_exec(const int argc, const VALUE *argv,
11
11
  const VALUE self) {
12
- int nested_scope =
13
- inst_methods_in_cntr_scope(contrast_patcher(), 0);
12
+ VALUE nested_scope = inst_methods_in_cntr_scope(contrast_patcher(), 0);
14
13
 
15
14
  if (nested_scope == Qfalse && argc > 0) {
16
15
  /* enter scope */
@@ -5,36 +5,50 @@
5
5
  #include "../cs__common/cs__common.h"
6
6
  #include <ruby.h>
7
7
 
8
- static VALUE contrast_marshal_module_load(const int argc,
9
- const VALUE *argv) {
8
+ /*
9
+ * Marshal#load source:
10
+ * static VALUE
11
+ * marshal_load(int argc, VALUE *argv)
12
+ * {
13
+ * VALUE port, proc;
14
+ *
15
+ * rb_check_arity(argc, 1, 2);
16
+ * port = argv[0];
17
+ * proc = argc > 1 ? argv[1] : Qnil;
18
+ * return rb_marshal_load_with_proc(port, proc);
19
+ * }
20
+ */
21
+ static VALUE contrast_marshal_module_load(const int argc, const VALUE *argv) {
10
22
  VALUE result;
11
23
  VALUE source_string;
12
24
 
13
- // Our patches only need only apply in the case where there was valid input.
25
+ /* Our patches need to apply only in the case where there was valid input.
26
+ */
14
27
  if (argc >= 1) {
15
28
  source_string = argv[0];
16
29
  } else {
17
30
  source_string = Qnil;
18
31
  }
19
32
 
20
- // Run our protect code ahead of the original method
33
+ /* Run our protect code ahead of the original method */
21
34
  if (source_string != Qnil) {
22
- rb_funcall(marshal_propagator, rb_sym_protect_marshal_load, 1, source_string);
35
+ rb_funcall(marshal_propagator, rb_sym_protect_marshal_load, 1,
36
+ source_string);
23
37
  }
24
38
 
25
- // Invoke the original method
39
+ /* Invoke the original method */
26
40
  result = rb_call_super(argc, argv);
27
41
 
28
- // Run our assess code after the original method
42
+ /* Run our assess code after the original method */
29
43
  if (source_string != Qnil) {
30
44
  VALUE tracked =
31
45
  rb_funcall(properties_hash, rb_sym_hash_tracked, 1, source_string);
32
46
 
33
- // Assuming the source is tracked and needs assess checks
47
+ /* Assuming the source is tracked and needs assess checks */
34
48
  if (tracked == Qtrue) {
35
49
  VALUE skip =
36
50
  rb_funcall(contrast_patcher(), rb_sym_skip_assess_analysis, 0);
37
- // And Assess is enabled and applies to this request
51
+ /* And Assess is enabled and applies to this request */
38
52
  if (skip == Qfalse) {
39
53
  rb_funcall(marshal_propagator, rb_sym_assess_marshal_load, 2,
40
54
  source_string, result);
@@ -45,7 +59,7 @@ static VALUE contrast_marshal_module_load(const int argc,
45
59
  }
46
60
 
47
61
  void Init_cs__assess_marshal_module(void) {
48
- // Contrast::Agent::Assess::Tracker::PROPERTIES_HASH
62
+ /* Contrast::Agent::Assess::Tracker::PROPERTIES_HASH */
49
63
  VALUE tracker = rb_define_class_under(assess, "Tracker", rb_cObject);
50
64
  properties_hash = rb_const_get(tracker, rb_intern("PROPERTIES_HASH"));
51
65
  marshal_propagator =
@@ -53,6 +67,6 @@ void Init_cs__assess_marshal_module(void) {
53
67
  rb_sym_assess_marshal_load = rb_intern("cs__load_assess");
54
68
  rb_sym_protect_marshal_load = rb_intern("cs__load_protect");
55
69
 
56
- contrast_register_singleton_prepend_patch(
57
- "Marshal", "load", &contrast_marshal_module_load);
70
+ contrast_register_singleton_prepend_patch("Marshal", "load",
71
+ &contrast_marshal_module_load);
58
72
  }
@@ -13,7 +13,7 @@ void contrast_assess_eval_trigger_check(VALUE module, VALUE source, VALUE ret) {
13
13
  }
14
14
 
15
15
  int nested_scope = inst_methods_in_cntr_scope(contrast_patcher(), 0);
16
- /* enter scope */
16
+ /* enter scope */
17
17
  inst_methods_enter_cntr_scope(contrast_patcher(), 0);
18
18
 
19
19
  if (nested_scope == Qfalse) {
@@ -3,8 +3,20 @@
3
3
 
4
4
  #include "cs__assess_regexp.h"
5
5
  #include "../cs__common/cs__common.h"
6
+ #include "../cs__contrast_patch/cs__contrast_patch.h"
6
7
  #include <ruby.h>
7
8
 
9
+ extern VALUE contrast_force_patch(const int argc, VALUE *argv) {
10
+ return contrast_check_and_register_instance_patch(
11
+ "Regexp", "=~", contrast_assess_regexp_equal_squiggle);
12
+ }
13
+
14
+ /* check if method is prepended and register instance alias or prepend patch */
15
+ VALUE contrast_check_and_register_instance_patch(const char *module_name,
16
+ const char *method_name,
17
+ VALUE(c_fn)(const int, VALUE *,
18
+ const VALUE));
19
+
8
20
  void contrast_alias_method(const VALUE target, const char *to,
9
21
  const char *from);
10
22
 
@@ -46,7 +58,8 @@ void Init_cs__assess_regexp(void) {
46
58
  rb_global_variable(&rb_sym_string);
47
59
  rb_sym_back_ref = ID2SYM(rb_intern("back_ref"));
48
60
  rb_global_variable(&rb_sym_back_ref);
61
+ rb_define_singleton_method(assess, "contrast_force_repatch_regexp", contrast_force_patch, 0);
49
62
 
50
- rb_sym_assess_regexp_equal_squiggle = contrast_register_patch(
51
- "Regexp", "=~", contrast_assess_regexp_equal_squiggle);
63
+ rb_sym_assess_regexp_equal_squiggle = contrast_check_and_register_instance_patch(
64
+ "Regexp", "=~", contrast_assess_regexp_equal_squiggle);
52
65
  }
@@ -20,4 +20,6 @@ static VALUE contrast_assess_regexp_equal_squiggle(const int argc,
20
20
  const VALUE *argv,
21
21
  const VALUE regexp);
22
22
 
23
+ extern VALUE contrast_force_patch(const int argc, VALUE *argv);
24
+
23
25
  void Init_cs__assess_regexp(void);
@@ -5,6 +5,25 @@
5
5
  #include "../cs__common/cs__common.h"
6
6
  #include <ruby.h>
7
7
 
8
+ /*
9
+ * The -@ method source:
10
+ *
11
+ * static VALUE
12
+ * str_uminus(VALUE str)
13
+ * {
14
+ * if (!BARE_STRING_P(str) && !rb_obj_frozen_p(str)) {
15
+ * str = rb_str_dup(str);
16
+ * }
17
+ * return rb_fstring(str);
18
+ * }
19
+ */
20
+
21
+ /*
22
+ * This patch won't do the Prepend. We would call to the String instance'
23
+ * uminus directly and skip other propagation from prepended modules.
24
+ * We could come back to this one and rethink it's prepend patching.
25
+ */
26
+
8
27
  static VALUE contrast_assess_string_freeze(const int argc, VALUE *argv,
9
28
  const VALUE obj) {
10
29
  if (!OBJ_FROZEN(obj)) {
@@ -39,10 +58,11 @@ void Init_cs__assess_string(void) {
39
58
  rb_sym_dup = rb_intern("dup");
40
59
  rb_sym_freeze = rb_intern("freeze");
41
60
  rb_sym_pre_freeze = rb_intern("pre_freeze");
42
- // Contrast::Agent::Assess::Tracker::PROPERTIES_HASH
61
+ /* Contrast::Agent::Assess::Tracker::PROPERTIES_HASH */
43
62
  VALUE tracker = rb_define_class_under(assess, "Tracker", rb_cObject);
44
63
  properties_hash = rb_const_get(tracker, rb_intern("PROPERTIES_HASH"));
45
64
 
65
+ /* We only do alias for this one */
46
66
  rb_sym_assess_string_uminus =
47
67
  contrast_register_patch("String", "-@", &contrast_assess_string_uminus);
48
68
  rb_sym_assess_string_freeze = contrast_register_patch(
@@ -0,0 +1,9 @@
1
+ #include <ruby.h>
2
+
3
+ static VALUE dummy_regexp;
4
+ static VALUE test_regexp;
5
+
6
+ VALUE rb_equal_squiggle(const int argc, const VALUE *argv)
7
+ void rb_force_prepend(void);
8
+
9
+ void Init_cs__assess_test(void)
@@ -0,0 +1,22 @@
1
+ #include "../cs__common/cs__common.h";
2
+ #include "ruby.h"
3
+ #include <ruby/re.h>
4
+
5
+ static VALUE dummy_regexp;
6
+ static VALUE test_regexp;
7
+
8
+ VALUE rb_equal_squiggle(const int argc, const VALUE *argv) {
9
+ return rb_call_super(argc, argv);
10
+ }
11
+
12
+ void rb_force_prepend(void) {
13
+ rb_prepend_module(rb_cRegexp, dummy_regexp);
14
+ }
15
+
16
+ void Init_cs__assess_test(void) {
17
+ test_regexp = rb_define_module("ForcePrepend");
18
+ rb_define_singleton_method(test_regexp, "cs__force_prepend",
19
+ rb_force_prepend, 0);
20
+ dummy_regexp = rb_define_module("DummyMod");
21
+ rb_define_method(dummy_regexp, "=~", rb_equal_squiggle, -1);
22
+ }
@@ -0,0 +1,5 @@
1
+ # Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ $TO_MAKE = File.basename(__dir__)
5
+ require_relative '../extconf_common'
@@ -59,13 +59,14 @@ VALUE contrast_patcher() {
59
59
  return patcher;
60
60
  }
61
61
 
62
+ /* register instance alias patch */
62
63
  VALUE contrast_register_patch(const char *module_name, const char *method_name,
63
- VALUE(c_fn)(const int, VALUE *,
64
- const VALUE)) {
64
+ VALUE(c_fn)(const int, VALUE *, const VALUE)) {
65
65
  return _contrast_register_patch(module_name, method_name, c_fn,
66
66
  IMPL_ALIAS_INSTANCE);
67
67
  }
68
68
 
69
+ /* register singleton alias patch */
69
70
  VALUE contrast_register_singleton_patch(const char *module_name,
70
71
  const char *method_name,
71
72
  VALUE(c_fn)(const int, VALUE *,
@@ -74,22 +75,49 @@ VALUE contrast_register_singleton_patch(const char *module_name,
74
75
  IMPL_ALIAS_SINGLETON);
75
76
  }
76
77
 
78
+ /* register instance prepend patch */
77
79
  VALUE contrast_register_prepend_patch(const char *module_name,
78
- const char *method_name,
79
- VALUE(c_fn)(const int, VALUE *,
80
- const VALUE)) {
80
+ const char *method_name,
81
+ VALUE(c_fn)(const int, VALUE *,
82
+ const VALUE)) {
81
83
  return _contrast_register_patch(module_name, method_name, c_fn,
82
84
  IMPL_PREPEND_INSTANCE);
83
85
  }
84
86
 
87
+ /* register singleton prepend patch */
85
88
  VALUE contrast_register_singleton_prepend_patch(const char *module_name,
86
- const char *method_name,
87
- VALUE(c_fn)(const int, VALUE *,
88
- const VALUE)) {
89
+ const char *method_name,
90
+ VALUE(c_fn)(const int, VALUE *,
91
+ const VALUE)) {
89
92
  return _contrast_register_patch(module_name, method_name, c_fn,
90
93
  IMPL_PREPEND_SINGLETON);
91
94
  }
92
95
 
96
+ /* check if method is prepended and register instance alias or prepend patch */
97
+ /* module name c_char "Module"; */
98
+ /* method name c_char "method"; */
99
+ /* c_func => pointer */
100
+ VALUE contrast_check_and_register_instance_patch(
101
+ const char *module_name, const char *method_name,
102
+ VALUE(c_fn)(const int, VALUE *, const VALUE)) {
103
+
104
+ VALUE object, method, is_prepended, patch_type;
105
+ /* check if method is prepended */
106
+ object = rb_const_get(rb_cObject, rb_intern(module_name));
107
+ method = ID2SYM(rb_intern(method_name));
108
+ is_prepended = contrast_check_prepended(object, method, Qtrue);
109
+
110
+ if (is_prepended == Qtrue) {
111
+ /* prepend patch */
112
+ return _contrast_register_patch(module_name, method_name, c_fn,
113
+ IMPL_PREPEND_INSTANCE);
114
+ } else {
115
+ /* alias patch */
116
+ return _contrast_register_patch(module_name, method_name, c_fn,
117
+ IMPL_ALIAS_INSTANCE);
118
+ }
119
+ }
120
+
93
121
  static VALUE
94
122
  _contrast_register_patch(const char *module_name, const char *method_name,
95
123
  VALUE(c_fn)(const int, VALUE *, const VALUE),
@@ -134,8 +162,9 @@ _contrast_register_patch(const char *module_name, const char *method_name,
134
162
  break;
135
163
  case IMPL_PREPEND_INSTANCE:
136
164
  impl = ID2SYM(rb_sym_prepend_instance);
165
+ break;
137
166
  case IMPL_PREPEND_SINGLETON:
138
- impl = ID2SYM(rb_sym_prepend_singleton);
167
+ impl = ID2SYM(rb_sym_prepend_singleton);
139
168
  break;
140
169
  }
141
170
 
@@ -146,8 +175,75 @@ _contrast_register_patch(const char *module_name, const char *method_name,
146
175
  }
147
176
 
148
177
  int rb_ver_below_three() {
149
- int ruby_version = FIX2INT(rb_funcall(rb_const_get(rb_cObject, rb_intern("RUBY_VERSION")), rb_intern("to_i"), 0));
150
- return ruby_version < 3;
178
+ int ruby_version =
179
+ FIX2INT(rb_funcall(rb_const_get(rb_cObject, rb_intern("RUBY_VERSION")),
180
+ rb_intern("to_i"), 0));
181
+ return ruby_version < 3;
182
+ }
183
+
184
+ /* used for direct check on object: String.cs__prepended? *args */
185
+ extern VALUE contrast_check_prepended(VALUE self, VALUE method_name,
186
+ VALUE is_instance) {
187
+ return _contrast_check_prepended(self, method_name, is_instance);
188
+ }
189
+
190
+ /* used for passing object to look if not called on itself.
191
+ Contrast::Agent::Assess.cs__object_method_prepended? object, :method_name,
192
+ true/false */
193
+ extern VALUE contrast_lookout_prepended(VALUE self, VALUE object_name,
194
+ VALUE method_name, VALUE is_instance) {
195
+ /* object_name must be the object, the self value is needed to prevent
196
+ lookout for self, since is always passed first we skip it */
197
+ VALUE result =
198
+ _contrast_check_prepended(object_name, method_name, is_instance);
199
+ return result;
200
+ }
201
+
202
+ static VALUE _contrast_check_prepended(VALUE object, VALUE method_name,
203
+ VALUE is_instance) {
204
+ VALUE entry, ancestors, object_idx, entry_methods;
205
+ VALUE result = Qfalse;
206
+ int i;
207
+ int y;
208
+
209
+ /* get self ancestors */
210
+ ancestors = rb_mod_ancestors(object);
211
+ /* get the size of the array */
212
+ int length = RARRAY_LEN(ancestors);
213
+ /* Locate self in ancestors: */
214
+ for (i = 0; i < length; ++i) {
215
+ entry = rb_ary_entry(ancestors, i);
216
+ if (entry == object) {
217
+ object_idx = i;
218
+ break;
219
+ }
220
+ }
221
+
222
+ /* find all the prepended modules */
223
+ /* we have the object place in ancestors: */
224
+ /* [suspect, suspect, object, ...] */
225
+ for (i = 0; i < object_idx; ++i) {
226
+ entry = rb_ary_entry(ancestors, i);
227
+ if (is_instance == Qtrue) {
228
+ entry_methods = rb_class_instance_methods(1, entry, entry);
229
+ } else {
230
+ entry_methods = rb_obj_singleton_methods(1, entry, entry);
231
+ }
232
+
233
+ /* Loop through the instance/singleton methods of the prepended modules
234
+ */
235
+ int entry_methods_length = RARRAY_LEN(entry_methods);
236
+ for (y = 0; y <= entry_methods_length; ++y) {
237
+ if (rb_ary_entry(entry_methods, y) == method_name) {
238
+ result = Qtrue;
239
+ break;
240
+ }
241
+ }
242
+ if (result == Qtrue) {
243
+ break;
244
+ }
245
+ }
246
+ return result;
151
247
  }
152
248
 
153
249
  void Init_cs__common(void) {
@@ -190,4 +286,10 @@ void Init_cs__common(void) {
190
286
 
191
287
  core_extensions = rb_define_module_under(contrast, "Extension");
192
288
  core_assess = rb_define_module_under(core_extensions, "Assess");
289
+ /* defined for direct object check */
290
+ rb_define_singleton_method(rb_cObject, "cs__prepended?",
291
+ contrast_check_prepended, 2);
292
+ /* defined for object lookout */
293
+ rb_define_singleton_method(assess, "cs__object_method_prepended?",
294
+ contrast_lookout_prepended, 4);
193
295
  }
@@ -57,15 +57,39 @@ VALUE contrast_register_singleton_patch(const char *module_name,
57
57
  VALUE(c_fn)(const int, VALUE *,
58
58
  const VALUE));
59
59
 
60
- VALUE contrast_register_singleton_prepend_patch(
61
- const char *module_name, const char *method_name,
62
- VALUE(c_fn)(const int, VALUE *, const VALUE));
60
+ VALUE contrast_register_prepend_patch(const char *module_name,
61
+ const char *method_name,
62
+ VALUE(c_fn)(const int, VALUE *,
63
+ const VALUE));
63
64
 
64
- static VALUE
65
- _contrast_register_patch(const char *module_name, const char *method_name,
65
+
66
+ VALUE contrast_register_singleton_prepend_patch(const char *module_name,
67
+ const char *method_name,
68
+ VALUE(c_fn)(const int, VALUE *,
69
+ const VALUE));
70
+
71
+ VALUE contrast_register_prepend_patch(const char *module_name,
72
+ const char *method_name,
73
+ VALUE(c_fn)(const int, VALUE *,
74
+ const VALUE));
75
+
76
+ static VALUE _contrast_register_patch(const char *module_name, const char *method_name,
66
77
  VALUE(c_fn)(const int, VALUE *, const VALUE),
67
78
  patch_impl patch_impl);
68
79
 
80
+ static VALUE _contrast_check_prepended(VALUE self, VALUE method_name, VALUE is_instance);
81
+
82
+ extern VALUE contrast_check_prepended(VALUE self, VALUE method_name, VALUE is_instance);
83
+
84
+ extern VALUE contrast_lookout_prepended(VALUE self, VALUE object_name, VALUE method_name,
85
+ VALUE is_instance);
86
+
87
+ /* check if method is prepended and register instance alias or prepend patch */
88
+ VALUE contrast_check_and_register_instance_patch(const char *module_name,
89
+ const char *method_name,
90
+ VALUE(c_fn)(const int, VALUE *,
91
+ const VALUE));
92
+
69
93
  VALUE contrast_patcher();
70
94
 
71
95
  void Init_cs__common(void);