diff --git a/supervisor/addons/options.py b/supervisor/addons/options.py index 8a6c325e9..1c7e4d737 100644 --- a/supervisor/addons/options.py +++ b/supervisor/addons/options.py @@ -169,6 +169,10 @@ class AddonOptions(CoreSysAttributes): elif typ.startswith(_LIST): return vol.In(match.group("list").split("|"))(str(value)) elif typ.startswith(_DEVICE): + if not isinstance(value, str): + raise vol.Invalid( + f"Expected a string for option '{key}' in {self._name} ({self._slug})" + ) try: device = self.sys_hardware.get_by_path(Path(value)) except HardwareNotFound: diff --git a/tests/addons/test_options.py b/tests/addons/test_options.py index f47fc24ed..72e2d7a54 100644 --- a/tests/addons/test_options.py +++ b/tests/addons/test_options.py @@ -273,6 +273,25 @@ def test_simple_device_schema(coresys): )({"name": "Pascal", "password": "1234", "input": "/dev/video1"}) +def test_device_schema_wrong_type(coresys): + """Test device option rejects non-string values.""" + with pytest.raises(vol.error.Invalid): + AddonOptions( + coresys, + {"name": "str", "input": "device(subsystem=tty)"}, + MOCK_ADDON_NAME, + MOCK_ADDON_SLUG, + )({"name": "Pascal", "input": {"baudrate": 115200, "flow_control": True}}) + + with pytest.raises(vol.error.Invalid): + AddonOptions( + coresys, + {"name": "str", "input": "device"}, + MOCK_ADDON_NAME, + MOCK_ADDON_SLUG, + )({"name": "Pascal", "input": 12345}) + + def test_simple_schema_password(coresys): """Test with simple schema password pwned.""" validate = AddonOptions(