fix: refuse standalone copies install can't run

This commit is contained in:
Abdessamad Derraz committed 2026-10-10 12:13:18 +02:00
1 parent 61cba2d3c1
commit c64e146a43
4 files changed
+33 -2

No files matched your search

+1 -1
View File
@@ -8,7 +8,7 @@ param(
$ErrorActionPreference = "Stop" $ErrorActionPreference = "Stop"
$defaultInstallUrl = "https://raw.githubusercontent.com/Abdess/retrobios/main/install.py" $defaultInstallUrl = "https://raw.githubusercontent.com/Abdess/retrobios/main/install.py"
$defaultInstallSha256 = "44492e7dea7639fec18b2b9c040606481b11dd7a91987e8b2548313fc82c902d" $defaultInstallSha256 = "d5f352fbe34cfd8ae40c0980c3986158ec1d9dd1babfe2bbc0918ffc0fa0bdf0"
$maximumInstallerBytes = 2MB $maximumInstallerBytes = 2MB
$installer = if ($PSScriptRoot) { Join-Path $PSScriptRoot "install.py" } else { $null } $installer = if ($PSScriptRoot) { Join-Path $PSScriptRoot "install.py" } else { $null }
$temporary = $null $temporary = $null
+18
View File
@@ -980,6 +980,24 @@ def _validate_manifest(data: object, plat: str) -> dict:
for index, entry in enumerate(copies): for index, entry in enumerate(copies):
if not isinstance(entry, dict): if not isinstance(entry, dict):
raise ValueError(f"standalone_copies[{index}] must be an object") raise ValueError(f"standalone_copies[{index}] must be an object")
# The shape do_standalone_copies reads, checked here: a note with a
# list for detect, a copy naming neither file nor pattern, or a list
# for emulator passed and crashed the copy step after the download.
where = f"standalone_copies[{index}]"
if "note" in entry:
detect = entry.get("detect", {})
if not isinstance(entry["note"], str) or not isinstance(detect, dict):
raise ValueError(f"invalid note entry at {where}")
for values in detect.values():
if not isinstance(values, list) or not all(
isinstance(value, str) for value in values
):
raise ValueError(f"invalid note entry at {where}")
continue
if "file" not in entry and "pattern" not in entry:
raise ValueError(f"{where} names neither a file nor a pattern")
if not isinstance(entry.get("emulator", ""), str):
raise ValueError(f"invalid emulator at {where}")
if "file" in entry: if "file" in entry:
_safe_relative_path( _safe_relative_path(
entry["file"], f"standalone_copies[{index}].file" entry["file"], f"standalone_copies[{index}].file"
+1 -1
View File
@@ -18,7 +18,7 @@ esac
TEMP_INSTALLER="" TEMP_INSTALLER=""
TEMP_DIRECTORY="" TEMP_DIRECTORY=""
DEFAULT_INSTALL_URL="https://raw.githubusercontent.com/Abdess/retrobios/main/install.py" DEFAULT_INSTALL_URL="https://raw.githubusercontent.com/Abdess/retrobios/main/install.py"
DEFAULT_INSTALL_SHA256="44492e7dea7639fec18b2b9c040606481b11dd7a91987e8b2548313fc82c902d" DEFAULT_INSTALL_SHA256="d5f352fbe34cfd8ae40c0980c3986158ec1d9dd1babfe2bbc0918ffc0fa0bdf0"
MAX_INSTALLER_BYTES=2097152 MAX_INSTALLER_BYTES=2097152
cleanup() { cleanup() {
+13
View File
@@ -1138,6 +1138,19 @@ class TestStandaloneCopyTargetsAreUntrusted(unittest.TestCase):
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
install._validate_manifest(manifest, "retroarch") install._validate_manifest(manifest, "retroarch")
def test_entries_the_copy_step_cannot_read_are_refused(self):
"""Each passed validation and crashed do_standalone_copies after the
download: a list for detect, no file nor pattern, a list for emulator."""
for entry in (
{"note": "hi", "detect": ["/x"]},
{"emulator": "pcsx2", "targets": {"linux": ["/tmp"]}},
{"file": "bios/x.bin", "emulator": ["a"], "targets": {"linux": ["/tmp"]}},
):
manifest = {"manifest_version": 2, "platform": "retroarch", "files": [],
"standalone_copies": [entry]}
with self.subTest(entry=entry), self.assertRaises(ValueError):
install._validate_manifest(manifest, "retroarch")
def test_plain_absolute_target_still_works(self): def test_plain_absolute_target_still_works(self):
manifest = { manifest = {
"manifest_version": 2, "manifest_version": 2,