Skip to content

Commit bd0c0ce

Browse files
authored
Gracefully exit of a override schema patch fails (#4134)
1 parent d09b366 commit bd0c0ce

File tree

4 files changed

+86
-4
lines changed

4 files changed

+86
-4
lines changed

src/cfnlint/schema/manager.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import os
1414
import re
1515
import shutil
16+
import sys
1617
import zipfile
1718
from copy import copy
1819
from functools import lru_cache
@@ -562,7 +563,11 @@ def patch(self, patch: SchemaPatch, region: str) -> None:
562563
except ResourceNotFoundError:
563564
# Resource type doesn't exist in this region
564565
continue
565-
schema.patch(patches=patches)
566+
try:
567+
schema.patch(patches=patches)
568+
except Exception as e:
569+
print(f"Error applying patch {patches} for {resource_type}: {e}")
570+
sys.exit(1)
566571

567572
@lru_cache(maxsize=None)
568573
def get_type_getatts(self, resource_type: str, region: str) -> AttributeDict:

src/cfnlint/schema/other_schema_manager.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import json
1010
import logging
1111
import os
12+
import sys
1213
from functools import lru_cache
1314
from typing import TYPE_CHECKING, Any
1415

@@ -116,9 +117,13 @@ def patch(self, patch: SchemaPatch, region: str) -> None:
116117
except SchemaNotFoundError:
117118
# Resource type doesn't exist in this region
118119
continue
119-
jsonpatch.JsonPatch(patches).apply(
120-
self._schemas[schema_path], in_place=True
121-
)
120+
try:
121+
jsonpatch.JsonPatch(patches).apply(
122+
self._schemas[schema_path], in_place=True
123+
)
124+
except Exception as e:
125+
print(f"Error applying patch {patches} for {schema_path}: {e}")
126+
sys.exit(1)
122127

123128

124129
OTHER_SCHEMA_MANAGER: OtherSchemaManager = OtherSchemaManager()

test/unit/module/schema/test_manager.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,3 +289,41 @@ def test_type_normalization(self):
289289
self.manager._registry_schemas[rt] = True
290290
schema = self.manager.get_resource_schema("us-east-1", rt)
291291
assert schema is True
292+
293+
294+
class TestManagerPatch(BaseTestCase):
295+
"""Test patching schemas"""
296+
297+
def setUp(self) -> None:
298+
super().setUp()
299+
self.manager = ProviderSchemaManager()
300+
self.schema_patch = [{"op": "add", "path": "/cfnSchema", "value": ["test"]}]
301+
302+
@patch("cfnlint.schema.manager.print")
303+
@patch("cfnlint.schema.manager.sys.exit")
304+
def test_patch_failure(self, mock_exit, mock_print):
305+
"""Test when patching a schema fails"""
306+
# Create a mock schema that will raise an exception when patch is called
307+
mock_schema = MagicMock()
308+
mock_schema.patch.side_effect = Exception("Invalid patch operation")
309+
310+
# Mock get_resource_schema to return our mocked schema
311+
self.manager.get_resource_schema = MagicMock(return_value=mock_schema)
312+
313+
# Create a patch
314+
resource_type = "AWS::EC2::Instance"
315+
patch = SchemaPatch([], [], {resource_type: self.schema_patch})
316+
317+
# Apply the patch
318+
self.manager.patch(patch, "us-east-1")
319+
320+
# Verify that print was called with the error message
321+
mock_print.assert_called_with(
322+
(
323+
f"Error applying patch {self.schema_patch} for "
324+
f"{resource_type}: Invalid patch operation"
325+
)
326+
)
327+
328+
# Verify that sys.exit was called with exit code 1
329+
mock_exit.assert_called_with(1)

test/unit/module/schema/test_other_schema_manager.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,40 @@ def test_patch_schema_not_found(self, mock_json_patch, mock_load_resource):
107107
# Verify patch was not applied
108108
mock_patch.apply.assert_not_called()
109109

110+
@patch("cfnlint.schema.other_schema_manager.load_resource")
111+
@patch("cfnlint.schema.other_schema_manager.jsonpatch.JsonPatch")
112+
@patch("cfnlint.schema.other_schema_manager.sys.exit")
113+
@patch("cfnlint.schema.other_schema_manager.print")
114+
def test_patch_failure(
115+
self, mock_print, mock_exit, mock_json_patch, mock_load_resource
116+
):
117+
"""Test when patching a schema fails"""
118+
# Setup the schema to be loaded successfully
119+
mock_load_resource.return_value = self.test_schema
120+
121+
# Setup the JsonPatch to raise an exception when apply is called
122+
mock_patch = MagicMock()
123+
mock_patch.apply.side_effect = Exception("Invalid patch operation")
124+
mock_json_patch.return_value = mock_patch
125+
126+
# Create a patch
127+
schema_path = "other.functions.join"
128+
patch = SchemaPatch([], [], {schema_path: self.schema_patch})
129+
130+
# Apply the patch
131+
self.manager.patch(patch, "us-east-1")
132+
133+
# Verify that print was called with the error message
134+
mock_print.assert_called_with(
135+
(
136+
f"Error applying patch {self.schema_patch} for "
137+
f"{schema_path}: Invalid patch operation"
138+
)
139+
)
140+
141+
# Verify that sys.exit was called with exit code 1
142+
mock_exit.assert_called_with(1)
143+
110144
@patch("cfnlint.schema.other_schema_manager.open", new_callable=mock_open)
111145
@patch("cfnlint.schema.other_schema_manager.os.walk")
112146
@patch("cfnlint.schema.other_schema_manager.os.path.join")

0 commit comments

Comments
 (0)