Hello,<br><br>Thank you for your Koji callback.<br><br>I perform some modifications:<br>+ to handle DEFAULT section (if section for Tag name is not defined)<br>+ to support empty GPG pass-phrase<br>+ to work on localized OS<br>
+ to log GPG messages if rpm --resign fails <br><br>Note: your GPG directory (gpg_path in .conf file) must be readable and writeable by apache (the user which runs Koji hub)<br><br>Regards,<br>Pierre<br>
<br># Koji callback for GPG signing RPMs before import<br>#<br># Author:<br># Paul B Schroeder <paulbsch "at" vbridges "dot" com><br><br>from koji.plugin import register_callback<br>import logging<br>
<br># Configuration file in /etc like for other plugins<br>CONFIG_FILE = '/etc/koji-hub/plugins/sign.conf'<br><br>def sign(cbtype, *args, **kws):<br> if kws['type'] != 'build':<br> return<br>
<br> # Get the tag name from the buildroot map<br> import sys<br> sys.path.insert(0, '/usr/share/koji-hub')<br> from kojihub import get_buildroot<br> br_id = kws['brmap'].values()[0]<br> br = get_buildroot(br_id)<br>
tag_name = br['tag_name']<br><br> # Get GPG info using the config for the tag name<br> import ConfigParser<br> config = ConfigParser.ConfigParser()<br> config.read(CONFIG_FILE)<br> try:<br> rpm = config.get(tag_name, 'rpm')<br>
except ConfigParser.NoSectionError:<br> rpm = config.get(ConfigParser.DEFAULTSECT, 'rpm')<br> try:<br> gpgbin = config.get(tag_name, 'gpgbin')<br> except ConfigParser.NoSectionError:<br>
gpgbin = config.get(ConfigParser.DEFAULTSECT, 'gpgbin')<br> try:<br> gpg_path = config.get(tag_name, 'gpg_path')<br> except ConfigParser.NoSectionError:<br> gpg_path = config.get(ConfigParser.DEFAULTSECT, 'gpg_path')<br>
try:<br> gpg_name = config.get(tag_name, 'gpg_name')<br> except ConfigParser.NoSectionError:<br> gpg_name = config.get(ConfigParser.DEFAULTSECT, 'gpg_name')<br> try:<br> gpg_pass = config.get(tag_name, 'gpg_pass')<br>
except ConfigParser.NoSectionError:<br> gpg_pass = config.get(ConfigParser.DEFAULTSECT, 'gpg_pass')<br><br> # Get the package paths set up<br> from koji import pathinfo<br> uploadpath = pathinfo.work()<br>
rpms = ''<br> for relpath in [kws['srpm']] + kws['rpms']:<br> rpms += '%s/%s ' % (uploadpath, relpath)<br><br> # Get the packages signed<br> import pexpect<br> import os<br>
os.environ['LC_ALL'] = 'C'<br> logging.getLogger('koji.plugin.sign').info('Attempting to sign packages'<br> ' (%s) with key "%s"' % (rpms, gpg_name))<br> rpm_cmd = "%s --resign --define '_signature gpg'" % rpm<br>
rpm_cmd += " --define '_gpgbin %s'" % gpgbin<br> rpm_cmd += " --define '_gpg_path %s'" % gpg_path<br> rpm_cmd += " --define '_gpg_name %s' %s" % (gpg_name, rpms)<br>
pex = pexpect.spawn(rpm_cmd, timeout=1000)<br> # Add rpm output to a temporary file<br> fout = os.tmpfile()<br> pex.logfile = fout<br> pex.expect('(E|e)nter (P|p)ass (P|p)hrase:', timeout=1000)<br>
if not gpg_pass:<br> pex.sendline('\r')<br> else:<br> pex.sendline(gpg_pass)<br> i = pex.expect(['good', 'failed', 'skipping', pexpect.TIMEOUT])<br> pex.expect(pexpect.EOF)<br>
if i == 0:<br> logging.getLogger('koji.plugin.sign').info('Package sign successful!')<br> elif i == 1:<br> logging.getLogger('koji.plugin.sign').error('Pass phrase check failed!')<br>
elif i == 2:<br> logging.getLogger('koji.plugin.sign').error('Package sign skipped!')<br> elif i == 3:<br> logging.getLogger('koji.plugin.sign').error('Package sign timed out!')<br>
else:<br> logging.getLogger('koji.plugin.sign').error('Unexpected sign result!')<br> if i != 0:<br> # Rewind in rpm output<br> fout.seek(0)<br> # Add GPG errors to log<br>
for line in fout.readlines():<br> if 'gpg:' in line:<br> logging.getLogger('koji.plugin.sign').error(line.rstrip('\n'))<br> fout.close()<br> raise Exception, 'Package sign failed!'<br>
else:<br> fout.close()<br><br>register_callback('preImport', sign)<br><br><br><br><br><br>Regards,<br>Pierre<br><br><br>