Files
upstream-activitywatch/scripts/package/configure_tauri_release.py
upstream-mirror c5c5af8cde
Some checks failed
Research feed publisher tests / test (push) Failing after 3s
Release / Pre-flight checks (push) Failing after 0s
Release / Research Edition — patch and packaging smoke tests (push) Has been skipped
Release / Build Qt artifacts (false, 22, ubuntu-22.04, 3.9, ${{ github.event_name == 'pull_request' || (github.event_name == 'push' && !startsWith(github.ref, 'refs/tags/')) }}, false, false) (push) Has been skipped
Release / Build Qt artifacts (false, 22, ubuntu-22.04, 3.9, false, false, false) (push) Has been skipped
Release / Build Qt artifacts (manylinux_2_28 — glibc 2.28 ABI floor) (22, 3.9) (push) Has been skipped
Release / Generate release notes (push) Has been skipped
Release / Create dev release tag (push) Has been skipped
CodeQL / Analyze (javascript) (push) Failing after 1s
CodeQL / Analyze (python) (push) Failing after 1s
Release / Build Qt artifacts (false, 22, windows-latest, 3.9, false, false, false) (push) Has been cancelled
Release / Build Tauri artifacts (false, 22, macos-15-intel, 3.9, false, false, false) (push) Has been cancelled
Release / Build Tauri artifacts (false, 22, macos-latest, 3.9, false, false, false) (push) Has been cancelled
Release / Build Tauri artifacts (false, 22, ubuntu-24.04, 3.9, ${{ github.event_name == 'pull_request' || (github.event_name == 'push' && !startsWith(github.ref, 'refs/tags/')) }}, false, false) (push) Has been cancelled
Release / Build Tauri artifacts (false, 22, ubuntu-24.04, 3.9, false, false, false) (push) Has been cancelled
Release / Build Tauri artifacts (false, 22, ubuntu-24.04-arm, 3.9, false, false, false) (push) Has been cancelled
Release / Build Tauri artifacts (false, 22, windows-latest, 3.9, false, false, false) (push) Has been cancelled
Release / Build Qt artifacts (false, 22, macos-15-intel, 3.9, false, false, false) (push) Has been cancelled
Release / Build Qt artifacts (false, 22, macos-latest, 3.9, false, false, false) (push) Has been cancelled
Release / Publish draft release (push) Has been cancelled
snapshot of https://github.com/ActivityWatch/activitywatch.git (master, 2026-09-15; blobs > 131072B omitted)
2026-09-15 22:29:06 +05:00

109 lines
4.1 KiB
Python

#!/usr/bin/env python3
"""Set the compiled updater version and isolate Research Edition update trust."""
import argparse
import base64
import binascii
import json
import os
import sys
from pathlib import Path
from generate_latest_json import tauri_version
RESEARCH_ENDPOINT = (
"https://raw.githubusercontent.com/ActivityWatch/activitywatch/"
"research-updates/latest-research.json"
)
STANDARD_ENDPOINT = "https://github.com/ActivityWatch/activitywatch/releases/latest/download/latest.json"
def msi_rejects(version: str) -> bool:
"""True if Tauri's msi (WiX) bundler will reject this SemVer version.
The msi target requires the optional pre-release identifier to be
numeric-only (e.g. "0.14.0-5"), unlike nsis or the other bundle formats.
AW's own pre-release scheme ("0.14.0-beta.5", "0.14.0-dev.gabc1234")
fails that check every time.
"""
if "-" not in version:
return False
prerelease = version.split("-", 1)[1]
return not all(part.isdigit() for part in prerelease.split("."))
def public_key(encoded: str) -> bytes:
"""Read Tauri's base64-wrapped minisign public key, ignoring its comment."""
try:
lines = base64.b64decode(encoded, validate=True).decode("ascii").splitlines()
if len(lines) != 2 or not lines[0].startswith("untrusted comment: "):
raise ValueError("invalid public key envelope")
packet = base64.b64decode(lines[1], validate=True)
if len(packet) != 42 or packet[:2] != b"Ed":
raise ValueError("invalid public key packet")
return packet[10:]
except (ValueError, UnicodeError, binascii.Error) as exc:
raise ValueError("Expected a base64-encoded minisign public key") from exc
def configure(
path: Path,
version: str,
research: bool,
require_signing_key: bool,
*,
platform: str = sys.platform,
) -> None:
config = json.loads(path.read_text(encoding="utf-8"))
tv = tauri_version(version)
config["version"] = tv
if platform == "win32" and msi_rejects(tv):
bundle = config.setdefault("bundle", {})
if bundle.get("targets") == "all":
# Windows only ever produces msi+nsis from "all"; drop msi and
# keep nsis, which accepts the full AW pre-release scheme.
bundle["targets"] = ["nsis"]
if research:
updater = config["plugins"]["updater"]
if updater["endpoints"] != [STANDARD_ENDPOINT]:
raise ValueError(
"Unexpected source updater endpoint; review before patching"
)
research_key = os.environ.get("TAURI_UPDATER_PUBLIC_KEY_RESEARCH", "").strip()
signing_key = os.environ.get("TAURI_SIGNING_PRIVATE_KEY", "").strip()
if require_signing_key and (not research_key or not signing_key):
raise ValueError(
"Research releases require their own public and signing keys"
)
if research_key:
if public_key(research_key) == public_key(updater["pubkey"]):
raise ValueError(
"Research updater key must differ from the standard key"
)
updater["pubkey"] = research_key
updater["endpoints"] = [RESEARCH_ENDPOINT]
else:
if signing_key:
raise ValueError("Research signing key supplied without its public key")
# Secretless PR smoke builds must never retain standard update trust.
updater["pubkey"] = ""
updater["endpoints"] = []
path.write_text(json.dumps(config, indent=2) + "\n", encoding="utf-8")
def main() -> None:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--config", type=Path, required=True)
parser.add_argument("--version", required=True)
parser.add_argument("--research", action="store_true")
parser.add_argument("--require-signing-key", action="store_true")
args = parser.parse_args()
try:
configure(args.config, args.version, args.research, args.require_signing_key)
except (ValueError, KeyError) as exc:
parser.exit(1, f"ERROR: {exc}\n")
if __name__ == "__main__":
main()