Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 74 additions & 17 deletions slp_mtmt/tests/integration/test_mtmt_processor.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
import json
from unittest.mock import patch

from pytest import mark

import pytest
from pytest import mark, param
from sl_util.sl_util.file_utils import get_byte_data
from sl_util.tests.util.file_utils import generate_temporary_file
from slp_base.slp_base.errors import SourceFileNotValidError, MappingFileNotValidError, ErrorCode
from slp_base.slp_base.mapping import MAX_SIZE as MAPPING_MAX_SIZE, MIN_SIZE as MAPPING_MIN_SIZE
from slp_base.tests.util.otm import validate_and_compare
from slp_mtmt import MTMTProcessor
from slp_mtmt.slp_mtmt.mtmt_validator import MIN_SIZE as FILE_MIN_SIZE, MAX_SIZE as FILE_MAX_SIZE
from slp_mtmt.tests.resources import test_resource_paths
from slp_mtmt.tests.resources.test_resource_paths import mapping_mtmt_mvp_legacy, mapping_mtmt_mvp_no_type, \
model_mtmt_mvp_otm, missing_position_otm, nested_trustzones_tm7, nested_trustzones_otm, nested_trustzones_line_otm, \
nested_trustzones_line_tm7
from slp_mtmt.tests.resources.test_resource_paths import model_mtmt_mvp_otm, missing_position_otm, \
nested_trustzones_tm7, nested_trustzones_otm, nested_trustzones_line_otm, nested_trustzones_line_tm7

SAMPLE_ID = 'example-project'
SAMPLE_NAME = 'Example Project'
SAMPLE_VALID_MTMT_FILE = test_resource_paths.model_mtmt_mvp
SAMPLE_VALID_MAPPING_FILE = test_resource_paths.mapping_mtmt_mvp
SAMPLE_VALID_MAPPING_MVP_LEGACY_FILE = test_resource_paths.mapping_mtmt_mvp_legacy
SAMPLE_VALID_MAPPING_MVP_NO_TYPE_FILE = test_resource_paths.mapping_mtmt_mvp_no_type
DEFAULT_MAPPING_FILE = test_resource_paths.mtmt_default_mapping
MTMT_MISSING_POSITION = test_resource_paths.missing_position
MTMT_EXAMPLE_POSITION = test_resource_paths.example_position_tm7
Expand All @@ -23,7 +28,9 @@
OTM_EXAMPLE_1LINE = test_resource_paths.position_1line_tz_otm
MTMT_EXAMPLE_1ORPHAN = test_resource_paths.position_1orphan_tm7
OTM_EXAMPLE_1ORPHAN = test_resource_paths.position_1orphan_otm

SAMPLE_UNMAPPED_TRUSTZONES = test_resource_paths.unmapped_trustzones_tm7
SAMPLE_UNMAPPED_TRUSTZONES_OTM = test_resource_paths.unmapped_trustzones_otm
SAMPLE_MODEL_NO_NAME_FIGURES = test_resource_paths.model_with_no_name_figures_tm7

class TestMtmtProcessor:
excluded_regex = [
Expand All @@ -32,7 +39,8 @@ class TestMtmtProcessor:
r"root\['mitigations'\]"
]

@mark.parametrize('mapping_file', [SAMPLE_VALID_MAPPING_FILE, mapping_mtmt_mvp_legacy, mapping_mtmt_mvp_no_type])
@mark.parametrize('mapping_file',
[SAMPLE_VALID_MAPPING_FILE, SAMPLE_VALID_MAPPING_MVP_LEGACY_FILE, SAMPLE_VALID_MAPPING_MVP_NO_TYPE_FILE])
def test_run_valid_mappings(self, mapping_file):
# GIVEN a valid MTMT file with some resources
source_file = get_byte_data(SAMPLE_VALID_MTMT_FILE)
Expand Down Expand Up @@ -70,9 +78,11 @@ def test_run_some_missing_source_coordinates(self, validate):
@mark.parametrize('source, expected', [
(MTMT_EXAMPLE_POSITION, OTM_EXAMPLE_POSITION),
(MTMT_EXAMPLE_1LINE, OTM_EXAMPLE_1LINE),
(MTMT_EXAMPLE_1ORPHAN, OTM_EXAMPLE_1ORPHAN)
(MTMT_EXAMPLE_1ORPHAN, OTM_EXAMPLE_1ORPHAN),
(nested_trustzones_tm7, nested_trustzones_otm),
(nested_trustzones_line_tm7, nested_trustzones_line_otm)
])
def test_coordinates_borders(self, source, expected):
def test_otm_output_of_valid_mtmt(self, source, expected):
# GIVEN a valid MTMT file
source_file = get_byte_data(source)

