From d0faf00a26efd16de456368b5688df9ece95f2a8 Mon Sep 17 00:00:00 2001 From: Trevor Batley Date: Fri, 27 Sep 2024 18:19:51 +1000 Subject: [PATCH] add plugins --- plugins/README.md | 27 ++ plugins/koji-plugin-sign/LICENSE | 201 +++++++++++ plugins/koji-plugin-sign/README.md | 9 + plugins/koji-plugin-sign/post_sign.py | 63 ++++ .../rpm/koji-plugin-sign.spec | 88 +++++ plugins/koji-plugin-sign/sign.conf | 15 + plugins/koji-plugin-sign/sign.py | 129 +++++++ plugins/tag2distrepo/LICENSE | 340 ++++++++++++++++++ plugins/tag2distrepo/MANIFEST.in | 2 + plugins/tag2distrepo/README.md | 63 ++++ plugins/tag2distrepo/setup.py | 14 + plugins/tag2distrepo/tag2distrepo.py | 59 +++ 12 files changed, 1010 insertions(+) create mode 100644 plugins/README.md create mode 100644 plugins/koji-plugin-sign/LICENSE create mode 100644 plugins/koji-plugin-sign/README.md create mode 100644 plugins/koji-plugin-sign/post_sign.py create mode 100644 plugins/koji-plugin-sign/rpm/koji-plugin-sign.spec create mode 100644 plugins/koji-plugin-sign/sign.conf create mode 100644 plugins/koji-plugin-sign/sign.py create mode 100644 plugins/tag2distrepo/LICENSE create mode 100644 plugins/tag2distrepo/MANIFEST.in create mode 100644 plugins/tag2distrepo/README.md create mode 100644 plugins/tag2distrepo/setup.py create mode 100644 plugins/tag2distrepo/tag2distrepo.py diff --git a/plugins/README.md b/plugins/README.md new file mode 100644 index 0000000..493799e --- /dev/null +++ b/plugins/README.md @@ -0,0 +1,27 @@ +# ![smeserver-koji](https://www.koozali.org/images/koozali/Logo/Png/Koozali_logo_2016.png) + +## Koji Plugins used by Koozali in our setup + +To install these plugins: + +Copy the tag2distrepo.py and sign.py programs into /usr/lib/koji-hub-plugins +Set the configurations as per the directions for each plugin below + +Edit the following settings in /etc/koji-hub/hub.conf to enable the plugins: + + PluginPath = /usr/lib/koji-hub-plugins + Plugins = tag2distrepo sign + +Reload Apache + $ systemctl reload httpd + +###koji-plugin-sign + +Automagically sign rpms with our key after successful build +This is a slightly modified version of the OSG Software Teams koji-hub plugin which can be found at + +###tag2distrepo + +This is a koji-hub plugin available in the available in default koji installation +Create an external repository for any tag when a new build is completed, or a build is attached (tag-build) to a tag + diff --git a/plugins/koji-plugin-sign/LICENSE b/plugins/koji-plugin-sign/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/plugins/koji-plugin-sign/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/plugins/koji-plugin-sign/README.md b/plugins/koji-plugin-sign/README.md new file mode 100644 index 0000000..67c4864 --- /dev/null +++ b/plugins/koji-plugin-sign/README.md @@ -0,0 +1,9 @@ +# koji-plugin-sign +Koji plugin for automated package signing; internally used by the OSG Software Team. + +This provides a koji-hub preImport plugin that makes a callout to rpmsign(8) to sign the built RPMs before importing them into Koji. +The key IDs and passphrases can be configured via a Python ConfigParser-style config file. +pexpect is used to type in the passphrase or PIN. + +This was originally taken from https://fedorahosted.org/koji/ticket/203 but that URL is gone. +The original license is unknown. diff --git a/plugins/koji-plugin-sign/post_sign.py b/plugins/koji-plugin-sign/post_sign.py new file mode 100644 index 0000000..5a8f19a --- /dev/null +++ b/plugins/koji-plugin-sign/post_sign.py @@ -0,0 +1,63 @@ +# Koji callback for writing signed rpms after signing via sign.py +# Required for package generation with strict keys in mash + +from koji.plugin import register_callback +import kojihub +import logging +from configparser import ConfigParser + +# Configuration file in /etc like for other plugins +config_file = '/etc/koji-hub/plugins/sign.conf' + +logger = logging.getLogger('koji.plugin.post_sign') + + +def validate_args(sigkey, sighash, build, rpm): + missing_args = [] + if sigkey is None: + missing_args.append('sigkey') + if sighash is None: + missing_args.append('sighash') + if build is None: + missing_args.append('build') + if rpm is None: + missing_args.append('rpm') + + if rpm is not None and 'buildroot_id' not in rpm: + missing_args.append('rpm.buildroot_id') + if build is not None and 'nvr' not in build: + missing_args.append('build.nvr') + + if any(missing_args): + logger.warning(f"Required arguments {missing_args} missing in post_sign plugin. Skipping") + return False + return True + +def post_sign(cbType, sigkey=None, sighash=None, build=None, rpm=None): + """ Run the kojihub write-signed-rpm command on rpms after they've been signed with a signing key, + which is required for generating repos that use a specific key. + """ + if not validate_args(sigkey, sighash, build, rpm): + return + + buildroot = kojihub.get_buildroot(rpm['buildroot_id']) + + if buildroot is None or 'tag_name' not in buildroot: + logger.warning("No tag name found for build. Skipping") + return + + tag_name = buildroot['tag_name'] + logger.info("Running post-sign plugin for build %s with tag_name %s", build['nvr'], tag_name) + + config = ConfigParser() + config.read(config_file) + + if not config.has_option(tag_name, "strict_keys") or not config.getboolean(tag_name, "strict_keys"): + # Only need to write-signed-rpm for repos with strict signing enabled + logger.info("tag_name %s doesn't have strict signing enabled. Skipping.", tag_name) + return + + kojihub.write_signed_rpm(rpm, sigkey) + logging.getLogger('koji.plugin.sign').info("write-signed-rpm task run successfully.") + +register_callback('postRPMSign', post_sign) diff --git a/plugins/koji-plugin-sign/rpm/koji-plugin-sign.spec b/plugins/koji-plugin-sign/rpm/koji-plugin-sign.spec new file mode 100644 index 0000000..b0575d9 --- /dev/null +++ b/plugins/koji-plugin-sign/rpm/koji-plugin-sign.spec @@ -0,0 +1,88 @@ +Name: koji-plugin-sign +Version: 1.4.0 +Release: 15%{?dist} +Summary: GPG signing plugin for koji-hub + +Group: Applications/System +License: Apache 2.0 +URL: https://github.com/osg-htc/koji-plugin-sign +Source: %{name}-%{version}.tar.gz +BuildArch: noarch +BuildRequires: koji-hub +Requires: koji-hub +%if 0%{?el7} +BuildRequires: pexpect +Requires: pexpect +%else +BuildRequires: python3-pexpect +Requires: python3-pexpect +%endif +Requires: /usr/bin/rpmsign + +%description +GPG signing plugin for koji-hub + +%prep +%autosetup -p1 + +%build +exit 0 + + +%install +mkdir -p $RPM_BUILD_ROOT +install -D sign.conf -m 0600 $RPM_BUILD_ROOT/etc/koji-hub/plugins/sign.conf +install -D sign.py -m 0755 $RPM_BUILD_ROOT/usr/lib/koji-hub-plugins/sign.py +install -D post_sign.py -m 0755 $RPM_BUILD_ROOT/usr/lib/koji-hub-plugins/post_sign.py + + +%files +%config(noreplace) %attr(0600,apache,apache) /etc/koji-hub/plugins/sign.conf +%attr(0755,root,root) /usr/lib/koji-hub-plugins/sign.py* +%attr(0755,root,root) /usr/lib/koji-hub-plugins/post_sign.py* + + + +%changelog +* Fri Oct 27 2023 Matt Westphall - 1.4.0-15 +- Add callback to run koji write-signed-rpm after signing + +* Mon Oct 16 2023 Matt Westphall - 1.4.0-14 +- Re-add more robust error checking for new prompts + +* Fri Oct 13 2023 Matt Westphall - 1.4.0-13 +- Update pexpect prompt check for yubikey with pinentry-mode loopback + +* Fri Oct 13 2023 Mátyás Selmeci - 1.4.0-12 +- First build from GitHub sources + +* Fri Dec 30 2022 Carl Edquist - 1.4.0-10 +- Bump and rebuild for new gpg key (SOFTWARE-5422) + +* Wed Dec 28 2022 Mátyás Selmeci - 1.4.0-9 +- Patch to add gpg_digest_algo option (SOFTWARE-5425) +- Patches to improve error detection (SOFTWARE-5410) +- Patch for Python 3 compat + +* Wed Apr 22 2020 Mátyás Selmeci - 1.4.0-8 +- Add /usr/bin/rpmsign dependency + +* Thu Oct 17 2013 Matyas Selmeci - 1.4.0-7 +- Rebuild with dist tag + +* Thu Sep 22 2011 Matyas Selmeci - 1.4.0-6 +- fixed disabling not working with previous patch + +* Thu Sep 22 2011 Matyas Selmeci - 1.4.0-5 +- added patch to allow enabling/disabling signing for a tag (or by default) + +* Thu Sep 15 2011 Matyas Selmeci - 1.4.0-4 +- added pexpect dependency + +* Thu Sep 15 2011 Matyas Selmeci 1.4.0-3 +- Set package to be noarch +- sign.py moved to /usr/lib/koji-hub-plugins to match what the package koji-hub-plugins is doing + +* Fri Aug 5 2011 Matyas Selmeci 1.4.0-1 +- Created + diff --git a/plugins/koji-plugin-sign/sign.conf b/plugins/koji-plugin-sign/sign.conf new file mode 100644 index 0000000..1f1858a --- /dev/null +++ b/plugins/koji-plugin-sign/sign.conf @@ -0,0 +1,15 @@ +# /etc/koji-sign-plugin/sign.conf +# This file and the gpg_path should be readable by the apache user only +[DEFAULT] +rpm = /bin/rpm +gpgbin = /usr/bin/gpg +gpg_path = /etc/koji-sign-plugin/gnupg +gpg_name = My Company, Inc. +gpg_pass = my_passphrase +enabled = 1 + +# Defaults can be overridden on a per tag basis +[dist-foo-build] +gpg_name = My Other Company, Inc. +gpg_pass = my_other_passphrase + diff --git a/plugins/koji-plugin-sign/sign.py b/plugins/koji-plugin-sign/sign.py new file mode 100644 index 0000000..b077e3a --- /dev/null +++ b/plugins/koji-plugin-sign/sign.py @@ -0,0 +1,129 @@ +# Koji callback for GPG signing RPMs before import +# Consider sigul for a more robust solution -- https://fedorahosted.org/sigul/ +# +# Author: +# Paul B Schroeder + +from koji.plugin import register_callback +from tempfile import TemporaryFile +import logging +import os +import pexpect +import re +from configparser import ConfigParser, NoOptionError + +# Get the tag name from the buildroot map +import sys +sys.path.insert(0, '/usr/share/koji-hub') +from kojihub import get_buildroot + +# Configuration file in /etc like for other plugins +config_file = '/etc/koji-hub/plugins/sign.conf' + +GPG_EXPECTS = ['Enter passphrase:', pexpect.EOF, 'failed', 'skipping', 'error', pexpect.TIMEOUT] +ERROR_MESSAGES = { + 2: 'Package signing failed!', + 3: 'Package signing skipped!', + 4: 'Package signing error!', + 5: 'Package signing timed out!' +} + +def sign(cbtype, *args, **kws): + if kws['type'] != 'build': + return + + br_id = list(kws['brmap'].values())[0] + br = get_buildroot(br_id) + tag_name = br['tag_name'] + + logging.getLogger('koji.plugin.sign').info("Got package with tag_name %s", tag_name) + + config = ConfigParser() + config.read(config_file) + if not config.has_section(tag_name): + tag_name = "DEFAULT" + rpm = config.get(tag_name, 'rpm') + gpgbin = config.get(tag_name, 'gpgbin') + gpg_path = config.get(tag_name, 'gpg_path') + gpg_name = config.get(tag_name, 'gpg_name') + gpg_pass = config.get(tag_name, 'gpg_pass') + try: + gpg_digest_algo = config.get(tag_name, 'gpg_digest_algo') + except NoOptionError: + gpg_digest_algo = None + try: + enabled = config.getboolean(tag_name, 'enabled') + except NoOptionError: + # Note that signing is _enabled_ by default + enabled = True + + + if not enabled: + logging.getLogger('koji.plugin.sign').info('Signing not enabled for this tag.') + return + + # Get the package paths set up + from koji import pathinfo + uploadpath = pathinfo.work() + rpm_paths = [f'{uploadpath}/{relpath}' for relpath in [kws['srpm']] + kws['rpms']] + rpms = ' '.join(rpm_paths) + + # Get the packages signed + os.environ['LC_ALL'] = 'C' + logging.getLogger('koji.plugin.sign').info('Attempting to sign packages' + ' (%s) with key "%s"' % (rpms, gpg_name)) + rpm_cmd = "%s --resign --define '_signature gpg'" % rpm + rpm_cmd += " --define '_gpgbin %s'" % gpgbin + rpm_cmd += " --define '_gpg_path %s'" % gpg_path + if gpg_digest_algo: + rpm_cmd += " --define '_gpg_digest_algo %s'" % gpg_digest_algo + rpm_cmd += " --define '_gpg_name %s' %s" % (gpg_name, rpms) + pex = pexpect.spawn(rpm_cmd, timeout=30) + # Add rpm output to a temporary file + fout = TemporaryFile() + pex.logfile = fout + + result = 0 + # Yubikey occassionally requests password twice, I have no idea why + while result == 0: + # With pinentry-mode loopback, this is the only prompt output by GPG + result = pex.expect(GPG_EXPECTS, timeout=30) + if result == 0: + pex.sendline(gpg_pass) + + pex.close() + ok = True + if result < 2 and pex.exitstatus == 0: + logging.getLogger('koji.plugin.sign').info('Package sign successful!') + else: + logging.getLogger('koji.plugin.sign').error(ERROR_MESSAGES.get(result, "Unknown signing error!")) + logging.getLogger('koji.plugin.sign').error("rpmsign exited with exit code %s, signal status %s", pex.exitstatus, pex.signalstatus) + ok = False + if not ok: + fout.seek(0) + # Add GPG errors to log + errors = '' + for line in fout.readlines(): + errors += line.decode().replace(gpg_pass, '') + fout.close() + raise Exception('Package sign failed!\n' + errors) + else: + fout.close() + + + # Sanity check, ensure that a signature exists for each rpm + non_signed_rpms = [] + for processed_rpm in rpm_paths: + rpm_cmd = f"{rpm} -qpi {processed_rpm}" + pex = pexpect.spawn(rpm_cmd, timeout=1000) + result = pex.expect(['Signature.*:.*Key ID.*',pexpect.EOF], timeout=5) + pex.close() + if result != 0: + non_signed_rpms.append(processed_rpm) + + if len(non_signed_rpms) > 0: + raise Exception('Signatures missing from the following packages: ' + ' '.join(non_signed_rpms)) + + + +register_callback('preImport', sign) diff --git a/plugins/tag2distrepo/LICENSE b/plugins/tag2distrepo/LICENSE new file mode 100644 index 0000000..623b625 --- /dev/null +++ b/plugins/tag2distrepo/LICENSE @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/plugins/tag2distrepo/MANIFEST.in b/plugins/tag2distrepo/MANIFEST.in new file mode 100644 index 0000000..9d5d250 --- /dev/null +++ b/plugins/tag2distrepo/MANIFEST.in @@ -0,0 +1,2 @@ +include LICENSE +include README.rst diff --git a/plugins/tag2distrepo/README.md b/plugins/tag2distrepo/README.md new file mode 100644 index 0000000..77b5d96 --- /dev/null +++ b/plugins/tag2distrepo/README.md @@ -0,0 +1,63 @@ +# tag2distrepo + +Koji plugin to automatically regenerate distrepos on tag operations + +It uses the following options on a tag to control behaviour: + +- `tag2distrepo.enabled`: set to "true" to enable automatic distrepos +- `tag2distrepo.keys`: set to a space-separated list of keys to use for distrepos + +The tag must have at least one arch configured on it. + +# Installing plugin on Koji Hub + +1. Copy `tag2distrepo.py` to `/usr/lib/koji-hub-plugins` + +2. Edit the following settings in `/etc/koji-hub/hub.conf` to enable the plugin: + + PluginPath = /usr/lib/koji-hub-plugins + Plugins = tag2distrepo + +3. Reload Apache + + systemctl reload httpd + +# Example usage + +Here is an example of enabling the plugin on an "f33-infra" tag. Create the tag and ensure it has at least one arch and a package list (direct or inherited) so we can tag packages into it. + + koji add-tag f33-infra --arches=x86_64 + koji add-pkg --owner kdreyer f33-infra bash + +Set the extra options on the tag so the plugin will generate the repository: + + koji edit-tag -x tag2distrepo.enabled=True -x tag2distrepo.keys=47dd8ef9 f33-infra + +Tag a new build to trigger the plugin: + + koji tag f33-infra bash-5.0.17-2.fc33 + +The hub will immediately queue a new distRepo task, using the tagBuild task host as the distRepo task owner. When the distRepo task completes, you can find the new repository under the ``topurl`` for your Koji instance. + +To confirm that the tag has the correct options set, use the `koji taginfo` command: + + koji taginfo f33-infra + Tag: f33-infra [18680] + Arches: x86_64 + Tag options: + tag2distrepo.enabled : 'true' + tag2distrepo.keys : '47dd8ef9' + +To disable the plugin for the same tag: + + koji edit-tag -r tag2distrepo.enabled -r tag2distrepo.keys f33-infra + +# Using Multiple Keys + +If you want to create a repository that contains builds signed by more than one key, list your desired key IDs ordered by preference. + +For example: + + koji edit-tag coreos-pool -x tag2distrepo.keys="45719a39 9867c58f 38ab71f4 5323552a" + +For each RPM in the tag, Koji will use the first signed copy that it finds. In other words, Koji will try the first key (`45719a39`), and if Koji does not have the first key's signature for that RPM, then it will try the second key (`9867c58f`), third key (`38ab71f4`), and so on. diff --git a/plugins/tag2distrepo/setup.py b/plugins/tag2distrepo/setup.py new file mode 100644 index 0000000..ffc415b --- /dev/null +++ b/plugins/tag2distrepo/setup.py @@ -0,0 +1,14 @@ +from setuptools import setup + +setup( + name='tag2distrepo', + version='2.0', + description='Koji Hub plugin to automatically regenerate distrepos on tag operations', + author='Patrick Uiterwijk', + author_email='puiterwijk@redhat.com', + url='https://pagure.io/tag2distrepo/', + license='gplv2+', + packages=[ + 'tag2distrepo', + ], +) diff --git a/plugins/tag2distrepo/tag2distrepo.py b/plugins/tag2distrepo/tag2distrepo.py new file mode 100644 index 0000000..20c8da6 --- /dev/null +++ b/plugins/tag2distrepo/tag2distrepo.py @@ -0,0 +1,59 @@ +# Koji tag2distrepo hub plugin +# Copyright (c) 2019 Red Hat, Inc. +# This callback automatically schedules distrepo tasks based on a tags config +# +# Authors: +# Patrick Uiterwijk + +from __future__ import absolute_import +from koji.plugin import callback +from kojihub import dist_repo_init, make_task, readTaggedRPMS, write_signed_rpm +import logging + +@callback('postTag') +def tag2distrepo(cbtype, tag, build, user, force=False): + logger = logging.getLogger('koji.plugin.tag2distrepo') + + if not tag['extra'].get("tag2distrepo.enabled"): + logger.debug("No tag2distrepo enabled for tag %s" % tag['name']) + return + if not tag['arches']: + raise ValueError("Tag %s has no arches configured but tag2distrepo is enabled" % tag['name']) + + keys = tag['extra'].get("tag2distrepo.keys", '').split() + + if keys: + logger.debug("Ensuring signed RPMs are written out") + [rpms, _] = readTaggedRPMS(tag['id'], rpmsigs=True) + for rpm in rpms: + for key in keys: + if rpm['sigkey'] == key: + write_signed_rpm(rpm['id'], key, False) + + task_opts = { + 'arch': tag['arches'].split(), + 'comp': None, + 'delta': [], + 'event': None, + 'inherit': False, + 'latest': False, + 'multilib': False, + 'split_debuginfo': False, + 'skip_missing_signatures': False, + 'allow_missing_signatures': not keys, + } + logging.debug( + "Scheduling distRepo for tag %s, keys %s", + tag['name'], + keys, + ) + + repo_id, event_id = dist_repo_init(tag['name'], keys, task_opts) + task_opts['event'] = event_id + task_id = make_task( + 'distRepo', + [tag['name'], repo_id, keys, task_opts], + priority=15, + channel='createrepo', + ) + logging.info("distRepo task %d scheduled for tag %s" % (task_id, tag['name']))