datadog_lambda 8.113.0__py3-none-any.whl → 8.114.0__py3-none-any.whl

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.
@@ -3,10 +3,11 @@ import os
3
3
 
4
4
 
5
5
  if os.environ.get("DD_INSTRUMENTATION_TELEMETRY_ENABLED") is None:
6
- os.environ["DD_INSTRUMENTATION_TELEMETRY_ENABLED"] = "false"
6
+ # Telemetry is required for Appsec Software Composition Analysis
7
+ os.environ["DD_INSTRUMENTATION_TELEMETRY_ENABLED"] = os.environ.get(
8
+ "DD_APPSEC_ENABLED", "false"
9
+ )
7
10
 
8
- if os.environ.get("DD_API_SECURITY_ENABLED") is None:
9
- os.environ["DD_API_SECURITY_ENABLED"] = "False"
10
11
 
11
12
  initialize_cold_start_tracing()
12
13
 
datadog_lambda/asm.py CHANGED
@@ -73,17 +73,16 @@ def asm_start_request(
73
73
  route: Optional[str] = None
74
74
 
75
75
  if event_source.event_type == EventTypes.ALB:
76
- headers = event.get("headers")
77
- multi_value_request_headers = event.get("multiValueHeaders")
78
- if multi_value_request_headers:
79
- request_headers = _to_single_value_headers(multi_value_request_headers)
80
- else:
81
- request_headers = headers or {}
82
-
83
76
  raw_uri = event.get("path")
84
- parsed_query = event.get("multiValueQueryStringParameters") or event.get(
85
- "queryStringParameters"
86
- )
77
+
78
+ if event_source.subtype == EventSubtypes.ALB:
79
+ request_headers = event.get("headers", {})
80
+ parsed_query = event.get("queryStringParameters")
81
+ if event_source.subtype == EventSubtypes.ALB_MULTI_VALUE_HEADERS:
82
+ request_headers = _to_single_value_headers(
83
+ event.get("multiValueHeaders", {})
84
+ )
85
+ parsed_query = event.get("multiValueQueryStringParameters")
87
86
 
88
87
  elif event_source.event_type == EventTypes.LAMBDA_FUNCTION_URL:
89
88
  request_headers = event.get("headers", {})
@@ -226,15 +225,27 @@ def get_asm_blocked_response(
226
225
  content_type = blocked.get("content-type", "application/json")
227
226
  content = http_utils._get_blocked_template(content_type)
228
227
 
229
- response_headers = {
230
- "content-type": content_type,
231
- }
232
- if "location" in blocked:
233
- response_headers["location"] = blocked["location"]
234
-
235
- return {
228
+ response = {
236
229
  "statusCode": blocked.get("status_code", 403),
237
- "headers": response_headers,
238
230
  "body": content,
239
231
  "isBase64Encoded": False,
240
232
  }
233
+
234
+ needs_multi_value_headers = event_source.equals(
235
+ EventTypes.ALB, EventSubtypes.ALB_MULTI_VALUE_HEADERS
236
+ )
237
+
238
+ if needs_multi_value_headers:
239
+ response["multiValueHeaders"] = {
240
+ "content-type": [content_type],
241
+ }
242
+ if "location" in blocked:
243
+ response["multiValueHeaders"]["location"] = [blocked["location"]]
244
+ else:
245
+ response["headers"] = {
246
+ "content-type": content_type,
247
+ }
248
+ if "location" in blocked:
249
+ response["headers"]["location"] = blocked["location"]
250
+
251
+ return response
datadog_lambda/trigger.py CHANGED
@@ -54,6 +54,10 @@ class EventSubtypes(_stringTypedEnum):
54
54
  WEBSOCKET = "websocket"
55
55
  HTTP_API = "http-api"
56
56
 
57
+ ALB = "alb" # regular alb
58
+ # ALB with the multi-value headers option checked on the target group
59
+ ALB_MULTI_VALUE_HEADERS = "alb-multi-value-headers"
60
+
57
61
 
58
62
  class _EventSource:
59
63
  """
@@ -133,7 +137,12 @@ def parse_event_source(event: dict) -> _EventSource:
133
137
  event_source.subtype = EventSubtypes.WEBSOCKET
134
138
 
135
139
  if request_context and request_context.get("elb"):
136
- event_source = _EventSource(EventTypes.ALB)
140
+ if "multiValueHeaders" in event:
141
+ event_source = _EventSource(
142
+ EventTypes.ALB, EventSubtypes.ALB_MULTI_VALUE_HEADERS
143
+ )
144
+ else:
145
+ event_source = _EventSource(EventTypes.ALB, EventSubtypes.ALB)
137
146
 
138
147
  if event.get("awslogs"):
139
148
  event_source = _EventSource(EventTypes.CLOUDWATCH_LOGS)
@@ -288,7 +297,7 @@ def extract_http_tags(event):
288
297
  """
289
298
  Extracts HTTP facet tags from the triggering event
290
299
  """
291
- http_tags = {}
300
+ http_tags = {"span.kind": "server"}
292
301
 
293
302
  # Safely get request_context and ensure it's a dictionary
294
303
  request_context = event.get("requestContext")
datadog_lambda/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "8.113.0"
1
+ __version__ = "8.114.0"
datadog_lambda/wrapper.py CHANGED
@@ -53,6 +53,9 @@ if config.appsec_enabled:
53
53
  asm_start_request,
54
54
  get_asm_blocked_response,
55
55
  )
56
+ from ddtrace.internal.appsec.product import start
57
+
58
+ start()
56
59
 
57
60
  if config.profiling_enabled:
58
61
  from ddtrace.profiling import profiler
@@ -281,6 +284,34 @@ class _LambdaDecorator(object):
281
284
  def _after(self, event, context):
282
285
  try:
283
286
  status_code = extract_http_status_code_tag(self.trigger_tags, self.response)
287
+
288
+ if self.span:
289
+ if config.appsec_enabled and not self.blocking_response:
290
+ asm_start_response(
291
+ self.span,
292
+ status_code,
293
+ self.event_source,
294
+ response=self.response,
295
+ )
296
+ self.blocking_response = get_asm_blocked_response(self.event_source)
297
+
298
+ if self.blocking_response:
299
+ status_code = str(self.blocking_response.get("statusCode"))
300
+ if config.capture_payload_enabled and self.response:
301
+ tag_object(
302
+ self.span, "function.blocked_response", self.response
303
+ )
304
+ self.response = self.blocking_response
305
+
306
+ if config.capture_payload_enabled:
307
+ tag_object(self.span, "function.request", event)
308
+ tag_object(self.span, "function.response", self.response)
309
+
310
+ if status_code:
311
+ self.span.set_tag("http.status_code", status_code)
312
+
313
+ self.span.finish()
314
+
284
315
  if status_code:
285
316
  self.trigger_tags["http.status_code"] = status_code
286
317
  mark_trace_as_error_for_5xx_responses(context, status_code, self.span)
@@ -295,25 +326,6 @@ class _LambdaDecorator(object):
295
326
  if should_trace_cold_start:
296
327
  trace_ctx = tracer.current_trace_context()
297
328
 
298
- if self.span:
299
- if config.capture_payload_enabled:
300
- tag_object(self.span, "function.request", event)
301
- tag_object(self.span, "function.response", self.response)
302
-
303
- if status_code:
304
- self.span.set_tag("http.status_code", status_code)
305
-
306
- if config.appsec_enabled and not self.blocking_response:
307
- asm_start_response(
308
- self.span,
309
- status_code,
310
- self.event_source,
311
- response=self.response,
312
- )
313
- self.blocking_response = get_asm_blocked_response(self.event_source)
314
-
315
- self.span.finish()
316
-
317
329
  if self.inferred_span:
318
330
  if status_code:
319
331
  self.inferred_span.set_tag("http.status_code", status_code)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: datadog_lambda
3
- Version: 8.113.0
3
+ Version: 8.114.0
4
4
  Summary: The Datadog AWS Lambda Library
5
5
  Home-page: https://github.com/DataDog/datadog-lambda-python
6
6
  License: Apache-2.0
@@ -1,6 +1,6 @@
1
- datadog_lambda/__init__.py,sha256=uAqki08Fd26eUXZtoptJX68kTFhK-ZkCyLVCtE0MS4k,802
1
+ datadog_lambda/__init__.py,sha256=rAQyhhjO-TzPu3_EtL111hr03gdeeQRmm1Zsz2dKKTw,816
2
2
  datadog_lambda/api.py,sha256=FqQ9vjNSxD5BxjeHDDKbim_NIN08dshW-52wNzqw5yo,5249
3
- datadog_lambda/asm.py,sha256=pYgtSKtOj8KTd701iPiXvOXQ32D1nH_k1BzOmMU7L1k,7767
3
+ datadog_lambda/asm.py,sha256=RyGUIvQMR8OSsfJ-B9hum5pMTYZa_OC157bk3Lwny-U,8175
4
4
  datadog_lambda/cold_start.py,sha256=NfE4EtRUHuc2ub26U8sAwMVEDNINbw1OTh2MAklQGyk,8032
5
5
  datadog_lambda/config.py,sha256=QoEZrSL_zSHY5lV9RznAwPONEZe0i3mCWp2jPoO8aEw,5260
6
6
  datadog_lambda/constants.py,sha256=0y6O9s_8RLflYR507SDMQjKmYY16tr1yi2KQuuF1GaY,1696
@@ -18,13 +18,13 @@ datadog_lambda/tag_object.py,sha256=NNvMVi07kNYRBMPpB7Lk7_-z5ccmxo2UmTWnvWVPhiM,
18
18
  datadog_lambda/tags.py,sha256=wy6uH8eAGMn7cfZEdHpL9uEGoM85bVyyXhYwSQtfHHc,2532
19
19
  datadog_lambda/thread_stats_writer.py,sha256=VfD6G65zNHDA0nABhGOO0it7yqvn-p6ereQ329DA7r8,2894
20
20
  datadog_lambda/tracing.py,sha256=A7uUXlWBwfxOa2PFVLg2Tgft8Ft14xz-kSOjvOaA8JQ,57396
21
- datadog_lambda/trigger.py,sha256=7EhNoCtJbnuYaqCvv1i2tAqZxfXx7ccsnMkwnWvmd7w,14212
22
- datadog_lambda/version.py,sha256=VIVUGpBGnx4PNj35gsO1Xf4OfZ_Naws0GXp54dMVxj0,24
23
- datadog_lambda/wrapper.py,sha256=ZCszRfSAbBplOcPJ_RI5XTMSkNBfvgEJYbYEdhlhbwQ,14270
21
+ datadog_lambda/trigger.py,sha256=LfdyPvU8Qq2D9-3QMmq_5XBJ-E64B7NDBnXZ_eQIqKo,14598
22
+ datadog_lambda/version.py,sha256=MBl-08iJNVy_nyamBQviE0yhqUjioZtisRer_BnpeJ4,24
23
+ datadog_lambda/wrapper.py,sha256=yfzneYh0LtW7ytkuXIZOrcULGQIrPdH9g7sextuOH4g,14738
24
24
  datadog_lambda/xray.py,sha256=jvA4Fk76PLMgsjUoUZ7gp2otv53hFt39Nvso1ZNaivg,3749
25
- datadog_lambda-8.113.0.dist-info/LICENSE,sha256=4yQmjpKp1MKL7DdRDPVHkKYc2W0aezm5SIDske8oAdM,11379
26
- datadog_lambda-8.113.0.dist-info/LICENSE-3rdparty.csv,sha256=9CDAR1GKawwTbZkqt1RP0uwEcaRM3RhOeTB5tWXr8Ts,1381
27
- datadog_lambda-8.113.0.dist-info/METADATA,sha256=eOT372rwVMUz4fdAIrkcEfT3Bx1Kuro2vWGymFpQY38,7727
28
- datadog_lambda-8.113.0.dist-info/NOTICE,sha256=Jue-d8mQ1ENIHDZdYc2-X8mVYtScXb8pzF1pTLN-kRc,141
29
- datadog_lambda-8.113.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
30
- datadog_lambda-8.113.0.dist-info/RECORD,,
25
+ datadog_lambda-8.114.0.dist-info/LICENSE,sha256=4yQmjpKp1MKL7DdRDPVHkKYc2W0aezm5SIDske8oAdM,11379
26
+ datadog_lambda-8.114.0.dist-info/LICENSE-3rdparty.csv,sha256=9CDAR1GKawwTbZkqt1RP0uwEcaRM3RhOeTB5tWXr8Ts,1381
27
+ datadog_lambda-8.114.0.dist-info/METADATA,sha256=dKOTfbF5ue0qu8OwTtnH4WHjB5fjIab0aXsA2cYLqAI,7727
28
+ datadog_lambda-8.114.0.dist-info/NOTICE,sha256=Jue-d8mQ1ENIHDZdYc2-X8mVYtScXb8pzF1pTLN-kRc,141
29
+ datadog_lambda-8.114.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
30
+ datadog_lambda-8.114.0.dist-info/RECORD,,