diff --git a/VIBE/CHAT_LOG.md b/VIBE/CHAT_LOG.md index 229a03a..e49f20f 100644 --- a/VIBE/CHAT_LOG.md +++ b/VIBE/CHAT_LOG.md @@ -1490,3 +1490,9 @@ Make sure that when the plugin is signed the version in the link it the about pa ### 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. + +### 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. diff --git a/VIBE/PROMPTS.md b/VIBE/PROMPTS.md index 0128c39..b86dff9 100644 --- a/VIBE/PROMPTS.md +++ b/VIBE/PROMPTS.md @@ -267,6 +267,7 @@ 245. Add sha hashes to the updates.json 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 +248. Release script fails because the runner's hashlib module has no file_digest attribute. ## Future entries diff --git a/scripts/release/generate_updates.py b/scripts/release/generate_updates.py index 33071f9..8d95a7d 100644 --- a/scripts/release/generate_updates.py +++ b/scripts/release/generate_updates.py @@ -38,8 +38,11 @@ def read_packaged_manifest(xpi_path: Path) -> dict: def sha256_digest(xpi_path: Path) -> str: + digest = hashlib.sha256() 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: diff --git a/scripts/release/validate_release.py b/scripts/release/validate_release.py index fcd4ef1..ea1bc7d 100644 --- a/scripts/release/validate_release.py +++ b/scripts/release/validate_release.py @@ -38,6 +38,14 @@ def find_latest_signed_xpi() -> tuple[str, Path]: 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: gecko_settings = source_manifest.get('browser_specific_settings', {}).get('gecko', {}) 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}' ) - with xpi_path.open('rb') as xpi_file: - expected_hash = f'sha256:{hashlib.file_digest(xpi_file, "sha256").hexdigest()}' + expected_hash = f'sha256:{sha256_digest(xpi_path)}' if entry.get('update_hash') != expected_hash: fail( f'{UPDATES_PATH.relative_to(ROOT)} update_hash {entry.get("update_hash")!r} does not match '