fix: accept the lists a pack carries

Since ddafc2ff4 a pack's manifest.json holds install_list and
targets, which install.py reads with the pack alone. The pack schema
refused both. It now names them, and validate_schemas.py checks each
against the install and target manifest schemas.
This commit is contained in:
Abdessamad Derraz committed 2026-11-10 02:05:59 +01:00
1 parent 372d41e3b4
commit f08d6bccf6
3 files changed
+53

No files matched your search

+8
View File
@@ -54,6 +54,14 @@
"type": "array",
"uniqueItems": true,
"items": { "enum": ["systems", "cores", "regions"] }
},
"install_list": {
"description": "The install manifest built with the same choices as the pack, as install/<platform>.json holds it. With the pack alone, the installer narrows by system, core and region from it. validate_schemas.py checks it against install-manifest.schema.json.",
"type": "object"
},
"targets": {
"description": "The platform's cores per hardware target, as install/targets/<platform>.json publishes them. With the pack alone, the installer applies the card's board and accepts --target from it. validate_schemas.py checks it against target-manifest.schema.json.",
"type": "object"
}
}
}
+9
View File
@@ -230,6 +230,12 @@ def _validate_pack_manifests(dist: Path) -> list[str]:
def _scan_pack_manifests(dist: Path) -> list[str]:
validator = _validator("pack-manifest.schema.json")
# The lists a pack carries for the installer, each under its own
# contract: the schemas name no other file, so they are checked here.
carried = {
"install_list": _validator("install-manifest.schema.json"),
"targets": _validator("target-manifest.schema.json"),
}
def _label(path: Path) -> str:
resolved = path.resolve()
@@ -255,6 +261,9 @@ def _scan_pack_manifests(dist: Path) -> list[str]:
out.append(f"{label}: {exc}")
continue
out.extend(_errors(validator, document, label))
for key, inner in carried.items():
if isinstance(document, dict) and key in document:
out.extend(_errors(inner, document[key], f"{label}:{key}"))
except (OSError, zipfile.BadZipFile) as exc:
out.append(f"{_label(archive)}: {exc}")
return out
+36
View File
@@ -2139,6 +2139,42 @@ class InstallerBoundaryRegressions(unittest.TestCase):
self.assertTrue(errors, "an invalid in-archive manifest must be reported")
self.assertTrue(any("sha1" in message for message in errors), errors)
@unittest.skipUnless(HAS_JSONSCHEMA, "validating a schema needs jsonschema")
def test_a_pack_carries_its_install_list_and_board_lists(self):
"""pack_systems puts the install list and the per-board core lists
in the pack's manifest.json, which install.py reads with the pack
alone. The pack schema refused both keys, and each is checked under
its own contract."""
import generate_pack
import validate_schemas
install_list = json.loads((ROOT / "install" / "romm.json").read_text(encoding="utf-8"))
targets = {"browser": None, "rpi4": {"cores": ["mgba"], "images": ["rpi4"]}}
document = {
"schema_version": 1, "version": 1,
"generator": "retrobios generate_pack.py",
"generated": "2026-08-10T00:00:00Z", "files": [],
"summary": {"total_files": 0, "verified": 0, "untracked": 0, "errors": 0},
"errors": [],
}
generate_pack.annotate_pack_systems(
document, generate_pack.pack_systems(install_list, targets))
self.assertIn("install_list", document)
self.assertIn("targets", document)
with tempfile.TemporaryDirectory(dir=TMP_ROOT) as directory:
dist = Path(directory)
with zipfile.ZipFile(dist / "Pack.zip", "w") as archive:
archive.writestr("manifest.json", json.dumps(document))
self.assertEqual(validate_schemas._validate_pack_manifests(dist), [])
broken = {**document, "targets": {"rpi4": [1]},
"install_list": {**install_list, "files": "none"}}
with zipfile.ZipFile(dist / "Pack.zip", "w") as archive:
archive.writestr("manifest.json", json.dumps(broken))
errors = validate_schemas._validate_pack_manifests(dist)
self.assertTrue(any(":targets:" in message for message in errors), errors)
self.assertTrue(any(":install_list:" in message for message in errors), errors)
def test_null_core_list_keeps_the_other_targets(self):
"""A target without a core inventory must not void the manifest.