mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-23 20:42:02 +00:00
feat: add categories and resource group validator
This commit is contained in:
+110
-35
@@ -1,4 +1,5 @@
|
||||
import functools
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
@@ -15,6 +16,87 @@ from prowler.lib.check.compliance_models import Compliance
|
||||
from prowler.lib.check.utils import recover_checks_from_provider
|
||||
from prowler.lib.logger import logger
|
||||
|
||||
# Valid ResourceGroup values as defined in the RFC
|
||||
VALID_RESOURCE_GROUPS = frozenset(
|
||||
{
|
||||
"compute",
|
||||
"container",
|
||||
"serverless",
|
||||
"database",
|
||||
"storage",
|
||||
"network",
|
||||
"IAM",
|
||||
"messaging",
|
||||
"security",
|
||||
"monitoring",
|
||||
"api_gateway",
|
||||
"ai_ml",
|
||||
"governance",
|
||||
"collaboration",
|
||||
"devops",
|
||||
"analytics",
|
||||
}
|
||||
)
|
||||
|
||||
# Valid Categories as defined in the RFC
|
||||
VALID_CATEGORIES = frozenset(
|
||||
{
|
||||
"encryption",
|
||||
"internet-exposed",
|
||||
"logging",
|
||||
"secrets",
|
||||
"resilience",
|
||||
"threat-detection",
|
||||
"trust-boundaries",
|
||||
"vulnerabilities",
|
||||
"cluster-security",
|
||||
"container-security",
|
||||
"node-security",
|
||||
"gen-ai",
|
||||
"ci-cd",
|
||||
"identity-access",
|
||||
"email-security",
|
||||
"forensics-ready",
|
||||
"software-supply-chain",
|
||||
"e3",
|
||||
"e5",
|
||||
"privilege-escalation",
|
||||
"ec2-imdsv1",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@functools.lru_cache(maxsize=1)
|
||||
def _load_aws_check_types_hierarchy() -> dict:
|
||||
"""
|
||||
Load and cache the AWS CheckTypes hierarchy from the JSON config file.
|
||||
|
||||
Returns:
|
||||
dict: The CheckTypes hierarchy, or empty dict if file not found.
|
||||
"""
|
||||
try:
|
||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
check_types_file = os.path.normpath(
|
||||
os.path.join(
|
||||
current_dir,
|
||||
"..",
|
||||
"..",
|
||||
"providers",
|
||||
"aws",
|
||||
"config",
|
||||
"check_types.json",
|
||||
)
|
||||
)
|
||||
|
||||
if not os.path.exists(check_types_file):
|
||||
return {}
|
||||
|
||||
with open(check_types_file, "r") as f:
|
||||
return json.load(f)
|
||||
|
||||
except (FileNotFoundError, json.JSONDecodeError):
|
||||
return {}
|
||||
|
||||
|
||||
def _validate_aws_check_type_in_config(check_type: str) -> bool:
|
||||
"""
|
||||
@@ -27,42 +109,22 @@ def _validate_aws_check_type_in_config(check_type: str) -> bool:
|
||||
Returns:
|
||||
bool: True if the CheckType path exists in the config hierarchy
|
||||
"""
|
||||
try:
|
||||
import json
|
||||
import os
|
||||
|
||||
if not check_type:
|
||||
return False
|
||||
|
||||
# Get the path to the AWS CheckTypes configuration
|
||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
check_types_file = os.path.join(
|
||||
current_dir, "..", "..", "providers", "aws", "config", "check_types.json"
|
||||
)
|
||||
check_types_file = os.path.normpath(check_types_file)
|
||||
|
||||
# Load the CheckTypes hierarchy from JSON file
|
||||
if not os.path.exists(check_types_file):
|
||||
return False
|
||||
|
||||
with open(check_types_file, "r") as f:
|
||||
hierarchy = json.load(f)
|
||||
|
||||
# Split the path by '/' to get each level
|
||||
path_parts = check_type.split("/")
|
||||
|
||||
# Navigate through the hierarchy using direct lookups
|
||||
current_level = hierarchy
|
||||
for part in path_parts:
|
||||
if not isinstance(current_level, dict) or part not in current_level:
|
||||
return False
|
||||
current_level = current_level[part]
|
||||
|
||||
return True
|
||||
|
||||
except (KeyError, AttributeError, FileNotFoundError, json.JSONDecodeError):
|
||||
if not check_type:
|
||||
return False
|
||||
|
||||
hierarchy = _load_aws_check_types_hierarchy()
|
||||
if not hierarchy:
|
||||
return False
|
||||
|
||||
path_parts = check_type.split("/")
|
||||
current_level = hierarchy
|
||||
for part in path_parts:
|
||||
if not isinstance(current_level, dict) or part not in current_level:
|
||||
return False
|
||||
current_level = current_level[part]
|
||||
|
||||
return True
|
||||
|
||||
|
||||
class Code(BaseModel):
|
||||
"""
|
||||
@@ -142,7 +204,7 @@ class CheckMetadata(BaseModel):
|
||||
Compliance (list, optional): The compliance information for the check. Defaults to None.
|
||||
|
||||
Validators:
|
||||
valid_category(value): Validator function to validate the categories of the check.
|
||||
valid_category(value): Validator function to validate the categories of the check against predefined values.
|
||||
severity_to_lower(severity): Validator function to convert the severity to lowercase.
|
||||
valid_cli_command(remediation): Validator function to validate the CLI command is not an URL.
|
||||
valid_resource_type(resource_type): Validator function to validate the resource type is not empty.
|
||||
@@ -152,6 +214,7 @@ class CheckMetadata(BaseModel):
|
||||
validate_check_type(check_type, values): Validator function to validate CheckType - no empty strings for all providers, plus predefined types validation for AWS (loaded from config file).
|
||||
validate_description(description): Validator function to validate Description max length (400 chars).
|
||||
validate_risk(risk): Validator function to validate Risk max length (400 chars).
|
||||
validate_resource_group(resource_group): Validator function to validate ResourceGroup against predefined values.
|
||||
validate_additional_urls(additional_urls): Validator function to ensure AdditionalURLs contains no duplicates.
|
||||
"""
|
||||
|
||||
@@ -188,6 +251,10 @@ class CheckMetadata(BaseModel):
|
||||
raise ValueError(
|
||||
f"Invalid category: {value}. Categories can only contain lowercase letters, numbers and hyphen '-'"
|
||||
)
|
||||
if value_lower not in VALID_CATEGORIES:
|
||||
raise ValueError(
|
||||
f"Invalid category: '{value_lower}'. Must be one of: {', '.join(sorted(VALID_CATEGORIES))}."
|
||||
)
|
||||
return value_lower
|
||||
|
||||
@validator("Severity", pre=True, always=True)
|
||||
@@ -281,6 +348,14 @@ class CheckMetadata(BaseModel):
|
||||
)
|
||||
return risk
|
||||
|
||||
@validator("ResourceGroup", pre=True, always=True)
|
||||
def validate_resource_group(cls, resource_group):
|
||||
if resource_group and resource_group not in VALID_RESOURCE_GROUPS:
|
||||
raise ValueError(
|
||||
f"Invalid ResourceGroup: '{resource_group}'. Must be one of: {', '.join(sorted(VALID_RESOURCE_GROUPS))} or empty string."
|
||||
)
|
||||
return resource_group
|
||||
|
||||
@validator("AdditionalURLs", pre=True, always=True)
|
||||
def validate_additional_urls(cls, additional_urls):
|
||||
if not isinstance(additional_urls, list):
|
||||
|
||||
@@ -5,7 +5,11 @@
|
||||
},
|
||||
"AWS Security Best Practices": {
|
||||
"Network Reachability": {},
|
||||
"Runtime Behavior Analysis": {}
|
||||
"Network Security": {},
|
||||
"Runtime Behavior Analysis": {},
|
||||
"Data Encryption": {},
|
||||
"Encryption at Rest": {},
|
||||
"Encryption in Transit": {}
|
||||
},
|
||||
"Industry and Regulatory Standards": {
|
||||
"AWS Foundational Security Best Practices": {},
|
||||
@@ -20,6 +24,7 @@
|
||||
"SOC 1": {},
|
||||
"SOC 2": {},
|
||||
"HIPAA Controls (USA)": {},
|
||||
"NIST 800-53 Controls": {},
|
||||
"NIST 800-53 Controls (USA)": {},
|
||||
"NIST CSF Controls (USA)": {},
|
||||
"IRAP Controls (Australia)": {},
|
||||
@@ -38,7 +43,11 @@
|
||||
"Patch Management": {}
|
||||
},
|
||||
"TTPs": {
|
||||
"Initial Access": {},
|
||||
"Initial Access": {
|
||||
"Unauthorized Access": {},
|
||||
"External Remote Services": {},
|
||||
"Valid Accounts": {}
|
||||
},
|
||||
"Execution": {},
|
||||
"Persistence": {},
|
||||
"Privilege Escalation": {},
|
||||
|
||||
@@ -268,12 +268,17 @@ class TestCheckLoader:
|
||||
}
|
||||
compliance_frameworks = ["soc2_aws"]
|
||||
|
||||
assert {S3_BUCKET_LEVEL_PUBLIC_ACCESS_BLOCK_NAME} == load_checks_to_execute(
|
||||
bulk_checks_metadata=bulk_checks_metadata,
|
||||
bulk_compliance_frameworks=bulk_compliance_frameworks,
|
||||
compliance_frameworks=compliance_frameworks,
|
||||
provider=self.provider,
|
||||
)
|
||||
# Mock get_bulk to prevent loading real metadata files that may fail validation
|
||||
with patch(
|
||||
"prowler.lib.check.checks_loader.CheckMetadata.get_bulk",
|
||||
return_value=bulk_checks_metadata,
|
||||
):
|
||||
assert {S3_BUCKET_LEVEL_PUBLIC_ACCESS_BLOCK_NAME} == load_checks_to_execute(
|
||||
bulk_checks_metadata=bulk_checks_metadata,
|
||||
bulk_compliance_frameworks=bulk_compliance_frameworks,
|
||||
compliance_frameworks=compliance_frameworks,
|
||||
provider=self.provider,
|
||||
)
|
||||
|
||||
def test_load_checks_to_execute_with_categories(
|
||||
self,
|
||||
|
||||
@@ -215,7 +215,7 @@ class TestCompliance:
|
||||
},
|
||||
"Recommendation": {"Text": "text1", "Url": "url1"},
|
||||
},
|
||||
Categories=["categoryone"],
|
||||
Categories=["encryption"],
|
||||
DependsOn=["dependency1"],
|
||||
RelatedTo=["related1"],
|
||||
Notes="notes1",
|
||||
@@ -243,7 +243,7 @@ class TestCompliance:
|
||||
},
|
||||
"Recommendation": {"Text": "text2", "Url": "url2"},
|
||||
},
|
||||
Categories=["categorytwo"],
|
||||
Categories=["logging"],
|
||||
DependsOn=["dependency2"],
|
||||
RelatedTo=["related2"],
|
||||
Notes="notes2",
|
||||
|
||||
@@ -87,7 +87,7 @@ test_bulk_checks_metadata = {
|
||||
Text="Ensure all vpc has public and private subnets defined", Url=""
|
||||
),
|
||||
),
|
||||
Categories=["internet-exposed", "trustboundaries"],
|
||||
Categories=["internet-exposed", "trust-boundaries"],
|
||||
DependsOn=[],
|
||||
RelatedTo=[],
|
||||
Notes="",
|
||||
|
||||
+245
-57
@@ -8,10 +8,10 @@ from prowler.lib.check.models import Check, CheckMetadata
|
||||
from tests.lib.check.compliance_check_test import custom_compliance_metadata
|
||||
|
||||
mock_metadata = CheckMetadata(
|
||||
Provider="azure", # Using non-AWS provider to avoid config validation issues
|
||||
Provider="aws",
|
||||
CheckID="accessanalyzer_enabled",
|
||||
CheckTitle="Check 1",
|
||||
CheckType=["Security"],
|
||||
CheckType=["Software and Configuration Checks/AWS Security Best Practices"],
|
||||
ServiceName="accessanalyzer",
|
||||
SubServiceName="subservice1",
|
||||
ResourceIdTemplate="template1",
|
||||
@@ -29,7 +29,7 @@ mock_metadata = CheckMetadata(
|
||||
},
|
||||
"Recommendation": {"Text": "text1", "Url": "url1"},
|
||||
},
|
||||
Categories=["categoryone"],
|
||||
Categories=["encryption"],
|
||||
DependsOn=["dependency1"],
|
||||
RelatedTo=["related1"],
|
||||
Notes="notes1",
|
||||
@@ -37,10 +37,10 @@ mock_metadata = CheckMetadata(
|
||||
)
|
||||
|
||||
mock_metadata_lambda = CheckMetadata(
|
||||
Provider="azure", # Using non-AWS provider to avoid config validation issues
|
||||
Provider="aws",
|
||||
CheckID="awslambda_function_url_public",
|
||||
CheckTitle="Check 1",
|
||||
CheckType=["Security"],
|
||||
CheckType=["Software and Configuration Checks/AWS Security Best Practices"],
|
||||
ServiceName="awslambda",
|
||||
SubServiceName="subservice1",
|
||||
ResourceIdTemplate="template1",
|
||||
@@ -58,7 +58,7 @@ mock_metadata_lambda = CheckMetadata(
|
||||
},
|
||||
"Recommendation": {"Text": "text1", "Url": "url1"},
|
||||
},
|
||||
Categories=["categoryone"],
|
||||
Categories=["encryption"],
|
||||
DependsOn=["dependency1"],
|
||||
RelatedTo=["related1"],
|
||||
Notes="notes1",
|
||||
@@ -175,7 +175,7 @@ class TestCheckMetada:
|
||||
bulk_metadata = CheckMetadata.get_bulk(provider="aws")
|
||||
|
||||
result = CheckMetadata.list(
|
||||
bulk_checks_metadata=bulk_metadata, category="categoryone"
|
||||
bulk_checks_metadata=bulk_metadata, category="encryption"
|
||||
)
|
||||
|
||||
# Assertions
|
||||
@@ -363,7 +363,7 @@ class TestCheckMetadataValidators:
|
||||
"Url": "https://example.com",
|
||||
},
|
||||
},
|
||||
"Categories": ["security", "network", "data-protection"],
|
||||
"Categories": ["encryption", "logging", "secrets"],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "Test notes",
|
||||
@@ -371,7 +371,7 @@ class TestCheckMetadataValidators:
|
||||
|
||||
# Should not raise any validation error
|
||||
check_metadata = CheckMetadata(**valid_metadata)
|
||||
assert check_metadata.Categories == ["security", "network", "data-protection"]
|
||||
assert check_metadata.Categories == ["encryption", "logging", "secrets"]
|
||||
|
||||
def test_valid_category_failure_non_string(self):
|
||||
"""Test valid category validation fails with non-string category"""
|
||||
@@ -454,6 +454,85 @@ class TestCheckMetadataValidators:
|
||||
in str(exc_info.value)
|
||||
)
|
||||
|
||||
def test_valid_category_failure_not_predefined(self):
|
||||
"""Test valid category validation fails with non-predefined category"""
|
||||
invalid_metadata = {
|
||||
"Provider": "aws",
|
||||
"CheckID": "test_check",
|
||||
"CheckTitle": "Test Check",
|
||||
"CheckType": [
|
||||
"Software and Configuration Checks/AWS Security Best Practices/Network Reachability"
|
||||
],
|
||||
"ServiceName": "test",
|
||||
"SubServiceName": "subtest",
|
||||
"ResourceIdTemplate": "template",
|
||||
"Severity": "high",
|
||||
"ResourceType": "TestResource",
|
||||
"Description": "Test description",
|
||||
"Risk": "Test risk",
|
||||
"RelatedUrl": "https://example.com",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "test command",
|
||||
"NativeIaC": "test native",
|
||||
"Other": "test other",
|
||||
"Terraform": "test terraform",
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "test recommendation",
|
||||
"Url": "https://example.com",
|
||||
},
|
||||
},
|
||||
"Categories": ["not-a-real-category"], # Invalid: not in predefined list
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "Test notes",
|
||||
}
|
||||
|
||||
with pytest.raises(ValidationError) as exc_info:
|
||||
CheckMetadata(**invalid_metadata)
|
||||
assert "Invalid category: 'not-a-real-category'. Must be one of:" in str(
|
||||
exc_info.value
|
||||
)
|
||||
|
||||
def test_valid_category_all_predefined_values(self):
|
||||
"""Test that all predefined categories are accepted"""
|
||||
from prowler.lib.check.models import VALID_CATEGORIES
|
||||
|
||||
for category in VALID_CATEGORIES:
|
||||
valid_metadata = {
|
||||
"Provider": "azure",
|
||||
"CheckID": "test_check",
|
||||
"CheckTitle": "Test Check",
|
||||
"CheckType": ["Security"],
|
||||
"ServiceName": "test",
|
||||
"SubServiceName": "subtest",
|
||||
"ResourceIdTemplate": "template",
|
||||
"Severity": "high",
|
||||
"ResourceType": "TestResource",
|
||||
"Description": "Test description",
|
||||
"Risk": "Test risk",
|
||||
"RelatedUrl": "https://example.com",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "test command",
|
||||
"NativeIaC": "test native",
|
||||
"Other": "test other",
|
||||
"Terraform": "test terraform",
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "test recommendation",
|
||||
"Url": "https://example.com",
|
||||
},
|
||||
},
|
||||
"Categories": [category],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "Test notes",
|
||||
}
|
||||
check_metadata = CheckMetadata(**valid_metadata)
|
||||
assert category in check_metadata.Categories
|
||||
|
||||
def test_severity_to_lower_success(self):
|
||||
"""Test severity validation converts to lowercase"""
|
||||
valid_metadata = {
|
||||
@@ -483,7 +562,7 @@ class TestCheckMetadataValidators:
|
||||
"Url": "https://example.com",
|
||||
},
|
||||
},
|
||||
"Categories": ["security"],
|
||||
"Categories": ["encryption"],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "Test notes",
|
||||
@@ -521,7 +600,7 @@ class TestCheckMetadataValidators:
|
||||
"Url": "https://example.com",
|
||||
},
|
||||
},
|
||||
"Categories": ["security"],
|
||||
"Categories": ["encryption"],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "Test notes",
|
||||
@@ -560,7 +639,7 @@ class TestCheckMetadataValidators:
|
||||
"Url": "https://example.com",
|
||||
},
|
||||
},
|
||||
"Categories": ["security"],
|
||||
"Categories": ["encryption"],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "Test notes",
|
||||
@@ -599,7 +678,7 @@ class TestCheckMetadataValidators:
|
||||
"Url": "https://example.com",
|
||||
},
|
||||
},
|
||||
"Categories": ["security"],
|
||||
"Categories": ["encryption"],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "Test notes",
|
||||
@@ -637,7 +716,7 @@ class TestCheckMetadataValidators:
|
||||
"Url": "https://example.com",
|
||||
},
|
||||
},
|
||||
"Categories": ["security"],
|
||||
"Categories": ["encryption"],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "Test notes",
|
||||
@@ -676,7 +755,7 @@ class TestCheckMetadataValidators:
|
||||
"Url": "https://example.com",
|
||||
},
|
||||
},
|
||||
"Categories": ["security"],
|
||||
"Categories": ["encryption"],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "Test notes",
|
||||
@@ -714,7 +793,7 @@ class TestCheckMetadataValidators:
|
||||
"Url": "https://example.com",
|
||||
},
|
||||
},
|
||||
"Categories": ["security"],
|
||||
"Categories": ["encryption"],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "Test notes",
|
||||
@@ -754,7 +833,7 @@ class TestCheckMetadataValidators:
|
||||
"Url": "https://example.com",
|
||||
},
|
||||
},
|
||||
"Categories": ["security"],
|
||||
"Categories": ["encryption"],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "Test notes",
|
||||
@@ -793,7 +872,7 @@ class TestCheckMetadataValidators:
|
||||
"Url": "https://example.com",
|
||||
},
|
||||
},
|
||||
"Categories": ["security"],
|
||||
"Categories": ["encryption"],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "Test notes",
|
||||
@@ -831,7 +910,7 @@ class TestCheckMetadataValidators:
|
||||
"Url": "https://example.com",
|
||||
},
|
||||
},
|
||||
"Categories": ["security"],
|
||||
"Categories": ["encryption"],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "Test notes",
|
||||
@@ -869,7 +948,7 @@ class TestCheckMetadataValidators:
|
||||
"Url": "https://example.com",
|
||||
},
|
||||
},
|
||||
"Categories": ["security"],
|
||||
"Categories": ["encryption"],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "Test notes",
|
||||
@@ -908,7 +987,7 @@ class TestCheckMetadataValidators:
|
||||
"Url": "https://example.com",
|
||||
},
|
||||
},
|
||||
"Categories": ["security"],
|
||||
"Categories": ["encryption"],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "Test notes",
|
||||
@@ -950,7 +1029,7 @@ class TestCheckMetadataValidators:
|
||||
"Url": "https://example.com",
|
||||
},
|
||||
},
|
||||
"Categories": ["security"],
|
||||
"Categories": ["encryption"],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "Test notes",
|
||||
@@ -988,7 +1067,7 @@ class TestCheckMetadataValidators:
|
||||
"Url": "https://example.com",
|
||||
},
|
||||
},
|
||||
"Categories": ["security"],
|
||||
"Categories": ["encryption"],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "Test notes",
|
||||
@@ -1027,7 +1106,7 @@ class TestCheckMetadataValidators:
|
||||
"Url": "https://example.com",
|
||||
},
|
||||
},
|
||||
"Categories": ["security"],
|
||||
"Categories": ["encryption"],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "Test notes",
|
||||
@@ -1063,7 +1142,7 @@ class TestCheckMetadataValidators:
|
||||
"Url": "https://example.com",
|
||||
},
|
||||
},
|
||||
"Categories": ["security"],
|
||||
"Categories": ["encryption"],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "Test notes",
|
||||
@@ -1102,7 +1181,7 @@ class TestCheckMetadataValidators:
|
||||
"Url": "https://example.com",
|
||||
},
|
||||
},
|
||||
"Categories": ["security"],
|
||||
"Categories": ["encryption"],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "Test notes",
|
||||
@@ -1140,7 +1219,7 @@ class TestCheckMetadataValidators:
|
||||
"Url": "https://example.com",
|
||||
},
|
||||
},
|
||||
"Categories": ["security"],
|
||||
"Categories": ["encryption"],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "Test notes",
|
||||
@@ -1181,7 +1260,7 @@ class TestCheckMetadataValidators:
|
||||
"Url": "https://example.com",
|
||||
},
|
||||
},
|
||||
"Categories": ["security"],
|
||||
"Categories": ["encryption"],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "Test notes",
|
||||
@@ -1219,7 +1298,7 @@ class TestCheckMetadataValidators:
|
||||
"Url": "https://example.com",
|
||||
},
|
||||
},
|
||||
"Categories": ["security"],
|
||||
"Categories": ["encryption"],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "Test notes",
|
||||
@@ -1259,7 +1338,7 @@ class TestCheckMetadataValidators:
|
||||
"Url": "https://example.com",
|
||||
},
|
||||
},
|
||||
"Categories": ["security"],
|
||||
"Categories": ["encryption"],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "Test notes",
|
||||
@@ -1297,7 +1376,7 @@ class TestCheckMetadataValidators:
|
||||
"Url": "https://example.com",
|
||||
},
|
||||
},
|
||||
"Categories": ["security"],
|
||||
"Categories": ["encryption"],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "Test notes",
|
||||
@@ -1333,7 +1412,7 @@ class TestCheckMetadataValidators:
|
||||
"Url": "https://example.com",
|
||||
},
|
||||
},
|
||||
"Categories": ["security"],
|
||||
"Categories": ["encryption"],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "Test notes",
|
||||
@@ -1370,7 +1449,7 @@ class TestCheckMetadataValidators:
|
||||
"Url": "https://example.com",
|
||||
},
|
||||
},
|
||||
"Categories": ["security"],
|
||||
"Categories": ["encryption"],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "Test notes",
|
||||
@@ -1406,7 +1485,7 @@ class TestCheckMetadataValidators:
|
||||
"Url": "https://example.com",
|
||||
},
|
||||
},
|
||||
"Categories": ["security"],
|
||||
"Categories": ["encryption"],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "Test notes",
|
||||
@@ -1443,7 +1522,7 @@ class TestCheckMetadataValidators:
|
||||
"Url": "https://example.com",
|
||||
},
|
||||
},
|
||||
"Categories": ["security"],
|
||||
"Categories": ["encryption"],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "Test notes",
|
||||
@@ -1459,7 +1538,7 @@ class TestCheckMetadataValidators:
|
||||
Provider="aws",
|
||||
CheckID="test_check",
|
||||
CheckTitle="Test Check",
|
||||
CheckType=["type1"],
|
||||
CheckType=["Software and Configuration Checks/AWS Security Best Practices"],
|
||||
ServiceName="test",
|
||||
SubServiceName="subservice1",
|
||||
ResourceIdTemplate="template1",
|
||||
@@ -1477,7 +1556,7 @@ class TestCheckMetadataValidators:
|
||||
},
|
||||
"Recommendation": {"Text": "text1", "Url": "url1"},
|
||||
},
|
||||
Categories=["categoryone"],
|
||||
Categories=["encryption"],
|
||||
DependsOn=["dependency1"],
|
||||
RelatedTo=["related1"],
|
||||
Notes="notes1",
|
||||
@@ -1497,7 +1576,7 @@ class TestCheckMetadataValidators:
|
||||
Provider="aws",
|
||||
CheckID="test_check",
|
||||
CheckTitle="Test Check",
|
||||
CheckType=["type1"],
|
||||
CheckType=["Software and Configuration Checks/AWS Security Best Practices"],
|
||||
ServiceName="test",
|
||||
SubServiceName="subservice1",
|
||||
ResourceIdTemplate="template1",
|
||||
@@ -1515,7 +1594,7 @@ class TestCheckMetadataValidators:
|
||||
},
|
||||
"Recommendation": {"Text": "text1", "Url": "url1"},
|
||||
},
|
||||
Categories=["categoryone"],
|
||||
Categories=["encryption"],
|
||||
DependsOn=["dependency1"],
|
||||
RelatedTo=["related1"],
|
||||
Notes="notes1",
|
||||
@@ -1531,7 +1610,9 @@ class TestCheckMetadataValidators:
|
||||
Provider="aws",
|
||||
CheckID="test_check",
|
||||
CheckTitle="Test Check",
|
||||
CheckType=["type1"],
|
||||
CheckType=[
|
||||
"Software and Configuration Checks/AWS Security Best Practices"
|
||||
],
|
||||
ServiceName="test",
|
||||
SubServiceName="subservice1",
|
||||
ResourceIdTemplate="template1",
|
||||
@@ -1549,7 +1630,7 @@ class TestCheckMetadataValidators:
|
||||
},
|
||||
"Recommendation": {"Text": "text1", "Url": "url1"},
|
||||
},
|
||||
Categories=["categoryone"],
|
||||
Categories=["encryption"],
|
||||
DependsOn=["dependency1"],
|
||||
RelatedTo=["related1"],
|
||||
Notes="notes1",
|
||||
@@ -1565,7 +1646,9 @@ class TestCheckMetadataValidators:
|
||||
Provider="aws",
|
||||
CheckID="test_check",
|
||||
CheckTitle="Test Check",
|
||||
CheckType=["type1"],
|
||||
CheckType=[
|
||||
"Software and Configuration Checks/AWS Security Best Practices"
|
||||
],
|
||||
ServiceName="test",
|
||||
SubServiceName="subservice1",
|
||||
ResourceIdTemplate="template1",
|
||||
@@ -1583,7 +1666,7 @@ class TestCheckMetadataValidators:
|
||||
},
|
||||
"Recommendation": {"Text": "text1", "Url": "url1"},
|
||||
},
|
||||
Categories=["categoryone"],
|
||||
Categories=["encryption"],
|
||||
DependsOn=["dependency1"],
|
||||
RelatedTo=["related1"],
|
||||
Notes="notes1",
|
||||
@@ -1599,7 +1682,9 @@ class TestCheckMetadataValidators:
|
||||
Provider="aws",
|
||||
CheckID="test_check",
|
||||
CheckTitle="Test Check",
|
||||
CheckType=["type1"],
|
||||
CheckType=[
|
||||
"Software and Configuration Checks/AWS Security Best Practices"
|
||||
],
|
||||
ServiceName="test",
|
||||
SubServiceName="subservice1",
|
||||
ResourceIdTemplate="template1",
|
||||
@@ -1617,7 +1702,7 @@ class TestCheckMetadataValidators:
|
||||
},
|
||||
"Recommendation": {"Text": "text1", "Url": "url1"},
|
||||
},
|
||||
Categories=["categoryone"],
|
||||
Categories=["encryption"],
|
||||
DependsOn=["dependency1"],
|
||||
RelatedTo=["related1"],
|
||||
Notes="notes1",
|
||||
@@ -1633,7 +1718,9 @@ class TestCheckMetadataValidators:
|
||||
Provider="aws",
|
||||
CheckID="test_check",
|
||||
CheckTitle="Test Check",
|
||||
CheckType=["type1"],
|
||||
CheckType=[
|
||||
"Software and Configuration Checks/AWS Security Best Practices"
|
||||
],
|
||||
ServiceName="test",
|
||||
SubServiceName="subservice1",
|
||||
ResourceIdTemplate="template1",
|
||||
@@ -1651,7 +1738,7 @@ class TestCheckMetadataValidators:
|
||||
},
|
||||
"Recommendation": {"Text": "text1", "Url": "url1"},
|
||||
},
|
||||
Categories=["categoryone"],
|
||||
Categories=["encryption"],
|
||||
DependsOn=["dependency1"],
|
||||
RelatedTo=["related1"],
|
||||
Notes="notes1",
|
||||
@@ -1670,7 +1757,7 @@ class TestCheckMetadataValidators:
|
||||
Provider="aws",
|
||||
CheckID="test_check_empty_fields",
|
||||
CheckTitle="Test Check with Empty Fields",
|
||||
CheckType=["type1"],
|
||||
CheckType=["Software and Configuration Checks/AWS Security Best Practices"],
|
||||
ServiceName="test",
|
||||
SubServiceName="subservice1",
|
||||
ResourceIdTemplate="template1",
|
||||
@@ -1688,7 +1775,7 @@ class TestCheckMetadataValidators:
|
||||
},
|
||||
"Recommendation": {"Text": "text1", "Url": "url1"},
|
||||
},
|
||||
Categories=["categoryone"],
|
||||
Categories=["encryption"],
|
||||
DependsOn=["dependency1"],
|
||||
RelatedTo=["related1"],
|
||||
Notes="notes1",
|
||||
@@ -1706,7 +1793,7 @@ class TestCheckMetadataValidators:
|
||||
Provider="aws",
|
||||
CheckID="test_check_defaults",
|
||||
CheckTitle="Test Check with Default Fields",
|
||||
CheckType=["type1"],
|
||||
CheckType=["Software and Configuration Checks/AWS Security Best Practices"],
|
||||
ServiceName="test",
|
||||
SubServiceName="subservice1",
|
||||
ResourceIdTemplate="template1",
|
||||
@@ -1724,7 +1811,7 @@ class TestCheckMetadataValidators:
|
||||
},
|
||||
"Recommendation": {"Text": "text1", "Url": "url1"},
|
||||
},
|
||||
Categories=["categoryone"],
|
||||
Categories=["encryption"],
|
||||
DependsOn=["dependency1"],
|
||||
RelatedTo=["related1"],
|
||||
Notes="notes1",
|
||||
@@ -1743,7 +1830,9 @@ class TestCheckMetadataValidators:
|
||||
Provider="aws",
|
||||
CheckID="test_check_none_related_url",
|
||||
CheckTitle="Test Check with None RelatedUrl",
|
||||
CheckType=["type1"],
|
||||
CheckType=[
|
||||
"Software and Configuration Checks/AWS Security Best Practices"
|
||||
],
|
||||
ServiceName="test",
|
||||
SubServiceName="subservice1",
|
||||
ResourceIdTemplate="template1",
|
||||
@@ -1761,7 +1850,7 @@ class TestCheckMetadataValidators:
|
||||
},
|
||||
"Recommendation": {"Text": "text1", "Url": "url1"},
|
||||
},
|
||||
Categories=["categoryone"],
|
||||
Categories=["encryption"],
|
||||
DependsOn=["dependency1"],
|
||||
RelatedTo=["related1"],
|
||||
Notes="notes1",
|
||||
@@ -1778,7 +1867,9 @@ class TestCheckMetadataValidators:
|
||||
Provider="aws",
|
||||
CheckID="test_check_none_additional_urls",
|
||||
CheckTitle="Test Check with None AdditionalURLs",
|
||||
CheckType=["type1"],
|
||||
CheckType=[
|
||||
"Software and Configuration Checks/AWS Security Best Practices"
|
||||
],
|
||||
ServiceName="test",
|
||||
SubServiceName="subservice1",
|
||||
ResourceIdTemplate="template1",
|
||||
@@ -1796,7 +1887,7 @@ class TestCheckMetadataValidators:
|
||||
},
|
||||
"Recommendation": {"Text": "text1", "Url": "url1"},
|
||||
},
|
||||
Categories=["categoryone"],
|
||||
Categories=["encryption"],
|
||||
DependsOn=["dependency1"],
|
||||
RelatedTo=["related1"],
|
||||
Notes="notes1",
|
||||
@@ -1813,7 +1904,9 @@ class TestCheckMetadataValidators:
|
||||
Provider="aws",
|
||||
CheckID="test_check_invalid_additional_urls",
|
||||
CheckTitle="Test Check with Invalid AdditionalURLs",
|
||||
CheckType=["type1"],
|
||||
CheckType=[
|
||||
"Software and Configuration Checks/AWS Security Best Practices"
|
||||
],
|
||||
ServiceName="test",
|
||||
SubServiceName="subservice1",
|
||||
ResourceIdTemplate="template1",
|
||||
@@ -1831,7 +1924,7 @@ class TestCheckMetadataValidators:
|
||||
},
|
||||
"Recommendation": {"Text": "text1", "Url": "url1"},
|
||||
},
|
||||
Categories=["categoryone"],
|
||||
Categories=["encryption"],
|
||||
DependsOn=["dependency1"],
|
||||
RelatedTo=["related1"],
|
||||
Notes="notes1",
|
||||
@@ -1842,6 +1935,101 @@ class TestCheckMetadataValidators:
|
||||
assert "AdditionalURLs must be a list" in str(exc_info.value)
|
||||
|
||||
|
||||
class TestResourceGroupValidator:
|
||||
"""Test class for ResourceGroup validator"""
|
||||
|
||||
def _base_metadata(self, **overrides):
|
||||
"""Helper to build valid metadata with overrides"""
|
||||
base = {
|
||||
"Provider": "aws",
|
||||
"CheckID": "test_check",
|
||||
"CheckTitle": "Test Check",
|
||||
"CheckType": [
|
||||
"Software and Configuration Checks/AWS Security Best Practices"
|
||||
],
|
||||
"ServiceName": "test",
|
||||
"SubServiceName": "subtest",
|
||||
"ResourceIdTemplate": "template",
|
||||
"Severity": "high",
|
||||
"ResourceType": "TestResource",
|
||||
"Description": "Test description",
|
||||
"Risk": "Test risk",
|
||||
"RelatedUrl": "https://example.com",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "test command",
|
||||
"NativeIaC": "test native",
|
||||
"Other": "test other",
|
||||
"Terraform": "test terraform",
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "test recommendation",
|
||||
"Url": "https://example.com",
|
||||
},
|
||||
},
|
||||
"Categories": ["encryption"],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "Test notes",
|
||||
}
|
||||
base.update(overrides)
|
||||
return base
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"resource_group",
|
||||
[
|
||||
"compute",
|
||||
"container",
|
||||
"serverless",
|
||||
"database",
|
||||
"storage",
|
||||
"network",
|
||||
"IAM",
|
||||
"messaging",
|
||||
"security",
|
||||
"monitoring",
|
||||
"api_gateway",
|
||||
"ai_ml",
|
||||
"governance",
|
||||
"collaboration",
|
||||
"devops",
|
||||
"analytics",
|
||||
],
|
||||
)
|
||||
def test_valid_resource_group(self, resource_group):
|
||||
"""Test all valid ResourceGroup values are accepted"""
|
||||
metadata = CheckMetadata(**self._base_metadata(ResourceGroup=resource_group))
|
||||
assert metadata.ResourceGroup == resource_group
|
||||
|
||||
def test_resource_group_empty_string_allowed(self):
|
||||
"""Test that empty string (default) is allowed for ResourceGroup"""
|
||||
metadata = CheckMetadata(**self._base_metadata(ResourceGroup=""))
|
||||
assert metadata.ResourceGroup == ""
|
||||
|
||||
def test_resource_group_default_is_empty(self):
|
||||
"""Test that ResourceGroup defaults to empty string when not provided"""
|
||||
metadata = CheckMetadata(**self._base_metadata())
|
||||
assert metadata.ResourceGroup == ""
|
||||
|
||||
def test_resource_group_invalid_value(self):
|
||||
"""Test that invalid ResourceGroup value raises ValidationError"""
|
||||
with pytest.raises(ValidationError) as exc_info:
|
||||
CheckMetadata(**self._base_metadata(ResourceGroup="invalid_group"))
|
||||
assert "Invalid ResourceGroup: 'invalid_group'" in str(exc_info.value)
|
||||
|
||||
def test_resource_group_case_sensitive(self):
|
||||
"""Test that ResourceGroup validation is case-sensitive (IAM, not iam)"""
|
||||
with pytest.raises(ValidationError) as exc_info:
|
||||
CheckMetadata(**self._base_metadata(ResourceGroup="iam"))
|
||||
assert "Invalid ResourceGroup: 'iam'" in str(exc_info.value)
|
||||
|
||||
def test_resource_group_typo(self):
|
||||
"""Test that typos in ResourceGroup are rejected"""
|
||||
with pytest.raises(ValidationError) as exc_info:
|
||||
CheckMetadata(**self._base_metadata(ResourceGroup="computee"))
|
||||
assert "Invalid ResourceGroup: 'computee'" in str(exc_info.value)
|
||||
|
||||
|
||||
class TestCheck:
|
||||
@mock.patch("prowler.lib.check.models.CheckMetadata.parse_file")
|
||||
def test_verify_names_consistency_all_match(self, mock_parse_file):
|
||||
|
||||
@@ -37,7 +37,7 @@ class TestCSV:
|
||||
remediation_code_other="other-code",
|
||||
remediation_code_cli="cli-code",
|
||||
compliance={"compliance_key": "compliance_value"},
|
||||
categories=["categorya", "categoryb"],
|
||||
categories=["encryption", "logging"],
|
||||
depends_on=["dependency"],
|
||||
related_to=["related"],
|
||||
additional_urls=[
|
||||
@@ -101,7 +101,7 @@ class TestCSV:
|
||||
assert output_data["REMEDIATION_CODE_OTHER"] == "other-code"
|
||||
assert isinstance(output_data["COMPLIANCE"], str)
|
||||
assert output_data["COMPLIANCE"] == "compliance_key: compliance_value"
|
||||
assert output_data["CATEGORIES"] == "categorya | categoryb"
|
||||
assert output_data["CATEGORIES"] == "encryption | logging"
|
||||
assert output_data["DEPENDS_ON"] == "dependency"
|
||||
assert output_data["RELATED_TO"] == "related"
|
||||
assert (
|
||||
@@ -126,7 +126,7 @@ class TestCSV:
|
||||
output.batch_write_data_to_file()
|
||||
|
||||
mock_file.seek(0)
|
||||
expected_csv = f"AUTH_METHOD;TIMESTAMP;ACCOUNT_UID;ACCOUNT_NAME;ACCOUNT_EMAIL;ACCOUNT_ORGANIZATION_UID;ACCOUNT_ORGANIZATION_NAME;ACCOUNT_TAGS;FINDING_UID;PROVIDER;CHECK_ID;CHECK_TITLE;CHECK_TYPE;STATUS;STATUS_EXTENDED;MUTED;SERVICE_NAME;SUBSERVICE_NAME;SEVERITY;RESOURCE_TYPE;RESOURCE_UID;RESOURCE_NAME;RESOURCE_DETAILS;RESOURCE_TAGS;PARTITION;REGION;DESCRIPTION;RISK;RELATED_URL;REMEDIATION_RECOMMENDATION_TEXT;REMEDIATION_RECOMMENDATION_URL;REMEDIATION_CODE_NATIVEIAC;REMEDIATION_CODE_TERRAFORM;REMEDIATION_CODE_CLI;REMEDIATION_CODE_OTHER;COMPLIANCE;CATEGORIES;DEPENDS_ON;RELATED_TO;NOTES;PROWLER_VERSION;ADDITIONAL_URLS;ACCOUNT_OU_UID;ACCOUNT_OU_NAME\r\nprofile: default;{datetime.now()};123456789012;123456789012;;test-organization-id;test-organization;test-tag:test-value;test-unique-finding;aws;service_test_check_id;service_test_check_id;test-type;PASS;;False;service;;high;test-resource;;;;;aws;eu-west-1;check description;test-risk;test-url;;;;;;;test-compliance: test-compliance;test-category;test-dependency;test-related-to;test-notes;{prowler_version};https://docs.aws.amazon.com/prescriptive-guidance/latest/migration-operations-integration/best-practices.html | https://docs.aws.amazon.com/prescriptive-guidance/latest/migration-operations-integration/introduction.html;ou-abc1-12345678;Production/WebServices\r\n"
|
||||
expected_csv = f"AUTH_METHOD;TIMESTAMP;ACCOUNT_UID;ACCOUNT_NAME;ACCOUNT_EMAIL;ACCOUNT_ORGANIZATION_UID;ACCOUNT_ORGANIZATION_NAME;ACCOUNT_TAGS;FINDING_UID;PROVIDER;CHECK_ID;CHECK_TITLE;CHECK_TYPE;STATUS;STATUS_EXTENDED;MUTED;SERVICE_NAME;SUBSERVICE_NAME;SEVERITY;RESOURCE_TYPE;RESOURCE_UID;RESOURCE_NAME;RESOURCE_DETAILS;RESOURCE_TAGS;PARTITION;REGION;DESCRIPTION;RISK;RELATED_URL;REMEDIATION_RECOMMENDATION_TEXT;REMEDIATION_RECOMMENDATION_URL;REMEDIATION_CODE_NATIVEIAC;REMEDIATION_CODE_TERRAFORM;REMEDIATION_CODE_CLI;REMEDIATION_CODE_OTHER;COMPLIANCE;CATEGORIES;DEPENDS_ON;RELATED_TO;NOTES;PROWLER_VERSION;ADDITIONAL_URLS;ACCOUNT_OU_UID;ACCOUNT_OU_NAME\r\nprofile: default;{datetime.now()};123456789012;123456789012;;test-organization-id;test-organization;test-tag:test-value;test-unique-finding;aws;service_test_check_id;service_test_check_id;Software and Configuration Checks/AWS Security Best Practices/Network Reachability;PASS;;False;service;;high;test-resource;;;;;aws;eu-west-1;check description;test-risk;test-url;;;;;;;test-compliance: test-compliance;encryption;test-dependency;test-related-to;test-notes;{prowler_version};https://docs.aws.amazon.com/prescriptive-guidance/latest/migration-operations-integration/best-practices.html | https://docs.aws.amazon.com/prescriptive-guidance/latest/migration-operations-integration/introduction.html;ou-abc1-12345678;Production/WebServices\r\n"
|
||||
content = mock_file.read()
|
||||
|
||||
assert content == expected_csv
|
||||
@@ -204,7 +204,7 @@ class TestCSV:
|
||||
with patch.object(temp_file, "close", return_value=None):
|
||||
csv.batch_write_data_to_file()
|
||||
|
||||
expected_csv = f"AUTH_METHOD;TIMESTAMP;ACCOUNT_UID;ACCOUNT_NAME;ACCOUNT_EMAIL;ACCOUNT_ORGANIZATION_UID;ACCOUNT_ORGANIZATION_NAME;ACCOUNT_TAGS;FINDING_UID;PROVIDER;CHECK_ID;CHECK_TITLE;CHECK_TYPE;STATUS;STATUS_EXTENDED;MUTED;SERVICE_NAME;SUBSERVICE_NAME;SEVERITY;RESOURCE_TYPE;RESOURCE_UID;RESOURCE_NAME;RESOURCE_DETAILS;RESOURCE_TAGS;PARTITION;REGION;DESCRIPTION;RISK;RELATED_URL;REMEDIATION_RECOMMENDATION_TEXT;REMEDIATION_RECOMMENDATION_URL;REMEDIATION_CODE_NATIVEIAC;REMEDIATION_CODE_TERRAFORM;REMEDIATION_CODE_CLI;REMEDIATION_CODE_OTHER;COMPLIANCE;CATEGORIES;DEPENDS_ON;RELATED_TO;NOTES;PROWLER_VERSION;ADDITIONAL_URLS;ACCOUNT_OU_UID;ACCOUNT_OU_NAME\nprofile: default;{datetime.now()};123456789012;123456789012;;test-organization-id;test-organization;test-tag:test-value;test-unique-finding;aws;service_test_check_id;service_test_check_id;test-type;PASS;;False;service;;high;test-resource;;;;;aws;eu-west-1;check description;test-risk;test-url;;;;;;;test-compliance: test-compliance;test-category;test-dependency;test-related-to;test-notes;{prowler_version};https://docs.aws.amazon.com/prescriptive-guidance/latest/migration-operations-integration/best-practices.html | https://docs.aws.amazon.com/prescriptive-guidance/latest/migration-operations-integration/introduction.html;ou-abc1-12345678;Production/WebServices\n"
|
||||
expected_csv = f"AUTH_METHOD;TIMESTAMP;ACCOUNT_UID;ACCOUNT_NAME;ACCOUNT_EMAIL;ACCOUNT_ORGANIZATION_UID;ACCOUNT_ORGANIZATION_NAME;ACCOUNT_TAGS;FINDING_UID;PROVIDER;CHECK_ID;CHECK_TITLE;CHECK_TYPE;STATUS;STATUS_EXTENDED;MUTED;SERVICE_NAME;SUBSERVICE_NAME;SEVERITY;RESOURCE_TYPE;RESOURCE_UID;RESOURCE_NAME;RESOURCE_DETAILS;RESOURCE_TAGS;PARTITION;REGION;DESCRIPTION;RISK;RELATED_URL;REMEDIATION_RECOMMENDATION_TEXT;REMEDIATION_RECOMMENDATION_URL;REMEDIATION_CODE_NATIVEIAC;REMEDIATION_CODE_TERRAFORM;REMEDIATION_CODE_CLI;REMEDIATION_CODE_OTHER;COMPLIANCE;CATEGORIES;DEPENDS_ON;RELATED_TO;NOTES;PROWLER_VERSION;ADDITIONAL_URLS;ACCOUNT_OU_UID;ACCOUNT_OU_NAME\nprofile: default;{datetime.now()};123456789012;123456789012;;test-organization-id;test-organization;test-tag:test-value;test-unique-finding;aws;service_test_check_id;service_test_check_id;Software and Configuration Checks/AWS Security Best Practices/Network Reachability;PASS;;False;service;;high;test-resource;;;;;aws;eu-west-1;check description;test-risk;test-url;;;;;;;test-compliance: test-compliance;encryption;test-dependency;test-related-to;test-notes;{prowler_version};https://docs.aws.amazon.com/prescriptive-guidance/latest/migration-operations-integration/best-practices.html | https://docs.aws.amazon.com/prescriptive-guidance/latest/migration-operations-integration/introduction.html;ou-abc1-12345678;Production/WebServices\n"
|
||||
|
||||
temp_file.seek(0)
|
||||
|
||||
|
||||
@@ -910,7 +910,7 @@ class TestFinding:
|
||||
"provider": "test_provider",
|
||||
"checkid": "service_check_001",
|
||||
"checktitle": "Test Check",
|
||||
"checktype": [],
|
||||
"checktype": ["Security"],
|
||||
"servicename": "service",
|
||||
"subservicename": "SubService",
|
||||
"severity": "high",
|
||||
@@ -928,7 +928,7 @@ class TestFinding:
|
||||
},
|
||||
},
|
||||
"resourceidtemplate": "template",
|
||||
"categories": ["cat-one", "cat-two"],
|
||||
"categories": ["encryption", "logging"],
|
||||
"dependson": ["dep1"],
|
||||
"relatedto": ["rel1"],
|
||||
"notes": "Some notes",
|
||||
@@ -953,7 +953,7 @@ class TestFinding:
|
||||
assert meta.Provider == "test_provider"
|
||||
assert meta.CheckID == "service_check_001"
|
||||
assert meta.CheckTitle == "Test Check"
|
||||
assert meta.CheckType == []
|
||||
assert meta.CheckType == ["Security"]
|
||||
assert meta.ServiceName == "service"
|
||||
assert meta.SubServiceName == "SubService"
|
||||
assert meta.Severity == "high"
|
||||
@@ -968,7 +968,7 @@ class TestFinding:
|
||||
assert meta.Remediation.Code.CLI == "cli_code"
|
||||
assert meta.Remediation.Code.Other == "other_code"
|
||||
assert meta.ResourceIdTemplate == "template"
|
||||
assert meta.Categories == ["cat-one", "cat-two"]
|
||||
assert meta.Categories == ["encryption", "logging"]
|
||||
assert meta.DependsOn == ["dep1"]
|
||||
assert meta.RelatedTo == ["rel1"]
|
||||
assert meta.Notes == "Some notes"
|
||||
@@ -1167,7 +1167,7 @@ class TestFinding:
|
||||
"recommendation": {"text": "Fix it", "url": "http://fix-gcp.com"},
|
||||
},
|
||||
"resourceidtemplate": "template",
|
||||
"categories": ["cat-one", "cat-two"],
|
||||
"categories": ["encryption", "logging"],
|
||||
"dependson": ["dep1"],
|
||||
"relatedto": ["rel1"],
|
||||
"notes": "Some notes",
|
||||
@@ -1247,7 +1247,7 @@ class TestFinding:
|
||||
"recommendation": {"text": "Fix it", "url": "http://fix-k8s.com"},
|
||||
},
|
||||
"resourceidtemplate": "template",
|
||||
"categories": ["cat-one"],
|
||||
"categories": ["encryption"],
|
||||
"dependson": [],
|
||||
"relatedto": [],
|
||||
"notes": "K8s notes",
|
||||
@@ -1313,7 +1313,7 @@ class TestFinding:
|
||||
"recommendation": {"text": "Fix it", "url": "http://fix-m365.com"},
|
||||
},
|
||||
"resourceidtemplate": "template",
|
||||
"categories": ["cat-one"],
|
||||
"categories": ["encryption"],
|
||||
"dependson": [],
|
||||
"relatedto": [],
|
||||
"notes": "M365 notes",
|
||||
|
||||
@@ -32,7 +32,7 @@ def generate_finding_output(
|
||||
remediation_code_terraform: str = "",
|
||||
remediation_code_cli: str = "",
|
||||
remediation_code_other: str = "",
|
||||
categories: list[str] = ["test-category"],
|
||||
categories: list[str] = ["encryption"],
|
||||
depends_on: list[str] = ["test-dependency"],
|
||||
related_to: list[str] = ["test-related-to"],
|
||||
notes: str = "test-notes",
|
||||
|
||||
@@ -214,7 +214,7 @@ class TestOCSF:
|
||||
"status_id": 1,
|
||||
"unmapped": {
|
||||
"related_url": "test-url",
|
||||
"categories": ["test-category"],
|
||||
"categories": ["encryption"],
|
||||
"depends_on": ["test-dependency"],
|
||||
"related_to": ["test-related-to"],
|
||||
"additional_urls": [
|
||||
|
||||
Reference in New Issue
Block a user