1
2
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
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
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
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 = []
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
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