Skip to content

Commit 3a1ebc9

Browse files
authored
Handle malformed addon map entries gracefully (#6126)
* Handle missing type attribute in add-on map config Handle missing type attribute in the add-on `map` configuration key. * Make sure wrong volumes are cleared in any case Also add warning when string mapping is rejected. * Add unit tests * Improve test coverage
1 parent 580c327 commit 3a1ebc9

File tree

2 files changed

+55
-2
lines changed

2 files changed

+55
-2
lines changed

supervisor/addons/validate.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -266,10 +266,23 @@ def _migrate(config: dict[str, Any]):
266266
volumes = []
267267
for entry in config.get(ATTR_MAP, []):
268268
if isinstance(entry, dict):
269+
# Validate that dict entries have required 'type' field
270+
if ATTR_TYPE not in entry:
271+
_LOGGER.warning(
272+
"Add-on config has invalid map entry missing 'type' field: %s. Skipping invalid entry for %s",
273+
entry,
274+
name,
275+
)
276+
continue
269277
volumes.append(entry)
270278
if isinstance(entry, str):
271279
result = RE_VOLUME.match(entry)
272280
if not result:
281+
_LOGGER.warning(
282+
"Add-on config has invalid map entry: %s. Skipping invalid entry for %s",
283+
entry,
284+
name,
285+
)
273286
continue
274287
volumes.append(
275288
{
@@ -278,8 +291,8 @@ def _migrate(config: dict[str, Any]):
278291
}
279292
)
280293

281-
if volumes:
282-
config[ATTR_MAP] = volumes
294+
# Always update config to clear potentially malformed ones
295+
config[ATTR_MAP] = volumes
283296

284297
# 2023-10 "config" became "homeassistant" so /config can be used for addon's public config
285298
if any(volume[ATTR_TYPE] == MappingType.CONFIG for volume in volumes):

tests/addons/test_config.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,46 @@ def test_valid_map():
140140
vd.SCHEMA_ADDON_CONFIG(config)
141141

142142

143+
def test_malformed_map_entries():
144+
"""Test that malformed map entries are handled gracefully (issue #6124)."""
145+
config = load_json_fixture("basic-addon-config.json")
146+
147+
# Test case 1: Empty dict in map (should be skipped with warning)
148+
config["map"] = [{}]
149+
valid_config = vd.SCHEMA_ADDON_CONFIG(config)
150+
assert valid_config["map"] == []
151+
152+
# Test case 2: Dict missing required 'type' field (should be skipped with warning)
153+
config["map"] = [{"read_only": False, "path": "/custom"}]
154+
valid_config = vd.SCHEMA_ADDON_CONFIG(config)
155+
assert valid_config["map"] == []
156+
157+
# Test case 3: Invalid string format that doesn't match regex
158+
config["map"] = ["invalid_format", "not:a:valid:mapping", "share:invalid_mode"]
159+
valid_config = vd.SCHEMA_ADDON_CONFIG(config)
160+
assert valid_config["map"] == []
161+
162+
# Test case 4: Mix of valid and invalid entries (invalid should be filtered out)
163+
config["map"] = [
164+
"share:rw", # Valid string format
165+
"invalid_string", # Invalid string format
166+
{}, # Invalid empty dict
167+
{"type": "config", "read_only": True}, # Valid dict format
168+
{"read_only": False}, # Invalid - missing type
169+
]
170+
valid_config = vd.SCHEMA_ADDON_CONFIG(config)
171+
# Should only keep the valid entries
172+
assert len(valid_config["map"]) == 2
173+
assert any(entry["type"] == "share" for entry in valid_config["map"])
174+
assert any(entry["type"] == "config" for entry in valid_config["map"])
175+
176+
# Test case 5: The specific case from the UplandJacob repo (malformed YAML format)
177+
# This simulates what YAML "- addon_config: rw" creates
178+
config["map"] = [{"addon_config": "rw"}] # Wrong structure, missing 'type' key
179+
valid_config = vd.SCHEMA_ADDON_CONFIG(config)
180+
assert valid_config["map"] == []
181+
182+
143183
def test_valid_basic_build():
144184
"""Validate basic build config."""
145185
config = load_json_fixture("basic-build-config.json")

0 commit comments

Comments
 (0)