diff options
Diffstat (limited to 'release/sign-launcher.py')
-rwxr-xr-x | release/sign-launcher.py | 178 |
1 files changed, 104 insertions, 74 deletions
diff --git a/release/sign-launcher.py b/release/sign-launcher.py index ffe23cc5..86566122 100755 --- a/release/sign-launcher.py +++ b/release/sign-launcher.py | |||
@@ -28,43 +28,56 @@ import util | |||
28 | 28 | ||
29 | 29 | ||
30 | def sign(opts): | 30 | def sign(opts): |
31 | """Sign the launcher!""" | 31 | """Sign the launcher!""" |
32 | output = '' | 32 | output = "" |
33 | for key in opts.keys: | 33 | for key in opts.keys: |
34 | # We use ! at the end of the key so that gpg uses this specific key. | 34 | # We use ! at the end of the key so that gpg uses this specific key. |
35 | # Otherwise it uses the key as a lookup into the overall key and uses the | 35 | # Otherwise it uses the key as a lookup into the overall key and uses |
36 | # default signing key. i.e. It will see that KEYID_RSA is a subkey of | 36 | # the default signing key. i.e. It will see that KEYID_RSA is a subkey |
37 | # another key, and use the primary key to sign instead of the subkey. | 37 | # of another key, and use the primary key to sign instead of the subkey. |
38 | cmd = ['gpg', '--homedir', opts.gpgdir, '-u', f'{key}!', '--batch', '--yes', | 38 | cmd = [ |
39 | '--armor', '--detach-sign', '--output', '-', opts.launcher] | 39 | "gpg", |
40 | ret = util.run(opts, cmd, encoding='utf-8', stdout=subprocess.PIPE) | 40 | "--homedir", |
41 | output += ret.stdout | 41 | opts.gpgdir, |
42 | 42 | "-u", | |
43 | # Save the combined signatures into one file. | 43 | f"{key}!", |
44 | with open(f'{opts.launcher}.asc', 'w', encoding='utf-8') as fp: | 44 | "--batch", |
45 | fp.write(output) | 45 | "--yes", |
46 | "--armor", | ||
47 | "--detach-sign", | ||
48 | "--output", | ||
49 | "-", | ||
50 | opts.launcher, | ||
51 | ] | ||
52 | ret = util.run(opts, cmd, encoding="utf-8", stdout=subprocess.PIPE) | ||
53 | output += ret.stdout | ||
54 | |||
55 | # Save the combined signatures into one file. | ||
56 | with open(f"{opts.launcher}.asc", "w", encoding="utf-8") as fp: | ||
57 | fp.write(output) | ||
46 | 58 | ||
47 | 59 | ||
48 | def check(opts): | 60 | def check(opts): |
49 | """Check the signature.""" | 61 | """Check the signature.""" |
50 | util.run(opts, ['gpg', '--verify', f'{opts.launcher}.asc']) | 62 | util.run(opts, ["gpg", "--verify", f"{opts.launcher}.asc"]) |
51 | 63 | ||
52 | 64 | ||
53 | def get_version(opts): | 65 | def get_version(opts): |
54 | """Get the version from |launcher|.""" | 66 | """Get the version from |launcher|.""" |
55 | # Make sure we don't search $PATH when signing the "repo" file in the cwd. | 67 | # Make sure we don't search $PATH when signing the "repo" file in the cwd. |
56 | launcher = os.path.join('.', opts.launcher) | 68 | launcher = os.path.join(".", opts.launcher) |
57 | cmd = [launcher, '--version'] | 69 | cmd = [launcher, "--version"] |
58 | ret = util.run(opts, cmd, encoding='utf-8', stdout=subprocess.PIPE) | 70 | ret = util.run(opts, cmd, encoding="utf-8", stdout=subprocess.PIPE) |
59 | m = re.search(r'repo launcher version ([0-9.]+)', ret.stdout) | 71 | m = re.search(r"repo launcher version ([0-9.]+)", ret.stdout) |
60 | if not m: | 72 | if not m: |
61 | sys.exit(f'{opts.launcher}: unable to detect repo version') | 73 | sys.exit(f"{opts.launcher}: unable to detect repo version") |
62 | return m.group(1) | 74 | return m.group(1) |
63 | 75 | ||
64 | 76 | ||
65 | def postmsg(opts, version): | 77 | def postmsg(opts, version): |
66 | """Helpful info to show at the end for release manager.""" | 78 | """Helpful info to show at the end for release manager.""" |
67 | print(f""" | 79 | print( |
80 | f""" | ||
68 | Repo launcher bucket: | 81 | Repo launcher bucket: |
69 | gs://git-repo-downloads/ | 82 | gs://git-repo-downloads/ |
70 | 83 | ||
@@ -81,55 +94,72 @@ NB: If a rollback is necessary, the GS bucket archives old versions, and may be | |||
81 | gsutil ls -la gs://git-repo-downloads/repo gs://git-repo-downloads/repo.asc | 94 | gsutil ls -la gs://git-repo-downloads/repo gs://git-repo-downloads/repo.asc |
82 | gsutil cp -a public-read gs://git-repo-downloads/repo#<unique id> gs://git-repo-downloads/repo | 95 | gsutil cp -a public-read gs://git-repo-downloads/repo#<unique id> gs://git-repo-downloads/repo |
83 | gsutil cp -a public-read gs://git-repo-downloads/repo.asc#<unique id> gs://git-repo-downloads/repo.asc | 96 | gsutil cp -a public-read gs://git-repo-downloads/repo.asc#<unique id> gs://git-repo-downloads/repo.asc |
84 | """) | 97 | """ # noqa: E501 |
98 | ) | ||
85 | 99 | ||
86 | 100 | ||
87 | def get_parser(): | 101 | def get_parser(): |
88 | """Get a CLI parser.""" | 102 | """Get a CLI parser.""" |
89 | parser = argparse.ArgumentParser(description=__doc__) | 103 | parser = argparse.ArgumentParser(description=__doc__) |
90 | parser.add_argument('-n', '--dry-run', | 104 | parser.add_argument( |
91 | dest='dryrun', action='store_true', | 105 | "-n", |
92 | help='show everything that would be done') | 106 | "--dry-run", |
93 | parser.add_argument('--gpgdir', | 107 | dest="dryrun", |
94 | default=os.path.join(util.HOMEDIR, '.gnupg', 'repo'), | 108 | action="store_true", |
95 | help='path to dedicated gpg dir with release keys ' | 109 | help="show everything that would be done", |
96 | '(default: ~/.gnupg/repo/)') | 110 | ) |
97 | parser.add_argument('--keyid', dest='keys', default=[], action='append', | 111 | parser.add_argument( |
98 | help='alternative signing keys to use') | 112 | "--gpgdir", |
99 | parser.add_argument('launcher', | 113 | default=os.path.join(util.HOMEDIR, ".gnupg", "repo"), |
100 | default=os.path.join(util.TOPDIR, 'repo'), nargs='?', | 114 | help="path to dedicated gpg dir with release keys " |
101 | help='the launcher script to sign') | 115 | "(default: ~/.gnupg/repo/)", |
102 | return parser | 116 | ) |
117 | parser.add_argument( | ||
118 | "--keyid", | ||
119 | dest="keys", | ||
120 | default=[], | ||
121 | action="append", | ||
122 | help="alternative signing keys to use", | ||
123 | ) | ||
124 | parser.add_argument( | ||
125 | "launcher", | ||
126 | default=os.path.join(util.TOPDIR, "repo"), | ||
127 | nargs="?", | ||
128 | help="the launcher script to sign", | ||
129 | ) | ||
130 | return parser | ||
103 | 131 | ||
104 | 132 | ||
105 | def main(argv): | 133 | def main(argv): |
106 | """The main func!""" | 134 | """The main func!""" |
107 | parser = get_parser() | 135 | parser = get_parser() |
108 | opts = parser.parse_args(argv) | 136 | opts = parser.parse_args(argv) |
109 | 137 | ||
110 | if not os.path.exists(opts.gpgdir): | 138 | if not os.path.exists(opts.gpgdir): |
111 | parser.error(f'--gpgdir does not exist: {opts.gpgdir}') | 139 | parser.error(f"--gpgdir does not exist: {opts.gpgdir}") |
112 | if not os.path.exists(opts.launcher): | 140 | if not os.path.exists(opts.launcher): |
113 | parser.error(f'launcher does not exist: {opts.launcher}') | 141 | parser.error(f"launcher does not exist: {opts.launcher}") |
114 | 142 | ||
115 | opts.launcher = os.path.relpath(opts.launcher) | 143 | opts.launcher = os.path.relpath(opts.launcher) |
116 | print(f'Signing "{opts.launcher}" launcher script and saving to ' | 144 | print( |
117 | f'"{opts.launcher}.asc"') | 145 | f'Signing "{opts.launcher}" launcher script and saving to ' |
118 | 146 | f'"{opts.launcher}.asc"' | |
119 | if opts.keys: | 147 | ) |
120 | print(f'Using custom keys to sign: {" ".join(opts.keys)}') | 148 | |
121 | else: | 149 | if opts.keys: |
122 | print('Using official Repo release keys to sign') | 150 | print(f'Using custom keys to sign: {" ".join(opts.keys)}') |
123 | opts.keys = [util.KEYID_DSA, util.KEYID_RSA, util.KEYID_ECC] | 151 | else: |
124 | util.import_release_key(opts) | 152 | print("Using official Repo release keys to sign") |
125 | 153 | opts.keys = [util.KEYID_DSA, util.KEYID_RSA, util.KEYID_ECC] | |
126 | version = get_version(opts) | 154 | util.import_release_key(opts) |
127 | sign(opts) | 155 | |
128 | check(opts) | 156 | version = get_version(opts) |
129 | postmsg(opts, version) | 157 | sign(opts) |
130 | 158 | check(opts) | |
131 | return 0 | 159 | postmsg(opts, version) |
132 | 160 | ||
133 | 161 | return 0 | |
134 | if __name__ == '__main__': | 162 | |
135 | sys.exit(main(sys.argv[1:])) | 163 | |
164 | if __name__ == "__main__": | ||
165 | sys.exit(main(sys.argv[1:])) | ||