mirror of
https://github.com/prowler-cloud/prowler.git
synced 2025-12-19 05:17:47 +00:00
Compare commits
6 Commits
d15dd53708
...
todo-check
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b384718bb0 | ||
|
|
120f788095 | ||
|
|
e9f528ce27 | ||
|
|
8286531a9a | ||
|
|
350739ae71 | ||
|
|
258216d651 |
@@ -7,6 +7,7 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
### Added
|
||||
- Support for AdditionalURLs in outputs [(#8651)](https://github.com/prowler-cloud/prowler/pull/8651)
|
||||
- Support for markdown metadata fields in Dashboard [(#8667)](https://github.com/prowler-cloud/prowler/pull/8667)
|
||||
- Equality validation for CheckID, filename and classname [(#8690)](https://github.com/prowler-cloud/prowler/pull/8690)
|
||||
|
||||
### Changed
|
||||
- Update AWS Neptune service metadata to new format [(#8494)](https://github.com/prowler-cloud/prowler/pull/8494)
|
||||
|
||||
@@ -8,6 +8,7 @@ from enum import Enum
|
||||
from typing import Any, Dict, Optional, Set
|
||||
|
||||
from pydantic.v1 import BaseModel, Field, ValidationError, validator
|
||||
from pydantic.v1.error_wrappers import ErrorWrapper
|
||||
|
||||
from prowler.config.config import Provider
|
||||
from prowler.lib.check.compliance_models import Compliance
|
||||
@@ -436,17 +437,31 @@ class Check(ABC, CheckMetadata):
|
||||
|
||||
def __init__(self, **data):
|
||||
"""Check's init function. Calls the CheckMetadataModel init."""
|
||||
file_path = os.path.abspath(sys.modules[self.__module__].__file__)[:-3]
|
||||
|
||||
# Parse the Check's metadata file
|
||||
metadata_file = (
|
||||
os.path.abspath(sys.modules[self.__module__].__file__)[:-3]
|
||||
+ ".metadata.json"
|
||||
)
|
||||
metadata_file = file_path + ".metadata.json"
|
||||
# Store it to validate them with Pydantic
|
||||
data = CheckMetadata.parse_file(metadata_file).dict()
|
||||
# Calls parents init function
|
||||
super().__init__(**data)
|
||||
# TODO: verify that the CheckID is the same as the filename and classname
|
||||
# to mimic the test done at test_<provider>_checks_metadata_is_valid
|
||||
|
||||
# Verify names consistency
|
||||
check_id = self.CheckID
|
||||
class_name = self.__class__.__name__
|
||||
file_name = file_path.split(sep="/")[-1]
|
||||
|
||||
errors = []
|
||||
if check_id != class_name:
|
||||
errors.append(f"CheckID '{check_id}' != class name '{class_name}'")
|
||||
if check_id != file_name:
|
||||
errors.append(f"CheckID '{check_id}' != file name '{file_name}'")
|
||||
|
||||
if errors:
|
||||
formatted_errors = [
|
||||
ErrorWrapper(ValueError(err), loc=("CheckID",)) for err in errors
|
||||
]
|
||||
raise ValidationError(formatted_errors, model=CheckMetadata)
|
||||
|
||||
def metadata(self) -> dict:
|
||||
"""Return the JSON representation of the check's metadata"""
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import sys
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
from pydantic.v1 import ValidationError
|
||||
|
||||
from prowler.lib.check.models import CheckMetadata
|
||||
from prowler.lib.check.models import Check, CheckMetadata
|
||||
from tests.lib.check.compliance_check_test import custom_compliance_metadata
|
||||
|
||||
mock_metadata = CheckMetadata(
|
||||
@@ -716,3 +717,96 @@ class TestCheckMetada:
|
||||
)
|
||||
# Should contain the validation error we set in the validator
|
||||
assert "AdditionalURLs must be a list" 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):
|
||||
"""Case where everything matches: CheckID == class_name == file_name"""
|
||||
mock_parse_file.return_value = mock_metadata.copy(
|
||||
update={
|
||||
"CheckID": "accessanalyzer_enabled",
|
||||
"ServiceName": "accessanalyzer",
|
||||
}
|
||||
)
|
||||
|
||||
class accessanalyzer_enabled(Check):
|
||||
def execute(self):
|
||||
pass
|
||||
|
||||
fake_module = mock.Mock()
|
||||
fake_module.__file__ = "/path/to/accessanalyzer_enabled.py"
|
||||
sys.modules[accessanalyzer_enabled.__module__] = fake_module
|
||||
|
||||
accessanalyzer_enabled()
|
||||
|
||||
@mock.patch("prowler.lib.check.models.CheckMetadata.parse_file")
|
||||
def test_verify_names_consistency_class_mismatch(self, mock_parse_file):
|
||||
"""CheckID != class name, but matches file_name"""
|
||||
mock_parse_file.return_value = mock_metadata.copy(
|
||||
update={
|
||||
"CheckID": "accessanalyzer_enabled",
|
||||
"ServiceName": "accessanalyzer",
|
||||
}
|
||||
)
|
||||
|
||||
class WrongClass(Check):
|
||||
def execute(self):
|
||||
pass
|
||||
|
||||
fake_module = mock.Mock()
|
||||
fake_module.__file__ = "/path/to/accessanalyzer_enabled.py"
|
||||
sys.modules[WrongClass.__module__] = fake_module
|
||||
|
||||
with pytest.raises(ValidationError) as excinfo:
|
||||
WrongClass()
|
||||
|
||||
assert "!= class name" in str(excinfo.value)
|
||||
|
||||
@mock.patch("prowler.lib.check.models.CheckMetadata.parse_file")
|
||||
def test_verify_names_consistency_file_mismatch(self, mock_parse_file):
|
||||
"""CheckID == class name, but != file_name"""
|
||||
mock_parse_file.return_value = mock_metadata.copy(
|
||||
update={
|
||||
"CheckID": "accessanalyzer_enabled",
|
||||
"ServiceName": "accessanalyzer",
|
||||
}
|
||||
)
|
||||
|
||||
class accessanalyzer_enabled(Check):
|
||||
def execute(self):
|
||||
pass
|
||||
|
||||
fake_module = mock.Mock()
|
||||
fake_module.__file__ = "/path/to/OtherFile.py"
|
||||
sys.modules[accessanalyzer_enabled.__module__] = fake_module
|
||||
|
||||
with pytest.raises(ValidationError) as excinfo:
|
||||
accessanalyzer_enabled()
|
||||
|
||||
assert "!= file name" in str(excinfo.value)
|
||||
|
||||
@mock.patch("prowler.lib.check.models.CheckMetadata.parse_file")
|
||||
def test_verify_names_consistency_both_mismatch(self, mock_parse_file):
|
||||
"""Neither class name nor file name match the CheckID"""
|
||||
mock_parse_file.return_value = mock_metadata.copy(
|
||||
update={
|
||||
"CheckID": "accessanalyzer_enabled",
|
||||
"ServiceName": "accessanalyzer",
|
||||
}
|
||||
)
|
||||
|
||||
class WrongClass(Check):
|
||||
def execute(self):
|
||||
pass
|
||||
|
||||
fake_module = mock.Mock()
|
||||
fake_module.__file__ = "/path/to/OtherFile.py"
|
||||
sys.modules[WrongClass.__module__] = fake_module
|
||||
|
||||
with pytest.raises(ValidationError) as excinfo:
|
||||
WrongClass()
|
||||
|
||||
msg = str(excinfo.value)
|
||||
assert "!= class name" in msg
|
||||
assert "!= file name" in msg
|
||||
|
||||
Reference in New Issue
Block a user