Fix release hash validation on older Python

This commit is contained in:
Olaf
2026-08-28 10:44:12 +02:00
parent 9bf9c94dd6
commit 19cc6dbc1c
4 changed files with 20 additions and 3 deletions
+6
View File
@@ -1490,3 +1490,9 @@ Make sure that when the plugin is signed the version in the link it the about pa
### Assistant outcome ### Assistant outcome
Extended `make update-updates` to set the About page plugin download URL to the newest valid signed XPI. Release validation now also rejects an About page whose link does not match the latest signed artifact; verified with LinkLog 0.2.0. Extended `make update-updates` to set the About page plugin download URL to the newest valid signed XPI. Release validation now also rejects an About page whose link does not match the latest signed artifact; verified with LinkLog 0.2.0.
### User
Release script fails because the runner's hashlib module has no file_digest attribute.
### Assistant outcome
Replaced Python 3.11-only `hashlib.file_digest` calls in signed-XPI metadata generation and release validation with streaming SHA-256 calculations compatible with older Python runners. Regenerated update metadata and verified release validation passes.
+1
View File
@@ -267,6 +267,7 @@
245. Add sha hashes to the updates.json 245. Add sha hashes to the updates.json
246. Update changelog and VIBE 246. Update changelog and VIBE
247. Make sure that when the plugin is signed the version in the link it the about page is updated too 247. Make sure that when the plugin is signed the version in the link it the about page is updated too
248. Release script fails because the runner's hashlib module has no file_digest attribute.
## Future entries ## Future entries
+4 -1
View File
@@ -38,8 +38,11 @@ def read_packaged_manifest(xpi_path: Path) -> dict:
def sha256_digest(xpi_path: Path) -> str: def sha256_digest(xpi_path: Path) -> str:
digest = hashlib.sha256()
with xpi_path.open('rb') as xpi_file: with xpi_path.open('rb') as xpi_file:
return hashlib.file_digest(xpi_file, 'sha256').hexdigest() for block in iter(lambda: xpi_file.read(1024 * 1024), b''):
digest.update(block)
return digest.hexdigest()
def update_about_plugin_link(xpi_path: Path) -> None: def update_about_plugin_link(xpi_path: Path) -> None:
+9 -2
View File
@@ -38,6 +38,14 @@ def find_latest_signed_xpi() -> tuple[str, Path]:
return max(candidates, key=lambda candidate: version_key(candidate[0])) return max(candidates, key=lambda candidate: version_key(candidate[0]))
def sha256_digest(xpi_path: Path) -> str:
digest = hashlib.sha256()
with xpi_path.open('rb') as xpi_file:
for block in iter(lambda: xpi_file.read(1024 * 1024), b''):
digest.update(block)
return digest.hexdigest()
def validate_self_update(source_manifest: dict, extension_version: str, xpi_path: Path) -> None: def validate_self_update(source_manifest: dict, extension_version: str, xpi_path: Path) -> None:
gecko_settings = source_manifest.get('browser_specific_settings', {}).get('gecko', {}) gecko_settings = source_manifest.get('browser_specific_settings', {}).get('gecko', {})
addon_id = gecko_settings.get('id') addon_id = gecko_settings.get('id')
@@ -64,8 +72,7 @@ def validate_self_update(source_manifest: dict, extension_version: str, xpi_path
f'the expected raw signed XPI URL {expected_link!r}' f'the expected raw signed XPI URL {expected_link!r}'
) )
with xpi_path.open('rb') as xpi_file: expected_hash = f'sha256:{sha256_digest(xpi_path)}'
expected_hash = f'sha256:{hashlib.file_digest(xpi_file, "sha256").hexdigest()}'
if entry.get('update_hash') != expected_hash: if entry.get('update_hash') != expected_hash:
fail( fail(
f'{UPDATES_PATH.relative_to(ROOT)} update_hash {entry.get("update_hash")!r} does not match ' f'{UPDATES_PATH.relative_to(ROOT)} update_hash {entry.get("update_hash")!r} does not match '