summaryrefslogtreecommitdiff
path: root/scripts/release/repo_init.py
blob: c0360c0e5c3b168ba528ada4e798585d09851f0b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
"""
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/<platform>/ — 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 ./<platform>/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-<key>" 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()