diff --git a/build_scripts/README.md b/build_scripts/README.md index 2682f8179..496e39c39 100644 --- a/build_scripts/README.md +++ b/build_scripts/README.md @@ -219,7 +219,8 @@ build jobs together. The workflow pipes `komac update --dry-run` output through `awk` to save separate YAML files by manifest type and locale; dry-run returns before handling `--output`. [winget_manifest.py](winget_manifest.py) retains identity, release URL and user - installation policy checks. Komac supplies the schema-required `InstallerSha256`; + installation policy checks and validates each file against Microsoft's JSON + schema for its declared `ManifestVersion`. Komac supplies the schema-required `InstallerSha256`; no extra comparison with GitHub asset digests is performed. Before submission, `komac sync-fork` updates the organization fork using the same PAT and `KOMAC_FORK_OWNER` as the final submit. Fork synchronization changes GitHub; diff --git a/build_scripts/tests/test_winget_manifest.py b/build_scripts/tests/test_winget_manifest.py index 5e758e89c..c3d53738b 100644 --- a/build_scripts/tests/test_winget_manifest.py +++ b/build_scripts/tests/test_winget_manifest.py @@ -6,7 +6,6 @@ INSTALL_DIRECTORY, INSTALLER_NAMES, PACKAGE_ID, - SCHEMA_VERSION, fix_installer, validate_manifests, ) @@ -29,7 +28,7 @@ def setUp(self): base = { "PackageIdentifier": PACKAGE_ID, "PackageVersion": "26.9.3", - "ManifestVersion": SCHEMA_VERSION, + "ManifestVersion": "1.12.0", } self.generated = base | { "ManifestType": "installer", @@ -139,7 +138,6 @@ def test_rejects_mixed_package_version_and_locale(self): for index, field, value in ( (1, "PackageVersion", "26.9.2"), (0, "PackageIdentifier", "Other.Package"), - (0, "ManifestVersion", "1.10.0"), (2, "DefaultLocale", "zh-CN"), ): with self.subTest(field=field): @@ -153,6 +151,12 @@ def test_rejects_non_release(self): with self.subTest(field=field), self.assertRaises(ValueError): validate_manifests(self.manifests, self.release | {field: True}) + def test_release_policy_does_not_pin_manifest_schema_versions(self): + manifests = deepcopy(self.manifests) + for manifest, version in zip(manifests, ("1.10.0", "1.12.0", "1.28.0")): + manifest["ManifestVersion"] = version + validate_manifests(manifests, self.release) + if __name__ == "__main__": unittest.main() diff --git a/build_scripts/winget_manifest.py b/build_scripts/winget_manifest.py index 0448b9421..2df4b0f1e 100644 --- a/build_scripts/winget_manifest.py +++ b/build_scripts/winget_manifest.py @@ -10,6 +10,7 @@ from copy import deepcopy from pathlib import Path from typing import ClassVar +from urllib.parse import quote from urllib.request import urlopen PACKAGE_ID = "YuanDevLLC.OneXray" @@ -19,7 +20,6 @@ "x64": "OneXray-windows-amd64.exe", "arm64": "OneXray-windows-arm64.exe", } -SCHEMA_VERSION = "1.12.0" def fix_installer(manifest): @@ -56,8 +56,6 @@ def validate_manifests(manifests, release): for item in manifests: if item.get("PackageIdentifier") != PACKAGE_ID or item.get("PackageVersion") != version: raise ValueError("Manifest package/version does not match the release") - if item.get("ManifestVersion") != SCHEMA_VERSION: - raise ValueError(f"Expected manifest schema {SCHEMA_VERSION}") by_type = {item["ManifestType"]: item for item in manifests} if by_type["version"]["DefaultLocale"] != by_type["defaultLocale"]["PackageLocale"]: raise ValueError("DefaultLocale does not match the default locale manifest") @@ -129,6 +127,7 @@ def validate_directory(directory, release): validate_manifests(manifests, release) for path, manifest in zip(paths, manifests): kind = manifest["ManifestType"] + schema_version = quote(manifest["ManifestVersion"], safe="") suffix = { "installer": ".installer", "version": "", @@ -139,7 +138,7 @@ def validate_directory(directory, release): raise ValueError(f"Unexpected manifest filename: {path.name}") url = ( "https://raw.githubusercontent.com/microsoft/winget-cli/master/schemas/JSON/manifests/" - f"v{SCHEMA_VERSION}/manifest.{kind}.{SCHEMA_VERSION}.json" + f"v{schema_version}/manifest.{kind}.{schema_version}.json" ) with urlopen(url, timeout=30) as response: schema = json.load(response)