Package backend :: Module sign
[hide private]
[frames] | no frames]

Source Code for Module backend.sign

  1  #!/usr/bin/env python 
  2  # coding: utf-8 
  3   
  4  """ 
  5  Wrapper for /bin/sign from obs-sign package 
  6  """ 
  7   
  8  from subprocess import Popen, PIPE 
  9  import json 
 10   
 11  import os 
 12  from requests import request 
 13   
 14  from .exceptions import CoprSignError, CoprSignNoKeyError, \ 
 15      CoprKeygenRequestError, \ 
 16      MockRemoteError 
 17   
 18   
 19  SIGN_BINARY = "/bin/sign" 
 20  DOMAIN = "fedorahosted.org" 
 21   
 22   
23 -def create_gpg_email(username, projectname):
24 """ 25 Creates canonical name_email to identify gpg key 26 """ 27 28 return "{}#{}@copr.{}".format(username, projectname, DOMAIN)
29 30
31 -def get_pubkey(username, projectname, outfile=None):
32 """ 33 Retrieves public key for user/project from signer host. 34 35 :param outfile: [optional] file to write obtained key 36 :return: public keys 37 38 :raises CoprSignError: failed to retrieve key, see error message 39 :raises CoprSignNoKeyError: if there are no such user in keyring 40 """ 41 usermail = create_gpg_email(username, projectname) 42 cmd = ["sudo", SIGN_BINARY, "-u", usermail, "-p"] 43 44 try: 45 handle = Popen(cmd, stdout=PIPE, stderr=PIPE) 46 stdout, stderr = handle.communicate() 47 except Exception as e: 48 raise CoprSignError("Failed to get user pubkey" 49 " due to: {}".format(e)) 50 51 if handle.returncode != 0: 52 if "unknown key:" in stderr: 53 raise CoprSignNoKeyError( 54 "There are no gpg keys for user {} in keyring".format(username), 55 return_code=handle.returncode, 56 cmd=cmd, stdout=stdout, stderr=stderr) 57 raise CoprSignError( 58 msg="Failed to get user pubkey\n" 59 "sign stdout: {}\n sign stderr: {}\n".format(stdout, stderr), 60 return_code=handle.returncode, 61 cmd=cmd, stdout=stdout, stderr=stderr) 62 63 if outfile: 64 with open(outfile, "w") as handle: 65 handle.write(stdout) 66 67 return stdout
68 69
70 -def _sign_one(path, email, callback=None):
71 cmd = ["sudo", SIGN_BINARY, "-u", email, "-r", path] 72 73 try: 74 handle = Popen(cmd, stdout=PIPE, stderr=PIPE) 75 stdout, stderr = handle.communicate() 76 except Exception as e: 77 err = CoprSignError( 78 msg="Failed to invoke sign {} by user {} with error {}" 79 .format(path, email, e, cmd=None, stdout=None, stderr=None)) 80 81 if callback: 82 callback.error(err) 83 raise err 84 85 if handle.returncode != 0: 86 err = CoprSignError( 87 msg="Failed to sign {} by user {}".format(path, email), 88 return_code=handle.returncode, 89 cmd=cmd, stdout=stdout, stderr=stderr) 90 91 if callback: 92 callback.error(err) 93 raise err 94 95 return stdout, stderr
96 97
98 -def sign_rpms_in_dir(username, projectname, path, opts, callback=None):
99 """ 100 Signs rpms using obs-signd. 101 102 If some some pkgs failed to sign, entire build marked as failed, 103 but we continue to try sign other pkgs. 104 105 106 107 :param username: copr username 108 :param projectname: copr projectname 109 :param path: directory with rpms to be signed 110 :param Bunch opts: backend config 111 112 :param callback: :py:class:`backend.mockremote.DefaultCallBack` object to log progress, 113 two methods are utilised: ``log`` and ``error`` 114 115 :raises: :py:class:`backend.exceptions.CoprSignError` failed to sign at least one package 116 """ 117 rpm_list = [ 118 os.path.join(path, filename) 119 for filename in os.listdir(path) 120 if filename.endswith(".rpm") 121 ] 122 123 if not rpm_list: 124 return 125 126 try: 127 get_pubkey(username, projectname) 128 except CoprSignNoKeyError: 129 create_user_keys(username, projectname, opts) 130 131 errors = [] # tuples (rpm_filepath, exception) 132 for rpm in rpm_list: 133 try: 134 _sign_one(rpm, 135 create_gpg_email(username, projectname), 136 callback) 137 138 if callback: 139 callback.log("signed rpm: {}".format(rpm)) 140 141 except CoprSignError as e: 142 errors.append((rpm, e)) 143 144 if errors: 145 raise CoprSignError("Rpm sign failed, affected rpms: {}" 146 .format([err[0] for err in errors]))
147 148
149 -def create_user_keys(username, projectname, opts):
150 """ 151 Generate a new key-pair at sign host 152 153 :param username: 154 :param projectname: 155 :param opts: backend config 156 157 :return: None 158 """ 159 data = json.dumps({ 160 "name_real": "{}_{}".format(username, projectname), 161 "name_email": create_gpg_email(username, projectname) 162 }) 163 164 keygen_url = "http://{}/gen_key".format(opts.keygen_host) 165 query = dict(url=keygen_url, data=data, method="post") 166 try: 167 response = request(**query) 168 except Exception as e: 169 raise CoprKeygenRequestError( 170 msg="Failed to create key-pair for user: {}," 171 " project:{} with error: {}" 172 .format(username, projectname, e), request=query) 173 174 if response.status_code >= 400: 175 raise CoprKeygenRequestError( 176 msg="Failed to create key-pair for user: {}, project:{}" 177 .format(username, projectname), 178 request=query, response=response)
179