Files: f39871e9cde93edf0f5d30c48833086d1891bdc4 / verify-merge.py
5694 bytesRaw
1 | #!/usr/bin/env python3 |
2 | import argparse |
3 | import os |
4 | import subprocess |
5 | import glob |
6 | import sys |
7 | |
8 | GIT = os.getenv('GIT','git') |
9 | GPG = os.getenv('GPG','gpg') |
10 | |
11 | def verify(): |
12 | global args, workdir |
13 | if args.import_keys: |
14 | os.chdir('gitian-pubkeys') |
15 | print('Importing gpg pubkeys...') |
16 | keys = [f for f in glob.glob('*.asc', recursive=False)] |
17 | for key in keys: |
18 | subprocess.check_call([GPG, '--import', key]) |
19 | os.chdir('../') |
20 | if args.refresh_keys: |
21 | print('Refreshing pubkeys...') |
22 | subprocess.check_call([GPG, '--refresh']) |
23 | print('Verifying signatures:') |
24 | is_verification_error = False |
25 | ver_pattern = args.version if args.version else 'v0*' |
26 | for sig_file in sorted(glob.glob(ver_pattern + '-*/*/*.sig', recursive=False)): |
27 | print(' - ' + '{message: <{fill}}'.format(message=sig_file, fill='72'), end='') |
28 | result = subprocess.run([GPG, '--verify', sig_file], capture_output=True, encoding='utf-8') |
29 | if result.returncode != 0: |
30 | is_verification_error = True |
31 | print('\n') |
32 | sys.stderr.write('ERROR:\n' + result.stderr + '-' * 80 + '\n') |
33 | else: |
34 | print(' [OK]') |
35 | if is_verification_error: |
36 | sys.stderr.write('ERROR: One or more signatures failed verification.\n') |
37 | exit(1) |
38 | |
39 | print('All signatures verified correctly.\n') |
40 | print('Beginning checksum comparison...\n') |
41 | # Check that the contents between the assertion signers match. |
42 | # This is meant for quick verification, not for validation of their contents. |
43 | # TODO: prevent false positives related to filenames / whitespace / formatting. |
44 | builds = glob.glob(ver_pattern + '*') |
45 | for build in builds: |
46 | first_file = glob.glob(build + '/*/*.assert', recursive=False)[0] |
47 | f = open(first_file, 'r') |
48 | first_file_contents = f.readlines() |
49 | f.close() |
50 | for assert_file in glob.glob(build + '/*/*.assert', recursive=False): |
51 | f = open(assert_file, 'r') |
52 | assert_file_contents = f.readlines() |
53 | f.close() |
54 | for i in range(len(assert_file_contents)): |
55 | # Compare each line in the assertion file until base_manifests: |
56 | if assert_file_contents[i] == '- base_manifests: !!omap\n': |
57 | break |
58 | # The OSX SDK may change from time to time: |
59 | if 'sdk' in assert_file_contents[i]: |
60 | continue |
61 | if assert_file_contents[i] != first_file_contents[i]: |
62 | sys.stderr.write('ERROR: Found conflicting contents on line:', i) |
63 | sys.stderr.write(assert_file + ':\n' + assert_file_contents[i]) |
64 | sys.stderr.write(first_file + ':\n' + first_file_contents[i]) |
65 | exit(1) |
66 | |
67 | print('No discrepancies found in assertion files.') |
68 | print('All checks passed.') |
69 | os.chdir(workdir) |
70 | |
71 | def main(): |
72 | host_repo = 'git@github.com/monero-project/gitian.sigs' |
73 | global args, workdir |
74 | parser = argparse.ArgumentParser(usage='%(prog)s [options]', description='Use this script to verify the signatures of existing gitian assert files and / or assert files in a specific pull request.') |
75 | parser.add_argument('-p', '--pull_id', dest='pull_id', help='GitHub Pull request id to check') |
76 | parser.add_argument('-r', '--remote', dest='remote', default='upstream', help='The git remote repository') |
77 | parser.add_argument('-t', '--target-branch', dest='target_branch', default='master', help='Remote repository merge into branch') |
78 | parser.add_argument('-m', '--merge', action='store_true', dest='merge', help='Merge the given pull request id') |
79 | parser.add_argument('-k', '--refresh-keys', action='store_true', dest='refresh_keys', help='Refresh all public keys that are currently in the gpg keyring.') |
80 | parser.add_argument('-i', '--import-keys', action='store_true', dest='import_keys', help='Import all public keys in the gitian-pubkeys directory to the gpg keyring.') |
81 | parser.add_argument('-o', '--no-verify', action='store_true', dest='no_verify', help='Do not run any signature verification') |
82 | parser.add_argument('-v', '--version', dest='version', help='Version number of sigs to be verified (defaults to all versions if not specified).') |
83 | |
84 | args = parser.parse_args() |
85 | |
86 | workdir = os.getcwd() |
87 | if args.pull_id != None: |
88 | # Get branch from remote pull request and compare |
89 | head_branch = args.pull_id + '_head' |
90 | subprocess.check_call([GIT, 'fetch', args.remote]) |
91 | subprocess.check_call([GIT, 'checkout', args.remote + '/' + args.target_branch]) |
92 | subprocess.check_call([GIT, 'fetch', '-q', args.remote, 'pull/' + args.pull_id + '/head:' + head_branch]) |
93 | subprocess.check_call([GIT, 'checkout', '-f', head_branch]) |
94 | if args.merge: |
95 | # Hard reset the target branch to the remote's state and merge the pull request's head branch into it |
96 | subprocess.check_call([GIT, 'checkout', args.target_branch]) |
97 | subprocess.check_call([GIT, 'reset', '--hard', args.remote + '/' + args.target_branch]) |
98 | print('Merging and signing pull request #' + args.pull_id + ' , if you are using a smartcard, confirm the signature now.') |
99 | subprocess.check_call([GIT, 'merge', '-q', '--commit', '--no-edit', '-m', 'Merge pull request #' + args.pull_id + ' into ' + args.target_branch, '--no-ff', '--gpg-sign', head_branch]) |
100 | if not args.no_verify: |
101 | verify() |
102 | subprocess.check_call([GIT, 'checkout', 'master']) |
103 | subprocess.check_call([GIT, 'branch', '-D', head_branch]) |
104 | else: |
105 | verify() |
106 | |
107 | |
108 | if __name__ == '__main__': |
109 | main() |
110 |
Built with git-ssb-web