From dba03d5714047c6de5a145d1c7a731ddaead13ef Mon Sep 17 00:00:00 2001 From: Patrick Uiterwijk Date: Oct 11 2018 12:44:01 +0000 Subject: Rewrote to integrate CentOS and use dynamic backend Signed-off-by: Patrick Uiterwijk --- diff --git a/README.rst b/README.rst index a285d5d..18ee674 100644 --- a/README.rst +++ b/README.rst @@ -3,12 +3,62 @@ pagure-dist-git .. split here -Since 3.0 pagure offers a way to customize the creation and compilation the of -the gitolite configuration file. +This project implements a dynamic Git auth backend for Pagure for Fedora and CentOS +dist-git setups, which have slightly different access models than standard on Pagure. + +Configuration +============= + +This plugin reuses the Pagure configuration, and adds several keys to it. + +ACL_DEBUG: Whether to print some output with information decisions are based on. +ACL_PROTECTED_NAMESPACES: List of namespaces where the extra strong protections are in place. +BLACKLIST_RES: List of regular expressions with refs that can never be pushed. +ACL_BLOCK_UNSPECIFIED: Whether to deny pushes to branches that aren't either RCM, SIG or supported branches. +UNSPECIFIED_BLACKLIST_RES: List of regular expressions with refs that can't be used if unspecified. +RCM_BRANCHES: List of regular expressions with refs that people in the RCM group can push. +RCM_GROUP: The group containing RCM members +SUPPORTED_SIGS: List of groups that grant access to sig_prefix-$signame-* refs. +SIG_PREFIXES: List of prefixes for SIG refs. + + +Example configurations +====================== + +Fedora +------ + +```` +ACL_DEBUG = False +ACL_BLOCK_UNSPECIFIED = False +ACL_PROTECTED_NAMESPACES = ['rpms', 'modules', 'container'] +RCM_GROUP = 'relenggroup' +RCM_BRANCHES = ['refs/heads/f[0-9]+'] +# Pushing to c* stuff is never allowed +BLACKLIST_RES = ['refs/heads/c[0-9]+.*'] +# Pushing to (f|epel|el|olpc)(num+) that is not previously approved +# (supported branches) is not allowed. +UNSPECIFIED_BLACKLIST_RES = ['refs/heads/f[0-9]+', + 'refs/heads/epel[0-9]+', + 'refs/heads/el[0-9]+', + 'refs/heads/olpc[0-9]+'] +```` + +CentOS +------ + +```` +SIG_PREFIXES = ['refs/heads/c7', 'refs/heads/c7-plus', 'refs/heads/c7-alt', ] +SUPPORTED_SIGS = ['sig-atomic', 'sig-cloud', 'sig-core', 'sig-storage', ] + +# Branches to which *nobody* will be able to push (basically Fedora) +BLACKLIST_RES = ['refs/heads/el[0-9]+.*', 'refs/heads/olpc[0-9]+.*', ] + +### Specific ACO group that will have access to all protected branches with RWC rights +RCM_GROUP = 'centos-rcm' +RCM_BRANCHES = ['refs/heads/c[0-9]+.*', 'refs/tags/.*', ] +```` -This project hosts the logic to generate gitolite's configuration file for -dist-git which has a different access model than regular projects on pagure (for -example, forced pushed is forbidden). Tests ===== diff --git a/dist_git_auth.py b/dist_git_auth.py index 887147d..468a4b2 100644 --- a/dist_git_auth.py +++ b/dist_git_auth.py @@ -1,177 +1,276 @@ # -*- coding: utf-8 -*- """ - (c) 2017 - Copyright Red Hat Inc + (c) 2017 - 2018 - Copyright Red Hat Inc - Authors: The Dream Team - Pierre-Yves Chibon - Ralph Bean + Authors: + Patrick Uiterwijk + + The Dream Team + Pierre-Yves Chibon + Ralph Bean """ from __future__ import print_function import logging +import re import os -import pdc_client -import werkzeug - -if 'PAGURE_CONFIG' not in os.environ \ - and os.path.exists('/etc/pagure/pagure.cfg'): - os.environ['PAGURE_CONFIG'] = '/etc/pagure/pagure.cfg' +try: + from pdc_client import PDCClient +except ImportError: + PDCClient = None -import pagure # noqa: E402 -from pagure.config import config # noqa: E402 -from pagure.lib import model # noqa: E402 -from pagure.lib.git_auth import Gitolite3Auth, _read_file # noqa: E402 +if "PAGURE_CONFIG" not in os.environ and os.path.exists( + "/etc/pagure/pagure.cfg" +): + os.environ["PAGURE_CONFIG"] = "/etc/pagure/pagure.cfg" -_NOT_PROVENPACKAGER = ['rpms/firefox', 'rpms/thunderbird', 'rpms/xulrunner'] +from pagure.config import config as pagure_config +from pagure.lib import model, get_user +from pagure.lib.git import is_forced_push +from pagure.lib.git_auth import GitAuthHelper, _read_file +from pagure.utils import is_repo_committer _log = logging.getLogger(__name__) -_blacklist = ''' - f[0-9][0-9] = @all - - epel[0-9] = @all - - epel[0-9][0-9] = @all - - el[0-9] = @all - - olpc[0-9] = @all''' - -namespace2pdctype = { - 'rpms': 'rpm', - 'modules': 'module', - 'container': 'container', -} - - -def get_supported_branches(namespace, package): - default_url = 'https://pdc.fedoraproject.org/rest_api/v1/' - url = config.get('PDC_URL', default_url) - pdc = pdc_client.PDCClient(url, develop=True) - _log.info('Querying PDC for %s/%s' % (namespace, package)) - kwargs = dict( - global_component=package, - type=namespace2pdctype[namespace], - active=True, # Not EOL. - ) - branches = pdc.get_paged(pdc['component-branches'], **kwargs) - return [branch['name'] for branch in branches] - - -class DistGitoliteAuth(Gitolite3Auth): - """ A dist-git's gitolite authentication module. """ - - @staticmethod - def _get_gitolite_command(): - """ Return the gitolite command to run based on the info in the - configuration file. +class DistGitAuth(GitAuthHelper): + """ A Fedora and CentOS dist-Git authentication module. """ + is_dynamic = True + + def __init__(self): + super(DistGitAuth, self).__init__() + + self.is_debug = pagure_config.get("ACL_DEBUG", False) + self.global_pr_only = pagure_config.get("PR_ONLY", False) + self.block_unspecified = pagure_config.get("ACL_BLOCK_UNSPECIFIED", + True) + self.blacklists = [re.compile(refre) + for refre + in pagure_config["BLACKLIST_RES"]] + self.unspecified_blacklist = [ + re.compile(refre) + for refre + in pagure_config.get("UNSPECIFIED_BLACKLIST_RES", [])] + self.rcm_branches = [re.compile(refre) + for refre + in pagure_config["RCM_BRANCHES"]] + self.rcm_group = pagure_config.get("RCM_GROUP") + self.supported_sigs = set(pagure_config.get("SUPPORTED_SIGS", [])) + self.sig_prefixes = pagure_config.get("SIG_PREFIXES", []) + self.protected_namespaces = pagure_config.get( + "ACL_PROTECTED_NAMESPACES", ["rpms"]) + + pdc_url = pagure_config.get('PDC_URL') + if pdc_url and PDCClient: + self.pdcclient = PDCClient(pdc_url, develop=True) + else: + self.pdcclient = None + + def is_supported_branch(self, project, refname): + """ Returns whether a specific branch is currently supported for Fedora + + This retrieves the information about EOL status from PDC, to prevent + EOL branches being pushed to. """ - _log.info('Compiling the gitolite configuration') - gitolite_folder = config.get('GITOLITE_HOME', None) - if gitolite_folder: - cmd = 'HOME=%s gitolite compile' % (gitolite_folder) - _log.debug('Command: %s', cmd) - return cmd + if not self.pdcclient: + # No way to confirm this is a supported branch, not supported + return None + if not refname.startswith('refs/heads/'): + # Anything outside of refs/heads is out-of-scope + return None + refname = refname[len('refs/heads/'):] + + namespace2pdctype = { + 'rpms': 'rpm', + 'modules': 'module', + 'container': 'container', + } + res = list(self.pdcclient.get_paged( + self.pdcclient['component-branches'], + global_component=project.name, + type=namespace2pdctype[project.namespace], + name=refname, + fields=['active'], + )) + if len(res) == 0: + # No status + return None + if len(res) != 1: + # PDC couldn't make up its mind.... + # Should never happen, but just in case... + raise ValueError("PDC was unable to make up its mind") + return res[0]['active'] + + def info(self, msg): + """ Function to print information. + + Is a function to help with the test suite. """ + print(msg) + + def debug(self, msg): + """ Function to print if in debug mode. + + Function to help in test. """ + if self.is_debug: + self.info(msg) + + def check_acl( + self, + session, + project, + username, + refname, + pull_request, + repodir, + repotype, + revfrom, + revto, + is_internal, + **info + ): + """ Perform dynamic ACL checks. + + For arguments, see GitAuthHelper.check_acl.""" + + # First, some rules regardless of user status + # Only the "main" and "requests" repos are used + if repotype not in ("main", "requests"): + self.info("Repotype %s not in use" % repotype) + return False + + # Do not allow branch deletions + if revto == '0'*40: + self.info("Branch deletion is not allowed") + return False + + # Do not allow non-fast-forward pushes for anything but forks + if not project.is_fork and is_forced_push(revfrom, revto, repodir): + self.info("Forced pushes are not allowed") + return False + + # If this is pushed through internal changes, approve. + # This flag is only provided if it's either an update to the "side" + # repos, or during creation/forking of a project. + if is_internal: + self.info("Internal push allowed") + return True + + # Deploy Keys are not allowed on dist-git + if username.startswith("deploykey_"): + self.info("Deploy keys are disabled") + return False + + # Now build up info about the user and project to make decisions + # Determine the users' groups + user = get_user(session, username) + usergroups = set(user.groups) + + # Determine whether the user is a committer + is_committer = is_repo_committer(project, username, session) + + # Determine whether the user is a SIG member + user_sigs = self.supported_sigs & usergroups + + # Determine whether the user is RCM + is_rcm = bool(self.rcm_group and self.rcm_group in usergroups) + + # If configured, print user info + self.debug("Protected namespaces: %s" % self.protected_namespaces) + self.debug("Blocking unspecified refs: %s" % self.block_unspecified) + self.debug("Blacklists: %s" % self.blacklists) + self.debug("User: %s" % user) + self.debug("User groups: %s" % usergroups) + self.debug('Committer: %s' % is_committer) + self.debug('SIG memberships: %s' % user_sigs) + self.debug('RCM: %s' % is_rcm) + + # We have data, start the actual ACL checking + if ( + repotype == "main" + and not project.is_fork + and project.namespace in self.protected_namespaces + ): + # In the protected namespace, we want to make sure we don't + # trample on blacklisted content. + for entry in self.blacklists: + if entry.match(refname): + self.info("Ref %s is blocked" % refname) + return False + + # Allow RCM push + if is_rcm: + for refre in self.rcm_branches: + if refre.match(refname): + # RCM on an RCM branch -> allow + self.debug("RCM push") + return True + + # Allow CentOS SIGs to push to e.g. c7-sig-core-$anything + for signame in user_sigs: + for sigprefix in self.sig_prefixes: + sigbranch = "%s-%s-" % (sigprefix, signame) + if refname.startswith(sigbranch): + self.debug("SIG push") + return True + + # For Fedora, allow supported branches + is_supported = self.is_supported_branch(project, refname) + if is_supported is False: + self.info("Branch %s is unsupported" % refname) + return False + elif is_supported is True: + self.debug("Branch %s is supported" % refname) + return is_committer + else: + self.debug("No supported status available") + + if self.block_unspecified: + self.info("Access to namespace %s is restricted" + % project.namespace) + return False + + # Block second level blacklists + for entry in self.unspecified_blacklist: + if entry.match(refname): + self.info("Unspecified ref %s is blocked" % refname) + return False + + # For unspecified refs, they can push if they're a committer + self.debug("Unspecified branch push") + return is_committer + + # This is outside of the strongly protected namespaces + if repotype == "main": + # If this project has PRs only on, or PRs are globally enforced and + # this is not a fork, only allow pushing if this is a PR merge. + pr_only = project.settings.get("pull_request_access_only", False) + if ( + pr_only + or (self.global_pr_only and not project.is_fork) + and pull_request is None + ): + self.info("A pull request is required for this branch") + return False + + # This is an unprotected namespace, let's allow committers + if is_committer: + self.debug("Committer push to unprotected") + return True + + # If all else fails, deny + self.info("Fall-through deny") + return False @classmethod - def _process_project(cls, project, config, global_pr_only): - """ Generate the gitolite configuration for the specified project. - - :arg project: the project to generate the configuration for - :type project: pagure.lib.model.Project - :arg config: a list containing the different lines of the - configuration file - :type config: list - :arg global_pr_only: boolean on whether the pagure instance enforces - the PR workflow only or not - :type global_pr_only: bool - :return: the updated config - :return type: list - - """ - - _log.debug(' Processing project: %s', project.fullname) + def generate_acls(cls, project, group=None): + """ Required function that doesn't do anything. """ + pass - # Check if the project or the pagure instance enforce the PR - # only development model. - pr_only = project.settings.get('pull_request_access_only', False) - - for repos in ['repos', 'requests/']: - if repos == 'repos': - config.append('repo %s' % project.fullname) - - # Add ACL for mass rebuilds, even in PR-only - config.append(' RW = releng') - - # Do not grant access to project enforcing the PR model - if pr_only or (global_pr_only and not project.is_fork): - continue - repos = '' - else: - config.append('repo %s%s' % (repos, project.fullname)) - - if repos not in ['tickets/', 'requests/']: - config.append(' R = @all') - - access = 'RWC' - if project.is_fork: - access = 'RW+C' - - users = sorted(set([project.user.user]).union( - set( - user.user - for user in project.committers - if user != project.user))) - groups = sorted(set( - group.group_name - for group in project.committer_groups - )) - - if repos == '' and not project.is_fork: - if project.fullname not in _NOT_PROVENPACKAGER: - groups.append('provenpackager') - # First, whitelist the supported branches from PDC - for branch in get_supported_branches( - project.namespace, project.name): - config.append(' %s %s = %s' % ( - access, branch, ' '.join(users) - ) - ) - if groups: - config.append(' %s %s = @%s' % ( - access, branch, ' @'.join(groups) - ) - ) - - # Then, blacklist a pattern over that (after). - config.append(_blacklist) - - if groups: - config.append(' %s = @%s' % (access, ' @'.join(groups))) - - config.append(' %s = %s' % (access, ' '.join(users))) - - for deploykey in project.deploykeys: - access = 'R' - if deploykey.pushaccess: - access = 'RW' - if project.is_fork: - access = 'RW+C' - # Note: the replace of / with _ is because gitolite - # users can't contain a /. At first, this might look - # like deploy keys in a project called - # $namespace_$project would give access to the repos of - # a project $namespace/$project or vica versa, however - # this is NOT the case because we add the deploykey.id - # to the end of the deploykey name, which means it is - # unique. The project name is solely there to make it - # easier to determine what project created the deploykey - # for admins. - config.append(' %s = deploykey_%s_%s' % - (access, - werkzeug.secure_filename(project.fullname), - deploykey.id)) - - config.append('') - - return config + @classmethod + def remove_acls(cls, session, project): + """ Required function that is unused. """ + pass diff --git a/dist_git_auth_tests.py b/dist_git_auth_tests.py index a270a0c..a0fb33e 100644 --- a/dist_git_auth_tests.py +++ b/dist_git_auth_tests.py @@ -3,539 +3,681 @@ from __future__ import print_function import tempfile import os -import mock +from mock import Mock, patch # These are the tests from the pagure/ git repo. # Run with: # PYTHONPATH=.:/path/to/pagure/checkout nosetests dist_git_auth_tests.py import pagure +import pagure.lib import tests import dist_git_auth -expected = """ -repo test - RW = releng - R = @all - RWC master = pingou - RWC master = @provenpackager - RWC f9000 = pingou - RWC f9000 = @provenpackager - - f[0-9][0-9] = @all - - epel[0-9] = @all - - epel[0-9][0-9] = @all - - el[0-9] = @all - - olpc[0-9] = @all - RWC = @provenpackager - RWC = pingou - -repo requests/test - RWC = pingou - -repo test2 - RW = releng - R = @all - RWC master = pingou - RWC master = @provenpackager - RWC f9000 = pingou - RWC f9000 = @provenpackager - - f[0-9][0-9] = @all - - epel[0-9] = @all - - epel[0-9][0-9] = @all - - el[0-9] = @all - - olpc[0-9] = @all - RWC = @provenpackager - RWC = pingou - -repo requests/test2 - RWC = pingou - -repo somenamespace/test3 - RW = releng - R = @all - RWC master = pingou - RWC master = @provenpackager - RWC f9000 = pingou - RWC f9000 = @provenpackager - - f[0-9][0-9] = @all - - epel[0-9] = @all - - epel[0-9][0-9] = @all - - el[0-9] = @all - - olpc[0-9] = @all - RWC = @provenpackager - RWC = pingou - -repo requests/somenamespace/test3 - RWC = pingou - -# end of body -""" - - -class DistGitoliteAuthTestCase(tests.Modeltests): - """ Test generating the gitolite configuration file for dist-git. """ +def setUp(): + tests.setUp() + + +def tearDown(): + tests.tearDown() + + +def patch_pdc(values): + """ Decorator to patch the PDC calls to return values for this test. + + Args: + values (dict): A dictionary where the keys are project fullnames + (i.e. namespace/name), and the values are dicts with key branch + names, and values their supported status. + Note that as namespace, the PDC "type" is used, which lacks the "s" + for rpms and modules. + e.g.: {'rpm/test': {'f28': True, 'f27': False}} + """ + def pdc_get_paged(_, global_component, type, name, fields): + """ Function that emulates the pdc.get_paged call + + Args as provided by dist_git_auth's calls to it. + + Args: + _ (anything): PDCClient internal + global_component (string): package name + type (string): The PDC "type": "rpm", "module", ... + name (string): The branch name + fields (list): Always ["active"] + """ + fullname = '%s/%s' % (type, global_component) + if fullname not in values: + return [] + val = values[fullname] + if name not in val: + return [] + val = val[name] + if val in (True, False): + return [{"active": val}] + # This case is used to emulate "weird" results + return val + + def decorator(func): + def test_wrapper(*args, **kwargs): + with patch.object(dist_git_auth.PDCClient, '__getitem__'): + with patch.object(dist_git_auth.PDCClient, 'get_paged', + side_effect=pdc_get_paged): + return func(*args, **kwargs) + return test_wrapper + return decorator + + +class DistGitAuthTests(tests.Modeltests): + """ Test DistGitAuth ACLs with Fedora config. """ maxDiff = None def setUp(self): """ Set up the environment in which to run the tests. """ - super(DistGitoliteAuthTestCase, self).setUp() - self.configfile = tempfile.mkstemp()[1] + super(DistGitAuthTests, self).setUp() + + pagure.config.config['ACL_DEBUG'] = True + pagure.config.config.update(self.dga_config) + + self.dga = dist_git_auth.DistGitAuth() + self.dga.info = Mock(side_effect=print) + # We default to saying it's not a forced push + dist_git_auth.is_forced_push = Mock(return_value=False) + + # Create an RCM user/group + rcmuser = pagure.lib.model.User( + user='releng', + fullname='Release Engineering', + token='aaabbbcd', + default_email='rcm@local.local', + ) + self.session.add(rcmuser) + self.session.flush() + rcmgroup = pagure.lib.model.PagureGroup( + group_name='relenggroup', + group_type='user', + display_name='Releng group', + user_id=rcmuser.id, + ) + self.session.add(rcmgroup) + self.session.flush() + rcmuser.group_objs.append(rcmgroup) + self.session.commit() def tearDown(self): """ Tear down the environment in which the tests ran. """ - try: - os.remove(self.configfile) - except: - print("Couldn't remove %r" % self.configfile) - pass - super(DistGitoliteAuthTestCase, self).tearDown() - - @mock.patch('dist_git_auth.get_supported_branches') - def test_write_gitolite_acls(self, get_supported_branches): - """ Test generating the entire gitolite configuration file - (project == -1). + self.dga = None + super(DistGitAuthTests, self).tearDown() - """ - get_supported_branches.return_value = ['master', 'f9000'] - print("Initializing DB.") - tests.create_projects(self.session) + def create_namespaced_project(self, namespace, name, is_fork=False): + item = pagure.lib.model.Project( + user_id=1, # pingou + name=name, + is_fork=is_fork, + parent_id=3 if is_fork else None, + description='namespaced test project', + hook_token='aaabbbeee', + namespace=namespace, + ) + item.close_status = [ + 'Invalid', 'Insufficient data', 'Fixed', 'Duplicate'] + self.session.add(item) + self.session.commit() + return pagure.lib._get_project( + self.session, name=name, namespace=namespace) + + def expect_info_msg(self, expect_msg): + found = False + for call in self.dga.info.call_args_list: + args = call[0] + msg = args[0] + if msg == expect_msg: + found = True + if not found: + raise AssertionError( + "Info message '%s' expected but not found" % expect_msg) + + +class DistGitAuthTestsGeneric(DistGitAuthTests): + dga_config = {} + + def test_unused_repotype(self): + self.assertFalse( + self.dga.check_acl( + self.session, + project=None, + username=None, + refname=None, + pull_request=None, + repodir=None, + repotype='tickets', + revfrom=None, + revto=None, + is_internal=False, + ) + ) - print("Generating %r" % self.configfile) - dist_git_auth.DistGitoliteAuth.write_gitolite_acls( - self.session, - configfile=self.configfile, - project=-1) + self.expect_info_msg("Repotype tickets not in use") + + def test_branch_deletion(self): + dist_git_auth.is_forced_push.return_value = True + + project = self.create_namespaced_project('rpms', 'test') + + self.assertFalse( + self.dga.check_acl( + self.session, + project=project, + username=None, + refname=None, + pull_request=None, + repodir=None, + repotype='main', + revfrom=None, + revto='0000000000000000000000000000000000000000', + is_internal=False, + ) + ) - print("Checking the contents of %r" % self.configfile) - with open(self.configfile, 'r') as f: - contents = f.read() - self.assertMultiLineEqual(contents.strip(), expected.strip()) + self.expect_info_msg("Branch deletion is not allowed") + + def test_forced_push(self): + dist_git_auth.is_forced_push.return_value = True + + project = self.create_namespaced_project('rpms', 'test') + + self.assertFalse( + self.dga.check_acl( + self.session, + project=project, + username=None, + refname=None, + pull_request=None, + repodir=None, + repotype='main', + revfrom=None, + revto=None, + is_internal=False, + ) + ) - @mock.patch('dist_git_auth.get_supported_branches') - def test_write_gitolite_acls_none_project(self, get_supported_branches): - """ Test not touching the gitolite configuration file - (project == None). + self.expect_info_msg("Forced pushes are not allowed") + + def test_internal(self): + project = self.create_namespaced_project('rpms', 'test') + + self.assertTrue( + self.dga.check_acl( + self.session, + project=project, + username=None, + refname=None, + pull_request=None, + repodir=None, + repotype='main', + revfrom=None, + revto=None, + is_internal=True, + ) + ) - """ - get_supported_branches.return_value = ['master', 'f9000'] - print("Initializing DB.") - tests.create_projects(self.session) + self.expect_info_msg("Internal push allowed") + + def test_deploykey(self): + project = self.create_namespaced_project('rpms', 'test') + + self.assertFalse( + self.dga.check_acl( + self.session, + project=project, + username="deploykey_foobar", + refname=None, + pull_request=None, + repodir=None, + repotype='main', + revfrom=None, + revto=None, + is_internal=False, + ) + ) + + self.expect_info_msg("Deploy keys are disabled") - print("Generating %r" % self.configfile) - dist_git_auth.DistGitoliteAuth.write_gitolite_acls( + def test_invalid_user(self): + project = self.create_namespaced_project('rpms', 'test') + + self.assertRaises( + pagure.exceptions.PagureException, + self.dga.check_acl, self.session, - configfile=self.configfile, - project=None) + project=project, + username="nosuchuser", + refname=None, + pull_request=None, + repodir=None, + repotype='main', + revfrom=None, + revto=None, + is_internal=False, + ) - print("Checking the contents of %r" % self.configfile) - with open(self.configfile, 'r') as f: - contents = f.read() - self.assertMultiLineEqual(contents.strip(), '') + def test_unprotected_committer(self): + project = self.create_namespaced_project('unprotected', 'test') + + self.assertTrue( + self.dga.check_acl( + self.session, + project=project, + username="pingou", + refname="refs/heads/mywip", + pull_request=None, + repodir=None, + repotype='main', + revfrom=None, + revto=None, + is_internal=False, + ) + ) - @mock.patch('dist_git_auth.get_supported_branches') - def test_write_gitolite_acls_test_project(self, get_supported_branches): - """ Test updating the gitolite configuration file for just one - project (project == a pagure.lib.model.Project). + self.expect_info_msg("Committer push to unprotected") + + def test_unprotected_non_committer(self): + project = self.create_namespaced_project('unprotected', 'test') + + self.assertFalse( + self.dga.check_acl( + self.session, + project=project, + username="foo", + refname="refs/heads/mywip", + pull_request=None, + repodir=None, + repotype='main', + revfrom=None, + revto=None, + is_internal=False, + ) + ) - """ + self.expect_info_msg("Fall-through deny") + + def test_unprotected_pr_required_pr(self): + project = self.create_namespaced_project('unprotected', 'test') + self.dga.global_pr_only = True + + self.assertTrue( + self.dga.check_acl( + self.session, + project=project, + username="pingou", + refname="refs/heads/mywip", + pull_request=True, + repodir=None, + repotype='main', + revfrom=None, + revto=None, + is_internal=False, + ) + ) - get_supported_branches.return_value = ['master', 'f9000'] - self.test_write_gitolite_acls() + self.expect_info_msg("Committer push to unprotected") + + def test_unprotected_pr_required_no_pr(self): + project = self.create_namespaced_project('unprotected', 'test') + self.dga.global_pr_only = True + + self.assertFalse( + self.dga.check_acl( + self.session, + project=project, + username="pingou", + refname="refs/heads/mywip", + pull_request=None, + repodir=None, + repotype='main', + revfrom=None, + revto=None, + is_internal=False, + ) + ) - print("Modifying the test project so the output differs.") - project = pagure.lib._get_project(self.session, 'test') - project.user_id = 2 - self.session.add(project) - self.session.commit() + self.expect_info_msg("A pull request is required for this branch") + + def test_unprotected_pr_required_requests(self): + project = self.create_namespaced_project('unprotected', 'test') + self.dga.global_pr_only = True + + self.assertTrue( + self.dga.check_acl( + self.session, + project=project, + username="pingou", + refname="refs/heads/mywip", + pull_request=None, + repodir=None, + repotype='requests', + revfrom=None, + revto=None, + is_internal=False, + ) + ) - project = pagure.lib._get_project(self.session, 'test') - msg = pagure.lib.add_user_to_project( - self.session, - project=project, - new_user='pingou', - user='foo', - access='commit' + self.expect_info_msg("Committer push to unprotected") + + +class DistGitAuthTestsFedora(DistGitAuthTests): + dga_config = { + 'PR_ONLY': False, + 'ACL_BLOCK_UNSPECIFIED': False, + 'BLACKLIST_RES': ['refs/heads/c[0-9]+.*'], + 'UNSPECIFIED_BLACKLIST_RES': [ + 'refs/heads/f[0-9]+', + ], + 'RCM_GROUP': 'relenggroup', + 'RCM_BRANCHES': ['refs/heads/f[0-9]+'], + 'ACL_PROTECTED_NAMESPACES': ['rpms', 'modules', 'container'], + 'PDC_URL': 'invalid://', + } + + def test_protected_blacklisted_ref(self): + project = self.create_namespaced_project('rpms', 'test') + + self.assertFalse( + self.dga.check_acl( + self.session, + project=project, + username="pingou", + refname="refs/heads/c7", + pull_request=None, + repodir=None, + repotype='main', + revfrom=None, + revto=None, + is_internal=False, + ) ) - self.assertEqual(msg, 'User added') - self.session.commit() - print("Rewriting %r" % self.configfile) - project = pagure.lib._get_project(self.session, 'test') - dist_git_auth.DistGitoliteAuth.write_gitolite_acls( - self.session, - configfile=self.configfile, - project=project + self.expect_info_msg("Ref refs/heads/c7 is blocked") + + def test_protected_rcm(self): + project = self.create_namespaced_project('rpms', 'test') + + self.assertTrue( + self.dga.check_acl( + self.session, + project=project, + username="releng", + refname="refs/heads/f27", + pull_request=None, + repodir=None, + repotype='main', + revfrom=None, + revto=None, + is_internal=False, + ) ) - print("Checking the contents of %r" % self.configfile) - with open(self.configfile, 'r') as f: - contents = f.read() - - expected = '''repo test2 - RW = releng - R = @all - RWC master = pingou - RWC master = @provenpackager - RWC f9000 = pingou - RWC f9000 = @provenpackager - - f[0-9][0-9] = @all - - epel[0-9] = @all - - epel[0-9][0-9] = @all - - el[0-9] = @all - - olpc[0-9] = @all - RWC = @provenpackager - RWC = pingou - -repo requests/test2 - RWC = pingou - -repo somenamespace/test3 - RW = releng - R = @all - RWC master = pingou - RWC master = @provenpackager - RWC f9000 = pingou - RWC f9000 = @provenpackager - - f[0-9][0-9] = @all - - epel[0-9] = @all - - epel[0-9][0-9] = @all - - el[0-9] = @all - - olpc[0-9] = @all - RWC = @provenpackager - RWC = pingou - -repo requests/somenamespace/test3 - RWC = pingou - -repo test - RW = releng - R = @all - RWC master = foo pingou - RWC master = @provenpackager - RWC f9000 = foo pingou - RWC f9000 = @provenpackager - - f[0-9][0-9] = @all - - epel[0-9] = @all - - epel[0-9][0-9] = @all - - el[0-9] = @all - - olpc[0-9] = @all - RWC = @provenpackager - RWC = foo pingou - -repo requests/test - RWC = foo pingou - -# end of body''' - self.assertMultiLineEqual(expected, contents.strip()) - - def test_get_supported_branches(self): - """ Test for real what is returned by PDC. """ - expected = ['master', 'f27', 'f26', 'f25', 'el6'] - actual = dist_git_auth.get_supported_branches('rpms', 'nethack') - self.assertEquals(set(actual), set(expected)) - - @mock.patch('dist_git_auth.get_supported_branches') - def test_write_gitolite_acls_test_project_w_group( - self, get_supported_branches): - """ Test updating the gitolite configuration file for just one - project (project == a pagure.lib.model.Project). + self.expect_info_msg("RCM push") + + @patch_pdc({"rpm/test": {"f26": False, "f27": True}}) + def test_protected_unsupported_branch(self): + project = self.create_namespaced_project('rpms', 'test') + + self.assertFalse( + self.dga.check_acl( + self.session, + project=project, + username="pingou", + refname="refs/heads/f26", + pull_request=None, + repodir=None, + repotype='main', + revfrom=None, + revto=None, + is_internal=False, + ) + ) - """ + self.expect_info_msg("Branch refs/heads/f26 is unsupported") + + @patch_pdc({"rpm/test": {"f26": False, "f27": True}}) + def test_protected_supported_branch_committer(self): + project = self.create_namespaced_project('rpms', 'test') + + self.assertTrue( + self.dga.check_acl( + self.session, + project=project, + username="pingou", + refname="refs/heads/f27", + pull_request=None, + repodir=None, + repotype='main', + revfrom=None, + revto=None, + is_internal=False, + ) + ) - get_supported_branches.return_value = ['master', 'f9000'] - self.test_write_gitolite_acls() + self.expect_info_msg("Branch refs/heads/f27 is supported") + + @patch_pdc({"rpm/test": {"f26": False, "f27": True}}) + def test_protected_supported_branch_non_committer(self): + project = self.create_namespaced_project('rpms', 'test') + + self.assertFalse( + self.dga.check_acl( + self.session, + project=project, + username="foo", + refname="refs/heads/f27", + pull_request=None, + repodir=None, + repotype='main', + revfrom=None, + revto=None, + is_internal=False, + ) + ) - print("Modifying the test project so the output differs.") - project = pagure.lib._get_project(self.session, 'test') - project.user_id = 2 - self.session.add(project) - self.session.commit() + self.expect_info_msg("Branch refs/heads/f27 is supported") + + @patch_pdc({"rpm/test": {"f26": False, "f27": True}}) + def test_protected_unspecified_branch_blacklisted(self): + project = self.create_namespaced_project('rpms', 'test') + + self.assertFalse( + self.dga.check_acl( + self.session, + project=project, + username="pingou", + refname="refs/heads/f28", + pull_request=None, + repodir=None, + repotype='main', + revfrom=None, + revto=None, + is_internal=False, + ) + ) - # Add a group to a project and someone to this group - project = pagure.lib._get_project(self.session, 'test') - msg = pagure.lib.add_group_to_project( - session=self.session, - project=project, - new_group='test_grp', - user='pingou', - access='admin', - create=True, - is_admin=True) - self.assertEqual(msg, 'Group added') - grp = pagure.lib.search_groups(self.session, group_name='test_grp') - msg = pagure.lib.add_user_to_group( - session=self.session, - username='pingou', - group=grp, - user='pingou', - is_admin=False) - self.session.commit() + self.expect_info_msg("Unspecified ref refs/heads/f28 is blocked") + + @patch_pdc({"rpm/test": {"f26": False, "f27": True}}) + def test_protected_unspecified_branch_normal_committer(self): + project = self.create_namespaced_project('rpms', 'test') + + self.assertTrue( + self.dga.check_acl( + self.session, + project=project, + username="pingou", + refname="refs/heads/mywip", + pull_request=None, + repodir=None, + repotype='main', + revfrom=None, + revto=None, + is_internal=False, + ) + ) - print("Rewriting %r" % self.configfile) - project = pagure.lib._get_project(self.session, 'test') - dist_git_auth.DistGitoliteAuth.write_gitolite_acls( - self.session, - configfile=self.configfile, - project=project + self.expect_info_msg("Unspecified branch push") + + @patch_pdc({"rpm/test": {"f26": False, "f27": True}}) + def test_protected_unspecified_branch_normal_non_committer(self): + project = self.create_namespaced_project('rpms', 'test') + + self.assertFalse( + self.dga.check_acl( + self.session, + project=project, + username="foo", + refname="refs/heads/mywip", + pull_request=None, + repodir=None, + repotype='main', + revfrom=None, + revto=None, + is_internal=False, + ) ) - print("Checking the contents of %r" % self.configfile) - with open(self.configfile, 'r') as f: - contents = f.read() - - expected = '''@test_grp = pingou -# end of groups - -repo test2 - RW = releng - R = @all - RWC master = pingou - RWC master = @provenpackager - RWC f9000 = pingou - RWC f9000 = @provenpackager - - f[0-9][0-9] = @all - - epel[0-9] = @all - - epel[0-9][0-9] = @all - - el[0-9] = @all - - olpc[0-9] = @all - RWC = @provenpackager - RWC = pingou - -repo requests/test2 - RWC = pingou - -repo somenamespace/test3 - RW = releng - R = @all - RWC master = pingou - RWC master = @provenpackager - RWC f9000 = pingou - RWC f9000 = @provenpackager - - f[0-9][0-9] = @all - - epel[0-9] = @all - - epel[0-9][0-9] = @all - - el[0-9] = @all - - olpc[0-9] = @all - RWC = @provenpackager - RWC = pingou - -repo requests/somenamespace/test3 - RWC = pingou - -repo test - RW = releng - R = @all - RWC master = foo - RWC master = @test_grp @provenpackager - RWC f9000 = foo - RWC f9000 = @test_grp @provenpackager - - f[0-9][0-9] = @all - - epel[0-9] = @all - - epel[0-9][0-9] = @all - - el[0-9] = @all - - olpc[0-9] = @all - RWC = @test_grp @provenpackager - RWC = foo - -repo requests/test - RWC = @test_grp - RWC = foo - -# end of body''' - self.assertMultiLineEqual(expected, contents.strip()) - - @mock.patch('dist_git_auth.get_supported_branches') - def test_write_gitolite_acls_fork( - self, get_supported_branches): - """ Test updating the gitolite configuration file when forking a - project. + self.expect_info_msg("Unspecified branch push") - """ - get_supported_branches.return_value = ['master', 'f9000'] - self.test_write_gitolite_acls() - - print("Forking the test project.") - project = pagure.lib._get_project(self.session, 'test') - pagure.lib.fork_project( - session=self.session, - user='pingou', - repo=project, - gitfolder=self.path, - docfolder=None, - ticketfolder=None, - requestfolder=None) - - print("Rewriting %r" % self.configfile) - dist_git_auth.DistGitoliteAuth.write_gitolite_acls( - self.session, - configfile=self.configfile, - project=-1 +class DistGitAuthTestsCentOS(DistGitAuthTests): + dga_config = { + 'PR_ONLY': False, + 'ACL_BLOCK_UNSPECIFIED': True, + 'BLACKLIST_RES': ['refs/heads/f[0-9]+.*'], + 'RCM_GROUP': 'relenggroup', + 'RCM_BRANCHES': ['refs/heads/c[0-9]+'], + 'SUPPORTED_SIGS': ['sig-core'], + 'SIG_PREFIXES': ['refs/heads/c7'], + 'ACL_PROTECTED_NAMESPACES': ['rpms'], + } + + def setUp(self): + super(DistGitAuthTestsCentOS, self).setUp() + + # Create an RCM user/group + arrfab = pagure.lib.model.User( + user='arrfab', + fullname='Fabian Arriton', + token='aaabbbcd', + default_email='arrfab@local.local', ) + self.session.add(arrfab) + self.session.flush() + sigcore = pagure.lib.model.PagureGroup( + group_name='sig-core', + group_type='user', + display_name='Core SIG group', + user_id=arrfab.id, + ) + self.session.add(sigcore) + self.session.flush() + arrfab.group_objs.append(sigcore) + self.session.commit() - print("Checking the contents of %r" % self.configfile) - with open(self.configfile, 'r') as f: - contents = f.read() - - expected = '''repo test - RW = releng - R = @all - RWC master = pingou - RWC master = @provenpackager - RWC f9000 = pingou - RWC f9000 = @provenpackager - - f[0-9][0-9] = @all - - epel[0-9] = @all - - epel[0-9][0-9] = @all - - el[0-9] = @all - - olpc[0-9] = @all - RWC = @provenpackager - RWC = pingou - -repo requests/test - RWC = pingou - -repo test2 - RW = releng - R = @all - RWC master = pingou - RWC master = @provenpackager - RWC f9000 = pingou - RWC f9000 = @provenpackager - - f[0-9][0-9] = @all - - epel[0-9] = @all - - epel[0-9][0-9] = @all - - el[0-9] = @all - - olpc[0-9] = @all - RWC = @provenpackager - RWC = pingou - -repo requests/test2 - RWC = pingou - -repo somenamespace/test3 - RW = releng - R = @all - RWC master = pingou - RWC master = @provenpackager - RWC f9000 = pingou - RWC f9000 = @provenpackager - - f[0-9][0-9] = @all - - epel[0-9] = @all - - epel[0-9][0-9] = @all - - el[0-9] = @all - - olpc[0-9] = @all - RWC = @provenpackager - RWC = pingou - -repo requests/somenamespace/test3 - RWC = pingou - -repo forks/pingou/test - RW = releng - R = @all - RW+C = pingou - -repo requests/forks/pingou/test - RW+C = pingou - -# end of body''' - self.assertMultiLineEqual(expected, contents.strip()) - - @mock.patch('dist_git_auth.get_supported_branches') - def test_write_gitolite_acls_rpms_firefox(self, get_supported_branches): - """ Test generating the entire gitolite configuration file - with the firefox project in the rpms namespace (ie a project not - allowing provenpackager access). + def test_protected_blacklisted_ref(self): + project = self.create_namespaced_project('rpms', 'test') + + self.assertFalse( + self.dga.check_acl( + self.session, + project=project, + username="pingou", + refname="refs/heads/f27", + pull_request=None, + repodir=None, + repotype='main', + revfrom=None, + revto=None, + is_internal=False, + ) + ) - """ - get_supported_branches.return_value = ['master', 'f9000'] - print("Initializing DB.") - item = pagure.lib.model.Project( - user_id=1, # pingou - name='firefox', - description='The firefox project', - hook_token='aaabbbeee', - namespace='rpms', + self.expect_info_msg("Ref refs/heads/f27 is blocked") + + def test_protected_rcm(self): + project = self.create_namespaced_project('rpms', 'test') + + self.assertTrue( + self.dga.check_acl( + self.session, + project=project, + username="releng", + refname="refs/heads/c7", + pull_request=None, + repodir=None, + repotype='main', + revfrom=None, + revto=None, + is_internal=False, + ) ) - self.session.add(item) - self.session.commit() - print("Generating %r" % self.configfile) - dist_git_auth.DistGitoliteAuth.write_gitolite_acls( - self.session, - configfile=self.configfile, - project=-1) - - print("Checking the contents of %r" % self.configfile) - with open(self.configfile, 'r') as f: - contents = f.read() - expected = """repo rpms/firefox - RW = releng - R = @all - RWC master = pingou - RWC f9000 = pingou - - f[0-9][0-9] = @all - - epel[0-9] = @all - - epel[0-9][0-9] = @all - - el[0-9] = @all - - olpc[0-9] = @all - RWC = pingou - -repo requests/rpms/firefox - RWC = pingou - -# end of body -""" - self.assertMultiLineEqual(contents.strip(), expected.strip()) - - @mock.patch('dist_git_auth.get_supported_branches') - def test_write_gitolite_acls_firefox(self, get_supported_branches): - """ Test generating the entire gitolite configuration file - with the firefox project. + self.expect_info_msg("RCM push") + + def test_protected_sig_sig_member(self): + project = self.create_namespaced_project('rpms', 'test') + + self.assertTrue( + self.dga.check_acl( + self.session, + project=project, + username="arrfab", + refname="refs/heads/c7-sig-core-test", + pull_request=None, + repodir=None, + repotype='main', + revfrom=None, + revto=None, + is_internal=False, + ) + ) - """ - get_supported_branches.return_value = ['master', 'f9000'] - print("Initializing DB.") - item = pagure.lib.model.Project( - user_id=1, # pingou - name='firefox', - description='The firefox project', - hook_token='aaabbbeee', - namespace=None, + self.expect_info_msg("SIG push") + + def test_protected_sig_no_sig_member(self): + project = self.create_namespaced_project('rpms', 'test') + + self.assertFalse( + self.dga.check_acl( + self.session, + project=project, + username="pingou", + refname="refs/heads/c7-sig-core-test", + pull_request=None, + repodir=None, + repotype='main', + revfrom=None, + revto=None, + is_internal=False, + ) ) - self.session.add(item) - self.session.commit() - print("Generating %r" % self.configfile) - dist_git_auth.DistGitoliteAuth.write_gitolite_acls( - self.session, - configfile=self.configfile, - project=-1) - - print("Checking the contents of %r" % self.configfile) - with open(self.configfile, 'r') as f: - contents = f.read() - expected = """repo firefox - RW = releng - R = @all - RWC master = pingou - RWC master = @provenpackager - RWC f9000 = pingou - RWC f9000 = @provenpackager - - f[0-9][0-9] = @all - - epel[0-9] = @all - - epel[0-9][0-9] = @all - - el[0-9] = @all - - olpc[0-9] = @all - RWC = @provenpackager - RWC = pingou - -repo requests/firefox - RWC = pingou - -# end of body -""" - self.assertMultiLineEqual(contents.strip(), expected.strip()) + self.expect_info_msg("Access to namespace rpms is restricted") + + def test_protected_sig_sig_member_no_sig_branch(self): + project = self.create_namespaced_project('rpms', 'test') + + self.assertFalse( + self.dga.check_acl( + self.session, + project=project, + username="arrfab", + refname="refs/heads/c7", + pull_request=None, + repodir=None, + repotype='main', + revfrom=None, + revto=None, + is_internal=False, + ) + ) + + self.expect_info_msg("Access to namespace rpms is restricted") diff --git a/pagure-dist-git.spec b/pagure-dist-git.spec index a161013..6bd9199 100644 --- a/pagure-dist-git.spec +++ b/pagure-dist-git.spec @@ -1,9 +1,10 @@ # Python3 packaging is turned off until pagure itself is ported to python3. -%global with_python3 0 +%global with_python3 1 # Current EL releases & older Fedora use "python-*" %if 0%{?el6} || 0%{?el7} || 0%{?fedora} < 25 %define py_prefix python +%global with_python3 0 %if 0%{?el6} || 0%{?el7} BuildRequires: python-devel %else @@ -19,10 +20,10 @@ BuildRequires: python2-devel %{!?_licensedir: %global license %%doc} %global modname pagure-dist-git -%global sum Pagure gitolite plugin for Fedora's dist-git setup. +%global sum Pagure Git auth backend for Fedora and CentOS dist-git setups Name: pagure-dist-git -Version: 0.12 +Version: 1.0 Release: 1%{?dist} Summary: %{sum} @@ -30,52 +31,47 @@ License: GPLv2+ URL: http://pypi.python.org/pypi/pagure-dist-git Source0: https://pypi.io/packages/source/p/%{modname}/%{modname}-%{version}.tar.gz BuildArch: noarch +# https://fedoraproject.org/wiki/Packaging:Guidelines#Noarch_with_Unported_Dependencies +ExclusiveArch: x86_64 noarch %description -Since 3.0 pagure offers a way to customize the creation and compilation the -of the gitolite configuration file. - -This project hosts the logic to generate gitolite's configuration file for -dist-git which has a different access model than regular projects on pagure -(for example, forced pushed is forbidden). +This implements access control list checks for Fedora and CentOS dist-git. -%package -n python2-%{modname} -Summary: Pagure gitolite plugin for Fedora's dist-git setup. +%package -n %{py_prefix}-%{modname} +Summary: Pagure Git auth backend for Fedora and CentOS dist-git %{?python_provide:%python_provide python2-%{modname}} BuildRequires: %{py_prefix}-devel BuildRequires: %{py_prefix}-setuptools +# For tests +BuildRequires: %{py_prefix}-mock +BuildRequires: %{py_prefix}-pdc-client +BuildRequires: %{py_prefix}-nose +BuildRequires: pagure >= 5.1 -Requires: %{py_prefix}-pdc-client -Requires: pagure >= 3.90 +Requires: pagure >= 5.1 -%description -n python2-%{modname} -Since 3.0 pagure offers a way to customize the creation and compilation the -of the gitolite configuration file. - -This project hosts the logic to generate gitolite's configuration file for -dist-git which has a different access model than regular projects on pagure -(for example, forced pushed is forbidden). +%description -n %{py_prefix}-%{modname} +This implements access control list checks for Fedora and CentOS dist-git. %if 0%{?with_python3} %package -n python3-%{modname} -Summary: Pagure gitolite plugin for Fedora's dist-git setup. +Summary: Pagure Git auth backend for Fedora and CentOS dist-git %{?python_provide:%python_provide python3-%{modname}} BuildRequires: python3-devel BuildRequires: python3-setuptools +# For tests +BuildRequires: python3-mock +BuildRequires: python3-pdc-client +BuildRequires: python3-nose +BuildRequires: pagure >= 5.1 -Requires: python3-pdc-client -Requires: python3-pagure>=3.90 +Requires: python3-pagure >= 5.1 %description -n python3-%{modname} -Since 3.0 pagure offers a way to customize the creation and compilation the -of the gitolite configuration file. - -This project hosts the logic to generate gitolite's configuration file for -dist-git which has a different access model than regular projects on pagure -(for example, forced pushed is forbidden). +This implements access control list checks for Fedora and CentOS dist-git. %endif %prep @@ -93,32 +89,24 @@ dist-git which has a different access model than regular projects on pagure %py3_install %endif -# Install the custom template/theme -mkdir -p $RPM_BUILD_ROOT/%{_datadir}/pagure_dist_git/template/ -install -p -m 644 template/*.html $RPM_BUILD_ROOT/%{_datadir}/pagure_dist_git/template/ - -# Install the customized static files or our own -mkdir -p $RPM_BUILD_ROOT/%{_datadir}/pagure_dist_git/static/ -install -p -m 644 static/pagure-logo.png $RPM_BUILD_ROOT/%{_datadir}/pagure_dist_git/static/ - # Install the different cron job scripts mkdir -p $RPM_BUILD_ROOT/%{_libexecdir}/pagure-dist-git/ install -p -m 644 scripts/*.py $RPM_BUILD_ROOT/%{_libexecdir}/pagure-dist-git/ -# The tests require network access, so don't run them. -#%%check -#%%{__python2} setup.py test -#%%if 0%%{?with_python3} -#%%{__python3} setup.py test -#%%endif +%check +# These tests don't currently pass because Pagure doesn't ship its testsuite +exit 0 +nosetests -v +%if 0%{?with_python3} +nosetests-3 -v +%endif -%files -n python2-%{modname} +%files -n %{py_prefix}-%{modname} %doc README.rst %license LICENSE %{python2_sitelib}/dist_git_auth.py* %{python2_sitelib}/pagure_dist_git-%{version}* -%{_datadir}/pagure_dist_git/ %{_libexecdir}/pagure-dist-git/ %if 0%{?with_python3} @@ -126,13 +114,17 @@ install -p -m 644 scripts/*.py $RPM_BUILD_ROOT/%{_libexecdir}/pagure-dist-git/ %doc README.rst %license LICENSE %{python3_sitelib}/dist_git_auth.py* +%{python3_sitelib}/__pycache__/* %{python3_sitelib}/pagure_dist_git-%{version}* -%{_datadir}/pagure_dist_git/ %{_libexecdir}/pagure-dist-git/ %endif %changelog +* Tue Oct 09 2018 Patrick Uiterwijk - 1.0-1 +- Rewrote to Dynamic auth backend system (new in Pagure 5.0) +- Merged CentOS ACL checks + * Mon Apr 23 2018 Pierre-Yves Chibon - 0.12-1 - Update to 0.12 - Add namespace to all the url_for() calls diff --git a/setup.py b/setup.py index 910590d..bec67f5 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,6 @@ long_description = long_description.split('split here', 1)[1] f.close() install_requires = [ - 'pdc_client', 'pagure', ] tests_require = [ @@ -16,8 +15,8 @@ tests_require = [ setup( name='pagure-dist-git', - version='0.12', - description="Pagure gitolite plugin for Fedora's dist-git setup.", + version='1.0', + description="Pagure Git auth backend for Fedora and CentOS dist-git", long_description=long_description, author='Pierre-Yves Chibon', author_email='pingou@fedoraproject.org', @@ -32,6 +31,6 @@ setup( zip_safe=False, entry_points=""" [pagure.git_auth.helpers] - distgit = dist_git_auth:DistGitoliteAuth + distgit = dist_git_auth:DistGitAuth """, )