From 29d5077e512d834eb96dc78292abbd6712e229f2 Mon Sep 17 00:00:00 2001 From: vringar Date: Thu, 26 Mar 2026 17:58:30 +0000 Subject: [PATCH 1/7] release: update to Firefox 149, rewrite update scripts, fix service worker test - Bump Firefox tag to FIREFOX_149_0_RELEASE in install-firefox.sh - Extract firefox_version.py: standalone module + CLI for detecting and updating the Firefox release tag from hg.mozilla.org - Rewrite update.sh as update.py using firefox_version.py - Fix test_service_worker_requests flakiness for Firefox 149: - Rewrite service_worker.js to fetch during activate (skipWaiting + event.waitUntil) instead of on message, eliminating the statechange race condition - Simplify http_service_worker_page.html accordingly - Add sleep_after=5 to visit() call to ensure flush before browser close --- CHANGELOG.md | 4 + scripts/firefox_version.py | 115 ++++++++++++++++++ scripts/install-firefox.sh | 2 +- scripts/update.py | 58 +++++++++ scripts/update.sh | 18 --- test/test_http_instrumentation.py | 2 +- test/test_pages/http_service_worker_page.html | 20 +-- test/test_pages/shared/service_worker.js | 13 +- 8 files changed, 191 insertions(+), 41 deletions(-) create mode 100755 scripts/firefox_version.py create mode 100755 scripts/update.py delete mode 100755 scripts/update.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ae8d79f4..68eb49d6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## v0.33.0 - 2026-03-26 + +Bump to Firefox 149 + ## v0.32.0 - 2026-03-01 Bump to Firefox 148 diff --git a/scripts/firefox_version.py b/scripts/firefox_version.py new file mode 100755 index 000000000..2307ceaff --- /dev/null +++ b/scripts/firefox_version.py @@ -0,0 +1,115 @@ +"""Fetch the latest Firefox release tag and optionally update install-firefox.sh. + +Subcommands +----------- +check Print the current and latest Firefox release tags. + Exits 0 if up to date, 1 if an update is available. + +update Update scripts/install-firefox.sh to the latest Firefox release. + No-op (exits 0) if already up to date. + +Run from any directory: + python scripts/firefox_version.py check + python scripts/firefox_version.py update +""" + +import argparse +import json +import re +import sys +import urllib.request +from pathlib import Path + +INSTALL_SCRIPT = Path(__file__).resolve().parent / "install-firefox.sh" +TAGS_URL = "https://hg.mozilla.org/releases/mozilla-release/json-tags" +_TAG_RE = re.compile(r"FIREFOX_\d+_\d+(?:_\d+)?_RELEASE") + + +def _version_key(tag: str) -> tuple[int, int, int]: + m = re.fullmatch(r"FIREFOX_(\d+)_(\d+)(?:_(\d+))?_RELEASE", tag) + if not m: + return (0, 0, 0) + return (int(m.group(1)), int(m.group(2)), int(m.group(3) or 0)) + + +def fetch_latest() -> tuple[str, str]: + """Return (tag_name, commit_hash) for the newest Firefox release on hg.mozilla.org.""" + with urllib.request.urlopen(TAGS_URL, timeout=15) as resp: + data = json.load(resp) + tags = [(t["tag"], t["node"]) for t in data["tags"] if _TAG_RE.fullmatch(t["tag"])] + if not tags: + raise RuntimeError("No Firefox release tags found") + tags.sort(key=lambda t: _version_key(t[0]), reverse=True) + return tags[0] + + +def get_current() -> str: + """Return the tag name currently pinned in install-firefox.sh.""" + text = INSTALL_SCRIPT.read_text() + m = re.search(r"# (FIREFOX_\d+_\d+(?:_\d+)?_RELEASE)", text) + if not m: + raise RuntimeError(f"No Firefox tag comment found in {INSTALL_SCRIPT}") + return m.group(1) + + +def update_if_needed() -> bool: + """Rewrite install-firefox.sh if a newer Firefox is available. + + Returns True if the file was updated, False if already current. + """ + current = get_current() + latest_tag, latest_hash = fetch_latest() + + if latest_tag == current: + print(f"Firefox is already at the latest release ({current}).") + return False + + print(f"Updating Firefox: {current} → {latest_tag}") + text = INSTALL_SCRIPT.read_text() + new_text = re.sub( + r"^TAG='[^']*' # .*$", + f"TAG='{latest_hash}' # {latest_tag}", + text, + flags=re.MULTILINE, + ) + INSTALL_SCRIPT.write_text(new_text) + print(f"Updated {INSTALL_SCRIPT.name} to {latest_tag} ({latest_hash})") + print("Remember to run ./scripts/install-firefox.sh and test before releasing.") + return True + + +def cmd_check() -> int: + current = get_current() + latest_tag, _ = fetch_latest() + print(f"Current : {current}") + print(f"Latest : {latest_tag}") + if latest_tag == current: + print("Up to date.") + return 0 + print("Update available.") + return 1 + + +def cmd_update() -> int: + update_if_needed() + return 0 + + +def main() -> int: + parser = argparse.ArgumentParser( + description="Check or update the Firefox release pinned in install-firefox.sh.", + ) + sub = parser.add_subparsers(dest="command", required=True) + sub.add_parser("check", help="Print current vs latest Firefox tag") + sub.add_parser("update", help="Update install-firefox.sh to latest Firefox") + args = parser.parse_args() + + if args.command == "check": + return cmd_check() + if args.command == "update": + return cmd_update() + return 1 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/scripts/install-firefox.sh b/scripts/install-firefox.sh index 8cdd99e9d..5c8c49c39 100755 --- a/scripts/install-firefox.sh +++ b/scripts/install-firefox.sh @@ -9,7 +9,7 @@ set -e # Note this script is **destructive** and will # remove the existing Firefox in the OpenWPM directory -TAG='eff69d257e44ce2a29f947baf876e992af8bb9b0' # FIREFOX_148_0_RELEASE +TAG='b20f603334b8677ba67ed2fb12a1043b3c8c6933' # FIREFOX_149_0_RELEASE case "$(uname -s)" in Darwin) diff --git a/scripts/update.py b/scripts/update.py new file mode 100755 index 000000000..19af0a3af --- /dev/null +++ b/scripts/update.py @@ -0,0 +1,58 @@ +"""Update all OpenWPM dependencies and check for a newer Firefox release. + +Steps +----- +1. Repin the conda environment (scripts/repin.sh) +2. Update root npm dependencies +3. Update Extension npm dependencies +4. Rebuild the extension +5. Check hg.mozilla.org for a newer Firefox and update install-firefox.sh if found + +Run from the project root: + python scripts/update.py +""" + +import subprocess +import sys +from pathlib import Path + +ROOT = Path(__file__).resolve().parent.parent +SCRIPTS = ROOT / "scripts" + + +def run(*cmd: str, cwd: Path = ROOT) -> None: + print(f"+ {' '.join(cmd)}") + subprocess.run(list(cmd), check=True, cwd=cwd) + + +def conda_run(*cmd: str, cwd: Path = ROOT) -> None: + run("conda", "run", "-n", "openwpm", *cmd, cwd=cwd) + + +def main() -> None: + # Repin the conda environment from unpinned sources + run("./repin.sh", cwd=SCRIPTS) + + # Update npm dependencies (root package.json and Extension/package.json) + conda_run("npm", "update", "--include=dev") + conda_run("npm", "update", "--include=dev", cwd=ROOT / "Extension") + + # Rebuild the extension XPI after dependency changes + run("./build-extension.sh", cwd=SCRIPTS) + + # Check for a newer Firefox release and update install-firefox.sh if available + sys.path.insert(0, str(SCRIPTS)) + import firefox_version + + firefox_version.update_if_needed() + + +if __name__ == "__main__": + try: + main() + except subprocess.CalledProcessError as e: + print(f"Command failed with exit code {e.returncode}: {e.cmd}", file=sys.stderr) + sys.exit(1) + except Exception as e: + print(f"Error: {e}", file=sys.stderr) + sys.exit(1) diff --git a/scripts/update.sh b/scripts/update.sh deleted file mode 100755 index a266e9673..000000000 --- a/scripts/update.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -set -e - -pushd scripts -./repin.sh -popd - -# Make mamba available to shell script -eval "$(conda shell.bash hook)" - -conda activate openwpm - -npm update --include=dev - -pushd Extension -npm update --include=dev -popd diff --git a/test/test_http_instrumentation.py b/test/test_http_instrumentation.py index 26bc67672..29c0ecbe2 100644 --- a/test/test_http_instrumentation.py +++ b/test/test_http_instrumentation.py @@ -661,7 +661,7 @@ def test_worker_script_requests(self): def test_service_worker_requests(self): """Check correct URL attribution for requests made by service worker""" test_url = utilities.BASE_TEST_URL + "/http_service_worker_page.html" - db = self.visit(test_url) + db = self.visit(test_url, sleep_after=5) request_id_to_url = dict() diff --git a/test/test_pages/http_service_worker_page.html b/test/test_pages/http_service_worker_page.html index 5f2f62750..936d911ac 100644 --- a/test/test_pages/http_service_worker_page.html +++ b/test/test_pages/http_service_worker_page.html @@ -4,8 +4,8 @@ -

This test page registers a service worker, then sends a message - to the worker to tell it to make a request. +

This test page registers a service worker that fetches an image + during its activate phase.