|
| 1 | +# frozen_string_literal: true |
| 2 | + |
| 3 | +require_relative 'stack_trace/representor' |
| 4 | +require_relative 'stack_trace/collector' |
| 5 | + |
| 6 | +require_relative '../../tracing/metadata/metastruct' |
| 7 | + |
| 8 | +module Datadog |
| 9 | + module AppSec |
| 10 | + module ActionsHandler |
| 11 | + # Adds stack traces to meta_struct |
| 12 | + module StackTrace |
| 13 | + module_function |
| 14 | + |
| 15 | + def skip_stack_trace?(context, group:) |
| 16 | + if context.trace.nil? && context.span.nil? |
| 17 | + Datadog.logger.debug { 'Cannot find trace or service entry span to add stack trace' } |
| 18 | + return true |
| 19 | + end |
| 20 | + |
| 21 | + max_collect = Datadog.configuration.appsec.stack_trace.max_collect |
| 22 | + return false if max_collect == 0 |
| 23 | + |
| 24 | + stack_traces_count = 0 |
| 25 | + |
| 26 | + unless context.trace.nil? |
| 27 | + trace_dd_stack = context.trace.metastruct[AppSec::Ext::TAG_STACK_TRACE] |
| 28 | + stack_traces_count += trace_dd_stack[group].size unless trace_dd_stack.nil? || trace_dd_stack[group].nil? |
| 29 | + end |
| 30 | + |
| 31 | + unless context.span.nil? |
| 32 | + span_dd_stack = context.span.metastruct[AppSec::Ext::TAG_STACK_TRACE] |
| 33 | + stack_traces_count += span_dd_stack[group].size unless span_dd_stack.nil? || span_dd_stack[group].nil? |
| 34 | + end |
| 35 | + |
| 36 | + stack_traces_count >= max_collect |
| 37 | + end |
| 38 | + |
| 39 | + def collect_stack_frames |
| 40 | + # caller_locations without params always returns an array but steep still thinks it can be nil |
| 41 | + # So we add || [] but it will never run the second part anyway (either this or steep:ignore) |
| 42 | + stack_frames = caller_locations || [] |
| 43 | + # Steep thinks that path can still be nil and that include? is not a method of nil |
| 44 | + # We must add a variable assignment to avoid this |
| 45 | + stack_frames.reject! do |loc| |
| 46 | + path = loc.path |
| 47 | + next true if path.nil? |
| 48 | + |
| 49 | + path.include?('lib/datadog') |
| 50 | + end |
| 51 | + |
| 52 | + StackTrace::Collector.collect(stack_frames) |
| 53 | + end |
| 54 | + |
| 55 | + def add_stack_trace_to_context(stack_trace, context, group:) |
| 56 | + # We use methods defined in Tracing::Metadata::Tagging, |
| 57 | + # which means we can use both the trace and the service entry span |
| 58 | + service_entry_op = (context.trace || context.span) |
| 59 | + |
| 60 | + dd_stack = service_entry_op.metastruct[AppSec::Ext::TAG_STACK_TRACE] |
| 61 | + if dd_stack.nil? |
| 62 | + service_entry_op.metastruct[AppSec::Ext::TAG_STACK_TRACE] = {} |
| 63 | + dd_stack = service_entry_op.metastruct[AppSec::Ext::TAG_STACK_TRACE] |
| 64 | + end |
| 65 | + |
| 66 | + dd_stack[AppSec::Ext::EXPLOIT_PREVENTION_EVENT_CATEGORY] ||= [] |
| 67 | + stack_group = dd_stack[AppSec::Ext::EXPLOIT_PREVENTION_EVENT_CATEGORY] |
| 68 | + |
| 69 | + stack_group << stack_trace |
| 70 | + rescue StandardError => e |
| 71 | + Datadog.logger.debug("Unable to add stack_trace #{stack_trace.id} in metastruct, ignoring it. Caused by: #{e}") |
| 72 | + end |
| 73 | + end |
| 74 | + end |
| 75 | + end |
| 76 | +end |
0 commit comments