Files: b53b89087262d29dec6eb41cf0d562715fd9c5d6 / verify-merge.py
5631 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 pubkeys...') |
16 | keys = [f for f in glob.glob("*.asc", recursive=True)] |
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. This is meant for quick verification, not for validation of their contents |
42 | # TODO: prevent false positives related to filenames / whitespace / formatting. |
43 | builds = glob.glob(ver_pattern + '*') |
44 | for build in builds: |
45 | first_file = glob.glob(build + '/*/*.assert', recursive=False)[0] |
46 | f = open(first_file, "r") |
47 | first_file_contents = f.readlines() |
48 | f.close() |
49 | for assert_file in glob.glob(build + '/*/*.assert', recursive=False): |
50 | f = open(assert_file, "r") |
51 | assert_file_contents = f.readlines() |
52 | f.close() |
53 | for i in range(len(assert_file_contents)): |
54 | # compare everything in the assertions until the base image manifests |
55 | if assert_file_contents[i] == "- base_manifests: !!omap\n": |
56 | break |
57 | # the OSX SDK may change from time to time |
58 | if "sdk" in assert_file_contents[i]: |
59 | continue |
60 | if assert_file_contents[i] != first_file_contents[i]: |
61 | print("ERROR: Found conflicting contents on line:", i) |
62 | print(assert_file, ":\n", assert_file_contents[i]) |
63 | print(first_file, ":\n", first_file_contents[i]) |
64 | exit(1) |
65 | |
66 | print('No discrepancies found in assertion files.') |
67 | print('All checks passed.') |
68 | os.chdir(workdir) |
69 | |
70 | def main(): |
71 | host_repo = "git@github.com/monero-project/gitian.sigs" |
72 | global args, workdir |
73 | 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.') |
74 | parser.add_argument('-p', '--pull_id', dest='pull_id', help='Github Pull request id to check') |
75 | parser.add_argument('-r', '--remote', dest='remote', default='upstream', help='git remote repository') |
76 | parser.add_argument('-t', '--target-branch', dest='target_branch', default='master', help='Remote repository merge into branch') |
77 | parser.add_argument('-m', '--merge', action='store_true', dest='merge', help='Merge the given pull request id') |
78 | parser.add_argument('-k', '--refresh-keys', action='store_true', dest='refresh_keys', help='refresh all pgp public keys that are currently in the gpg keyring.') |
79 | 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.') |
80 | parser.add_argument('-o', '--no-verify', action='store_true', dest='no_verify', help='Do not run any signature verification') |
81 | parser.add_argument('-v', '--version', dest='version', help='Version number of sigs to be verified (defaults to all versions if not specified).') |
82 | |
83 | args = parser.parse_args() |
84 | |
85 | workdir = os.getcwd() |
86 | if args.pull_id != None: |
87 | # Get branch from remote pull request and compare |
88 | head_branch = args.pull_id+'_head' |
89 | |
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