From 2d89c7d9cd4be2e55f959aecb962cdf2b72935e8 Mon Sep 17 00:00:00 2001 From: Diogo Pereira Date: Mon, 10 Nov 2025 17:08:35 +0000 Subject: [PATCH 1/2] Send AgentlessAPICall Lambda ARN to backend Sometimes there are delays in crawling resources after installing the integration. This makes it impossible for us to validate that the scanner deployment is working properly. By sending this Lambda ARN to the backend, we can scan it immediately. Although the DatadogAgentlessAPICall is not a very interesting resource to scan since it does not have dependencies, it is enough to validate that the scanner is working properly. --- aws_quickstart/datadog_agentless_api_call.py | 7 +++-- .../datadog_agentless_api_call_test.py | 28 ++++++++++--------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/aws_quickstart/datadog_agentless_api_call.py b/aws_quickstart/datadog_agentless_api_call.py index 5e2ef9e9..79f04c69 100644 --- a/aws_quickstart/datadog_agentless_api_call.py +++ b/aws_quickstart/datadog_agentless_api_call.py @@ -9,7 +9,7 @@ LOGGER = logging.getLogger() -def call_datadog_agentless_api(event, method): +def call_datadog_agentless_api(context, event, method): template_version = event["ResourceProperties"]["TemplateVersion"] api_key = event["ResourceProperties"]["APIKey"] app_key = event["ResourceProperties"]["APPKey"] @@ -69,6 +69,7 @@ def call_datadog_agentless_api(event, method): "orchestrator_policy_arn": orchestrator_policy_arn, "worker_policy_arn": worker_policy_arn, "worker_dspm_policy_arn": worker_dspm_policy_arn, + "invoked_function_arn": context.invoked_function_arn, }, }, "data": { @@ -116,7 +117,7 @@ def handler(event, context): try: if event["RequestType"] == "Create": LOGGER.info("Received Create request.") - response = call_datadog_agentless_api(event, "POST") + response = call_datadog_agentless_api(context, event, "POST") send_response( event, context, @@ -135,7 +136,7 @@ def handler(event, context): ) elif event["RequestType"] == "Delete": LOGGER.info("Received Delete request.") - response = call_datadog_agentless_api(event, "DELETE") + response = call_datadog_agentless_api(context, event, "DELETE") send_response( event, context, diff --git a/aws_quickstart/datadog_agentless_api_call_test.py b/aws_quickstart/datadog_agentless_api_call_test.py index 1187b898..c7a05cc2 100644 --- a/aws_quickstart/datadog_agentless_api_call_test.py +++ b/aws_quickstart/datadog_agentless_api_call_test.py @@ -2,6 +2,7 @@ import json import unittest +from types import SimpleNamespace from unittest.mock import patch, Mock from urllib.error import HTTPError @@ -17,6 +18,7 @@ class TestCallDatadogAgentlessAPI(unittest.TestCase): def setUp(self): """Set up test fixtures""" + self.context = SimpleNamespace(invoked_function_arn="arn:aws:lambda:us-east-1:012345678901:function:DatadogAgentlessAPICallFunction") self.base_event = { "ResourceProperties": { "TemplateVersion": "1.0.0", @@ -55,7 +57,7 @@ def test_post_success_200(self, mock_is_enabled, mock_urlopen): mock_response = self.create_mock_response(200) mock_urlopen.return_value = mock_response - result = call_datadog_agentless_api(self.base_event, "POST") + result = call_datadog_agentless_api(self.context, self.base_event, "POST") self.assertEqual(result.status, 200) @@ -71,7 +73,7 @@ def test_post_success_201(self, mock_is_enabled, mock_urlopen): mock_response = self.create_mock_response(201) mock_urlopen.return_value = mock_response - result = call_datadog_agentless_api(self.base_event, "POST") + result = call_datadog_agentless_api(self.context, self.base_event, "POST") self.assertEqual(result.status, 201) @@ -83,7 +85,7 @@ def test_post_success_204(self, mock_is_enabled, mock_urlopen): mock_response = self.create_mock_response(204) mock_urlopen.return_value = mock_response - result = call_datadog_agentless_api(self.base_event, "POST") + result = call_datadog_agentless_api(self.context, self.base_event, "POST") self.assertEqual(result.status, 204) @@ -96,7 +98,7 @@ def test_post_error_400(self, mock_is_enabled, mock_urlopen): mock_urlopen.side_effect = mock_error with self.assertRaises(HTTPError): - call_datadog_agentless_api(self.base_event, "POST") + call_datadog_agentless_api(self.context, self.base_event, "POST") @patch("datadog_agentless_api_call.urllib.request.urlopen") @patch("datadog_agentless_api_call.is_agentless_scanning_enabled") @@ -107,7 +109,7 @@ def test_post_error_404(self, mock_is_enabled, mock_urlopen): mock_urlopen.side_effect = mock_error with self.assertRaises(HTTPError): - call_datadog_agentless_api(self.base_event, "POST") + call_datadog_agentless_api(self.context, self.base_event, "POST") @patch("datadog_agentless_api_call.urllib.request.urlopen") @patch("datadog_agentless_api_call.is_agentless_scanning_enabled") @@ -118,7 +120,7 @@ def test_post_error_500(self, mock_is_enabled, mock_urlopen): mock_urlopen.side_effect = mock_error with self.assertRaises(HTTPError): - call_datadog_agentless_api(self.base_event, "POST") + call_datadog_agentless_api(self.context, self.base_event, "POST") @patch("datadog_agentless_api_call.urllib.request.urlopen") @patch("datadog_agentless_api_call.is_agentless_scanning_enabled") @@ -128,7 +130,7 @@ def test_post_patch_when_enabled(self, mock_is_enabled, mock_urlopen): mock_response = self.create_mock_response(200) mock_urlopen.return_value = mock_response - result = call_datadog_agentless_api(self.base_event, "POST") + result = call_datadog_agentless_api(self.context, self.base_event, "POST") self.assertEqual(result.status, 200) @@ -142,7 +144,7 @@ def test_delete_success_200(self, mock_urlopen): mock_response = self.create_mock_response(200) mock_urlopen.return_value = mock_response - result = call_datadog_agentless_api(self.base_event, "DELETE") + result = call_datadog_agentless_api(self.context, self.base_event, "DELETE") self.assertEqual(result.status, 200) @@ -152,7 +154,7 @@ def test_delete_success_204(self, mock_urlopen): mock_response = self.create_mock_response(204) mock_urlopen.return_value = mock_response - result = call_datadog_agentless_api(self.base_event, "DELETE") + result = call_datadog_agentless_api(self.context, self.base_event, "DELETE") self.assertEqual(result.status, 204) @@ -162,7 +164,7 @@ def test_delete_error_404_returns_error(self, mock_urlopen): mock_error = self.create_mock_http_error(404) mock_urlopen.side_effect = mock_error - result = call_datadog_agentless_api(self.base_event, "DELETE") + result = call_datadog_agentless_api(self.context, self.base_event, "DELETE") self.assertEqual(result.status, 404) @@ -173,11 +175,11 @@ def test_delete_error_500_raises_exception(self, mock_urlopen): mock_urlopen.side_effect = mock_error with self.assertRaises(HTTPError): - call_datadog_agentless_api(self.base_event, "DELETE") + call_datadog_agentless_api(self.context, self.base_event, "DELETE") def test_unsupported_method_returns_none(self): """Test that unsupported HTTP methods return None""" - result = call_datadog_agentless_api(self.base_event, "PUT") + result = call_datadog_agentless_api(self.context, self.base_event, "PUT") self.assertIsNone(result) @patch("datadog_agentless_api_call.urllib.request.urlopen") @@ -188,7 +190,7 @@ def test_post_request_payload_structure(self, mock_is_enabled, mock_urlopen): mock_response = self.create_mock_response(200) mock_urlopen.return_value = mock_response - call_datadog_agentless_api(self.base_event, "POST") + call_datadog_agentless_api(self.context, self.base_event, "POST") # Get the request that was made call_args = mock_urlopen.call_args[0][0] From 64a7d6eb6dc3df5c25daaa716caf851796c99938 Mon Sep 17 00:00:00 2001 From: Diogo Pereira Date: Tue, 11 Nov 2025 18:46:29 +0000 Subject: [PATCH 2/2] Bump aws_quickstart version to 4.2.1 --- aws_quickstart/version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws_quickstart/version.txt b/aws_quickstart/version.txt index 51be872e..85c71c86 100644 --- a/aws_quickstart/version.txt +++ b/aws_quickstart/version.txt @@ -1 +1 @@ -v4.2.0 +v4.2.1