""" scripts/release/repo_init.py Run ONCE PER PLATFORM, by the maintainer, locally, on a machine running that platform (no cross-compiling — build and sign Windows releases on Windows, Linux releases on Linux/WSL2, etc.). Generates that platform's TUF signing keys and initial repository metadata (including root.json, which later gets bundled into that platform's build via labui.spec). Every platform gets its own keystore/repository tree, under scripts/release// — Windows and Linux builds of the same version are different byte-for-byte archives, and TUF's metadata filenames (root.json, timestamp.json, ...) aren't platform-prefixed, so they can't share one repo/release without one platform silently overwriting the other's trust root and metadata. Running this again after a platform's repo already exists is safe (tufup skips re-creating keys/roles that already exist) but there is normally no reason to run it more than once per platform. Keys land in .//keystore — never commit that directory (already gitignored). Back it up somewhere safe and private, once per platform; losing a platform's root key means you can never publish another trusted update to that platform's existing installs. """ import os import sys from pathlib import Path from tufup.repo import Repository, RolesDict def _platform_key() -> str: """win / mac / linux — must match core.updater._platform_key() and the "updates-" release tag on the publishing side.""" if sys.platform.startswith("win"): return "win" if sys.platform == "darwin": return "mac" return "linux" PLATFORM = _platform_key() # Run from this script's own platform subdirectory — tufup's config file # (.tufup-repo-config) and all repo_dir/keys_dir paths are resolved relative # to the current working directory, so invocation location must be # consistent every time. _PLATFORM_DIR = Path(__file__).resolve().parent / PLATFORM _PLATFORM_DIR.mkdir(parents=True, exist_ok=True) os.chdir(_PLATFORM_DIR) APP_NAME = "labui" # tufup-example's 1-day timestamp / 7-day snapshot defaults assume an # automated CI worker re-signs on a schedule. We're signing manually # (see README.md in this directory), so use longer, human-manageable # expirations instead. Whichever of these lapses first is the cadence # you need to re-sign at, even between actual app releases. EXPIRATION_DAYS = RolesDict(root=365, targets=90, snapshot=90, timestamp=90) def main(): # Not using app_version_attr here: tufup's setuptools-based attribute # reader resolves dotted paths relative to the current working directory, # which we deliberately pin to this script's own directory below (tufup's # own config-file/relative-path handling expects that) — the two # assumptions conflict. repo_release.py passes the version explicitly # instead, which sidesteps this entirely. repo = Repository( app_name=APP_NAME, repo_dir=Path("repository"), keys_dir=Path("keystore"), expiration_days=EXPIRATION_DAYS, ) repo.initialize() repo.save_config() print(f"Initialized tufup repo for '{APP_NAME}' ({PLATFORM}) in " f"{_PLATFORM_DIR / 'repository'}, keys in {_PLATFORM_DIR / 'keystore'}") print(f"Back up {_PLATFORM_DIR / 'keystore'} now, somewhere private and " f"durable. It is gitignored on purpose.") if __name__ == "__main__": main()