From ef23781287470e6bee0633628ad443b636f636e9 Mon Sep 17 00:00:00 2001 From: Gunjan-Katre-Comprinno Date: Mon, 9 Jun 2025 14:06:18 +0000 Subject: [PATCH 1/2] Added test case for check inspector_lambda_standard_scan_enabled --- ..._inspector_lambda_standard_scan_enabled.py | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 library/aws/tests/inspector/test_inspector_lambda_standard_scan_enabled.py diff --git a/library/aws/tests/inspector/test_inspector_lambda_standard_scan_enabled.py b/library/aws/tests/inspector/test_inspector_lambda_standard_scan_enabled.py new file mode 100644 index 00000000..78db2868 --- /dev/null +++ b/library/aws/tests/inspector/test_inspector_lambda_standard_scan_enabled.py @@ -0,0 +1,94 @@ +import pytest +from unittest.mock import MagicMock +from tevico.engine.entities.report.check_model import CheckStatus, CheckMetadata, Remediation, RemediationCode, RemediationRecommendation +from library.aws.checks.inspector.inspector_lambda_standard_scan_enabled import inspector_lambda_standard_scan_enabled + + +class TestInspectorLambdaStandardScanEnabled: + def setup_method(self): + metadata = CheckMetadata( + Provider="aws", + CheckID="inspector_lambda_standard_scan_enabled", + CheckTitle="Ensure Inspector Lambda standard scan is enabled", + CheckType=["security"], + ServiceName="inspector2", + SubServiceName="lambda", + ResourceIdTemplate="", + Severity="high", + ResourceType="account", + Risk="If Inspector Lambda scans are not enabled, you might miss vulnerabilities in Lambda functions.", + RelatedUrl="https://docs.aws.amazon.com/inspector/latest/user/lambda-scan.html", + Remediation=Remediation( + Code=RemediationCode( + CLI="aws inspector2 enable --resource-types LAMBDA", + Terraform=None, + NativeIaC=None, + Other=None, + ), + Recommendation=RemediationRecommendation( + Text="Enable Inspector2 Lambda scanning.", + Url="https://docs.aws.amazon.com/inspector/latest/user/lambda-scan.html" + ) + ), + Description="Checks whether Inspector Lambda standard scan is enabled.", + Categories=["security", "compliance"] + ) + + self.check = inspector_lambda_standard_scan_enabled(metadata) + self.mock_session = MagicMock() + self.mock_inspector_client = MagicMock() + self.mock_sts_client = MagicMock() + + self.mock_session.client.side_effect = lambda service: { + "inspector2": self.mock_inspector_client, + "sts": self.mock_sts_client + }[service] + + self.mock_sts_client.get_caller_identity.return_value = {"Account": "123456789012"} + + def set_inspector_response(self, status): + self.mock_inspector_client.batch_get_account_status.return_value = { + "accounts": [{ + "resourceState": { + "lambda": { + "status": status + } + } + }] + } + + def test_lambda_scan_enabled(self): + self.set_inspector_response("ENABLED") + report = self.check.execute(self.mock_session) + + assert report.status == CheckStatus.PASSED + assert any(r.summary is not None and "enabled" in r.summary.lower() for r in report.resource_ids_status) + + def test_lambda_scan_disabled(self): + self.set_inspector_response("DISABLED") + report = self.check.execute(self.mock_session) + + assert report.status == CheckStatus.FAILED + assert any(r.summary is not None and "not enabled" in r.summary.lower() for r in report.resource_ids_status) + + def test_lambda_scan_suspended(self): + self.set_inspector_response("SUSPENDED") + report = self.check.execute(self.mock_session) + + assert report.status == CheckStatus.FAILED + assert any(r.summary is not None and "suspended" in r.summary.lower() for r in report.resource_ids_status) + + def test_lambda_scan_unknown_status(self): + self.set_inspector_response("TRANSITIONING") + report = self.check.execute(self.mock_session) + + assert report.status == CheckStatus.UNKNOWN + assert any(r.summary is not None and "transitional" in r.summary.lower() for r in report.resource_ids_status) + + def test_api_failure(self): + self.mock_inspector_client.batch_get_account_status.side_effect = Exception("API error") + + report = self.check.execute(self.mock_session) + + assert report.status == CheckStatus.UNKNOWN + assert any(r.summary is not None and "error checking" in r.summary.lower() for r in report.resource_ids_status) From 67f0f89f625e34511fc6b0973618708a2896b4f8 Mon Sep 17 00:00:00 2001 From: Gunjan-Katre-Comprinno Date: Tue, 8 Jul 2025 19:40:20 +0000 Subject: [PATCH 2/2] Addressed the comments on PR Test case for check inspector_lambda_standard_scan_enabled --- ..._inspector_lambda_standard_scan_enabled.py | 45 ++++++++++++++++--- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/library/aws/tests/inspector/test_inspector_lambda_standard_scan_enabled.py b/library/aws/tests/inspector/test_inspector_lambda_standard_scan_enabled.py index 78db2868..f6c68e1a 100644 --- a/library/aws/tests/inspector/test_inspector_lambda_standard_scan_enabled.py +++ b/library/aws/tests/inspector/test_inspector_lambda_standard_scan_enabled.py @@ -1,11 +1,15 @@ import pytest from unittest.mock import MagicMock -from tevico.engine.entities.report.check_model import CheckStatus, CheckMetadata, Remediation, RemediationCode, RemediationRecommendation +from botocore.exceptions import ClientError +from tevico.engine.entities.report.check_model import ( + CheckStatus, CheckMetadata, Remediation, RemediationCode, RemediationRecommendation +) from library.aws.checks.inspector.inspector_lambda_standard_scan_enabled import inspector_lambda_standard_scan_enabled class TestInspectorLambdaStandardScanEnabled: def setup_method(self): + """Initialize metadata, check, and mock AWS clients for each test.""" metadata = CheckMetadata( Provider="aws", CheckID="inspector_lambda_standard_scan_enabled", @@ -47,6 +51,7 @@ def setup_method(self): self.mock_sts_client.get_caller_identity.return_value = {"Account": "123456789012"} def set_inspector_response(self, status): + """Helper to set the inspector2 batch_get_account_status response.""" self.mock_inspector_client.batch_get_account_status.return_value = { "accounts": [{ "resourceState": { @@ -58,37 +63,65 @@ def set_inspector_response(self, status): } def test_lambda_scan_enabled(self): + """Inspector Lambda scan is enabled.""" self.set_inspector_response("ENABLED") report = self.check.execute(self.mock_session) assert report.status == CheckStatus.PASSED - assert any(r.summary is not None and "enabled" in r.summary.lower() for r in report.resource_ids_status) + assert any(r.summary and "enabled" in r.summary.lower() for r in report.resource_ids_status) def test_lambda_scan_disabled(self): + """Inspector Lambda scan is disabled.""" self.set_inspector_response("DISABLED") report = self.check.execute(self.mock_session) assert report.status == CheckStatus.FAILED - assert any(r.summary is not None and "not enabled" in r.summary.lower() for r in report.resource_ids_status) + assert any(r.summary and "not enabled" in r.summary.lower() for r in report.resource_ids_status) def test_lambda_scan_suspended(self): + """Inspector Lambda scan is suspended.""" self.set_inspector_response("SUSPENDED") report = self.check.execute(self.mock_session) assert report.status == CheckStatus.FAILED - assert any(r.summary is not None and "suspended" in r.summary.lower() for r in report.resource_ids_status) + assert any(r.summary and "suspended" in r.summary.lower() for r in report.resource_ids_status) def test_lambda_scan_unknown_status(self): + """Inspector Lambda scan is in transitional state (e.g., TRANSITIONING).""" self.set_inspector_response("TRANSITIONING") report = self.check.execute(self.mock_session) assert report.status == CheckStatus.UNKNOWN - assert any(r.summary is not None and "transitional" in r.summary.lower() for r in report.resource_ids_status) + assert any(r.summary and "transitional" in r.summary.lower() for r in report.resource_ids_status) + + def test_lambda_resource_key_missing(self): + """Inspector2 returned no 'lambda' key in resourceState.""" + self.mock_inspector_client.batch_get_account_status.return_value = { + "accounts": [{"resourceState": {}}] # lambda key missing + } + + report = self.check.execute(self.mock_session) + + assert report.status == CheckStatus.UNKNOWN + assert any("transitional" in r.summary.lower() or r.status == CheckStatus.UNKNOWN for r in report.resource_ids_status) + + def test_lambda_scan_client_error(self): + """Simulate AWS ClientError (e.g., Access Denied).""" + self.mock_inspector_client.batch_get_account_status.side_effect = ClientError( + error_response={"Error": {"Code": "AccessDenied", "Message": "Access Denied"}}, + operation_name="BatchGetAccountStatus" + ) + + report = self.check.execute(self.mock_session) + + assert report.status == CheckStatus.UNKNOWN + assert any("access denied" in r.summary.lower() for r in report.resource_ids_status) def test_api_failure(self): + """Simulate generic exception while calling Inspector2 API.""" self.mock_inspector_client.batch_get_account_status.side_effect = Exception("API error") report = self.check.execute(self.mock_session) assert report.status == CheckStatus.UNKNOWN - assert any(r.summary is not None and "error checking" in r.summary.lower() for r in report.resource_ids_status) + assert any(r.summary and "error checking" in r.summary.lower() for r in report.resource_ids_status)