Expand All @@ -92,19 +102,15 @@ def test_coordinates_borders(self, source, expected):
result, expected = validate_and_compare(otm_json, expected_otm, self.excluded_regex)
assert result == expected

@mark.parametrize('source,expected', [
(nested_trustzones_tm7, nested_trustzones_otm),
(nested_trustzones_line_tm7, nested_trustzones_line_otm)
])
def test_nested_trust_zones(self, source, expected):
def test_unmapped_trust_zones(self):
# GIVEN a valid MTMT file
source_file = get_byte_data(source)
source_file = get_byte_data(SAMPLE_UNMAPPED_TRUSTZONES)

# AND a valid MTMT mapping file
mapping_file = get_byte_data(DEFAULT_MAPPING_FILE)

# AND the expected OTM
expected_otm = json.loads(get_byte_data(expected))
expected_otm = json.loads(get_byte_data(SAMPLE_UNMAPPED_TRUSTZONES_OTM))

# WHEN the MTMT file is processed
otm = MTMTProcessor(SAMPLE_ID, SAMPLE_NAME, source_file, [mapping_file]).process()
Expand All @@ -114,4 +120,55 @@ def test_nested_trust_zones(self, source, expected):

# THEN we check the result is as expected
result, expected = validate_and_compare(otm_json, expected_otm, self.excluded_regex)
assert result == expected
assert result == expected

def test_model_with_no_name_figures(self):
# GIVEN a valid MTMT file
source_file = get_byte_data(SAMPLE_MODEL_NO_NAME_FIGURES)

# AND a valid MTMT mapping file
mapping_file = get_byte_data(DEFAULT_MAPPING_FILE)

# WHEN the MTMT file is processed
otm = MTMTProcessor(SAMPLE_ID, SAMPLE_NAME, source_file, [mapping_file]).process()

# THEN we check the result is as expected
assert len(otm.trustzones) == 3
assert len(otm.components) == 4
assert len(otm.dataflows) == 3

@mark.parametrize('source_file', [
param(generate_temporary_file(FILE_MIN_SIZE - 1), id='mtmt file too small'),
param(generate_temporary_file(FILE_MAX_SIZE + 1), id='mtmt file too big')
])
def test_invalid_file_size(self, source_file: bytes):
# GIVEN a valid MTMT mapping file
mapping_file = get_byte_data(DEFAULT_MAPPING_FILE)

# WHEN MTMTProcessor::process is invoked
# THEN a SourceFileNotValidError is raised
with pytest.raises(SourceFileNotValidError) as error:
MTMTProcessor(SAMPLE_ID, SAMPLE_NAME, source_file, [mapping_file]).process()

# AND whose information is right
assert error.value.title == 'Microsoft Threat Modeling Tool file is not valid'
assert error.value.message == 'Provided source_file is not valid. Invalid size'

@mark.parametrize('mappings', [
param([generate_temporary_file(MAPPING_MIN_SIZE - 1)], id='default mapping file too small'),
param([generate_temporary_file(MAPPING_MAX_SIZE + 1)], id='default mapping file too big')
])
def test_invalid_mapping_file_size(self, mappings: list[bytes]):
# GIVEN a valid MTMT file with some resources
source_file = get_byte_data(SAMPLE_VALID_MTMT_FILE)

# WHEN MTMTProcessor::process is invoked
# THEN a MappingFileNotValidError is raised
with pytest.raises(MappingFileNotValidError) as error:
MTMTProcessor(SAMPLE_ID, SAMPLE_NAME, source_file, mappings).process()

# AND the error details are correct
assert ErrorCode.MAPPING_FILE_NOT_VALID == error.value.error_code
assert 'Mapping files are not valid' == error.value.title
assert 'Mapping files are not valid. Invalid size' == error.value.detail
assert 'Mapping files are not valid. Invalid size' == error.value.message

Large diffs are not rendered by default.

Loading
Loading