From 4b8e2f9de2e8a5734f71f8670c3125e9c70fa2a5 Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Fri, 23 Oct 2026 20:37:03 +0200 Subject: [PATCH] fix: check system_titles at the boundary A list or a number among the titles passed validation and raised later, in --system matching or the interface. --- install.ps1 | 2 +- install.py | 9 +++++++++ install.sh | 2 +- tests/test_install_selection.py | 13 +++++++++++++ 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/install.ps1 b/install.ps1 index ab608c8f..1ddca47e 100644 --- a/install.ps1 +++ b/install.ps1 @@ -11,7 +11,7 @@ $ErrorActionPreference = "Stop" $defaultInstallUrl = "https://raw.githubusercontent.com/Abdess/retrobios/main/install.py" - $defaultInstallSha256 = "5fedfbf308ba04a174ce0682380a28150b6fe5eab514a605e3b318193ce37c7a" + $defaultInstallSha256 = "6d8af0dbca6697ba71692e5e482c8a16d9e8b9896652fec722d9c84f23bba047" $maximumInstallerBytes = 2MB $installerExit = 0 $installer = if ($PSScriptRoot) { Join-Path $PSScriptRoot "install.py" } else { $null } diff --git a/install.py b/install.py index 8f2464c7..cb583f7f 100644 --- a/install.py +++ b/install.py @@ -3069,6 +3069,15 @@ def _validate_manifest(data: object, plat: str) -> dict: _check_tags(mapping, key, field) if mapping[key] is None: raise ValueError(f"invalid {field} for {key}") + titles = data.get("system_titles") + if titles is not None: + if not isinstance(titles, dict) or len(titles) > MAX_MANIFEST_FILES: + raise ValueError("invalid system_titles") + for key, title in titles.items(): + if not isinstance(key, str) or not 0 < len(key) <= 256: + raise ValueError("invalid system_titles key") + if not isinstance(title, str) or not 0 < len(title) <= 256: + raise ValueError(f"invalid system_titles for {key}") copies = data.get("standalone_copies", []) if not isinstance(copies, list) or len(copies) > 10_000: diff --git a/install.sh b/install.sh index 47b0c4da..e85ff322 100755 --- a/install.sh +++ b/install.sh @@ -18,7 +18,7 @@ esac TEMP_INSTALLER="" TEMP_DIRECTORY="" DEFAULT_INSTALL_URL="https://raw.githubusercontent.com/Abdess/retrobios/main/install.py" -DEFAULT_INSTALL_SHA256="5fedfbf308ba04a174ce0682380a28150b6fe5eab514a605e3b318193ce37c7a" +DEFAULT_INSTALL_SHA256="6d8af0dbca6697ba71692e5e482c8a16d9e8b9896652fec722d9c84f23bba047" MAX_INSTALLER_BYTES=2097152 cleanup() { diff --git a/tests/test_install_selection.py b/tests/test_install_selection.py index 97b969b3..5cf8f481 100644 --- a/tests/test_install_selection.py +++ b/tests/test_install_selection.py @@ -493,6 +493,19 @@ class TheBoundaryChecksTheNewFields(unittest.TestCase): with self.subTest(field=field, value=bad), self.assertRaises(ValueError): install._validate_manifest(manifest, "retroarch") + def test_the_system_titles(self): + """A title is read as text by --system and the interface: a list or + a number there raised mid-run instead of at the boundary.""" + good = self._manifest() + good["system_titles"] = {"sony-playstation": "Sony PlayStation"} + install._validate_manifest(good, "retroarch") + for bad in (["x"], {"s": ["Sony"]}, {"s": None}, {"s": 5}, {"s": ""}, + {"": "Sony"}, {"s": "x" * 257}, {"s" * 257: "Sony"}): + manifest = self._manifest() + manifest["system_titles"] = bad + with self.subTest(value=bad), self.assertRaises(ValueError): + install._validate_manifest(manifest, "retroarch") + class _QuietHandler(http.server.SimpleHTTPRequestHandler): def log_message(self, format, *args): # noqa: A002 - stdlib signature