Re: [Launchpad-reviewers] [Merge] lp:~twom/launchpad/rework-git-permissions-for-shadowing into lp:launchpad

2018-10-18 Thread Colin Watson
Review: Needs Fixing



Diff comments:

> 
> === modified file 'lib/lp/code/interfaces/gitrule.py'
> --- lib/lp/code/interfaces/gitrule.py 2018-10-16 15:29:37 +
> +++ lib/lp/code/interfaces/gitrule.py 2018-10-18 13:49:45 +
> @@ -71,6 +71,16 @@
>  
>  grants = Attribute("The access grants for this rule.")
>  
> +def findRuleGrantsByGrantee(grantee):
> +"""Find the grants for a grantee applied to this repository.
> +
> +:param grantee: The Person affected
> +"""
> +
> +def findRuleGrantsForRepositoryOwner():
> +"""Find the grants of type REPOSITORY_OWNER applied to this 
> repository.
> +"""

s/this repository/this rule/ on both these docstrings, if you're leaving them 
here.  (But see below; I think it might be better to move this back to 
IGitRepository.)

> +
>  
>  class IGitRuleEditableAttributes(Interface):
>  """`IGitRule` attributes that can be edited.
> 
> === modified file 'lib/lp/code/xmlrpc/git.py'
> --- lib/lp/code/xmlrpc/git.py 2018-10-17 10:09:33 +
> +++ lib/lp/code/xmlrpc/git.py 2018-10-18 13:49:45 +
> @@ -414,3 +418,70 @@
>  self._listRefRules,
>  translated_path,
>  )
> +
> +def make_regex(self, pattern):
> +return re.compile(self.glob_to_re(pattern.rstrip(b'\n')))
> +
> +def glob_to_re(self, s):
> +"""Convert a glob to a regular expression.
> +
> +The only wildcard supported is "*", to match any path segment.

This is now any number of characters, rather than just any path segment.

However, should we consider just using the standard library's `fnmatch` 
instead?  That's what I'd specified before I realised that turnip had its own 
implementation, and I think it probably still makes sense: it's easy enough to 
explain, it's a bit more useful, and all its metacharacters are invalid in ref 
names.

> +"""
> +return b'^%s\Z' % (
> +b''.join(b'.*' if c == b'*' else re.escape(c) for c in s))
> +
> +def _find_matching_rules(self, repository, ref_path):
> +"""Find all matching rules for a given ref path"""
> +

Extra blank line.

> +matching_rules = []
> +for rule in repository.rules:
> +regex = self.make_regex(rule.ref_pattern)
> +if regex.match(ref_path):
> +matching_rules.append(rule)
> +return matching_rules
> +
> +def _checkRefPermissions(self, requester, translated_path, ref_paths):
> +repository = removeSecurityProxy(
> +getUtility(IGitLookup).getByHostingPath(translated_path))
> +is_owner = requester.inTeam(repository.owner)
> +result = {}
> +for ref in ref_paths:
> +matching_rules = self._find_matching_rules(repository, ref)
> +if is_owner and not matching_rules:
> +result[ref] = ['create', 'push', 'force_push']
> +continue
> +seen_grantees = []

This should be a set, so that membership checks are cheap.

> +union_permissions = set()
> +for rule in matching_rules:
> +grants = rule.findRuleGrantsByGrantee(requester)
> +if is_owner:
> +owner_grants = rule.findRuleGrantsForRepositoryOwner()
> +grants = grants.union(owner_grants)

This is potentially quite a lot of database queries: it's one or two per 
matching rule per ref being pushed.  Instead, could you collect all the grants 
across the whole repository up-front, organise them into a dict indexed by 
rule, and look them up in that dict as you go?  The DB indexes are arranged 
with the intent of making this an efficient operation.

> +
> +for grant in grants:
> +if (grant.grantee, grant.grantee_type) in seen_grantees:
> +continue
> +permissions = self._buildPermissions(grant)
> +union_permissions.update(permissions)
> +seen_grantees.append(
> +(grant.grantee, grant.grantee_type)
> +)

Could be on one line.

> +
> +owner_grantees = any(x[1] == GitGranteeType.REPOSITORY_OWNER
> + for x in seen_grantees)
> +if is_owner and not owner_grantees:

if is_owner and (None, GitGranteeType.REPOSITORY_OWNER) not in seen_grantees:

> +union_permissions.update(['create', 'push'])
> +
> +sorted_permissions = self._sortPermissions(union_permissions)
> +result[ref] = sorted_permissions
> +return result
> +
> +def checkRefPermissions(self, translated_path, ref_paths, auth_params):
> +""" See `IGitAPI`"""
> +requester_id = auth_params.get("uid")
> +return run_with_login(
> +requester_id,
> +self._checkRefPermissions,
> +translated_path,
> +ref_paths
> +   

[Launchpad-reviewers] [Merge] lp:~wgrant/launchpad/genericise-cron.publish-ppa into lp:launchpad

2018-10-18 Thread William Grant
William Grant has proposed merging 
lp:~wgrant/launchpad/genericise-cron.publish-ppa into lp:launchpad.

Commit message:
Make cron.publish-ppa take distro selection criteria as arguments.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~wgrant/launchpad/genericise-cron.publish-ppa/+merge/357123

This is live on production already.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of 
lp:~wgrant/launchpad/genericise-cron.publish-ppa into lp:launchpad.
=== modified file 'cronscripts/publishing/cron.publish-ppa'
--- cronscripts/publishing/cron.publish-ppa	2014-08-05 10:37:07 +
+++ cronscripts/publishing/cron.publish-ppa	2018-10-19 05:27:09 +
@@ -10,12 +10,8 @@
 
 LPCURRENT=`dirname $0`/../..
 
-# Publish Ubuntu PPAs.
-$LPCURRENT/scripts/process-accepted.py -v --ppa -d ubuntu
-$LPCURRENT/scripts/publish-distro.py -v --ppa -d ubuntu
-$LPCURRENT/scripts/publish-distro.py -v --private-ppa -d ubuntu
-
-# Publish PPAs for other distros.
-$LPCURRENT/scripts/process-accepted.py -v --ppa --all-derived
-$LPCURRENT/scripts/publish-distro.py -v --ppa --all-derived
-$LPCURRENT/scripts/publish-distro.py -v --private-ppa --all-derived
+for DISTRO_ARG in "$@"; do
+  $LPCURRENT/scripts/process-accepted.py -v --ppa $DISTRO_ARG
+  $LPCURRENT/scripts/publish-distro.py -v --ppa $DISTRO_ARG
+  $LPCURRENT/scripts/publish-distro.py -v --private-ppa $DISTRO_ARG
+done

___
Mailing list: https://launchpad.net/~launchpad-reviewers
Post to : launchpad-reviewers@lists.launchpad.net
Unsubscribe : https://launchpad.net/~launchpad-reviewers
More help   : https://help.launchpad.net/ListHelp


[Launchpad-reviewers] [Merge] lp:~twom/launchpad/rework-git-permissions-for-shadowing into lp:launchpad

2018-10-18 Thread Tom Wardill
Tom Wardill has proposed merging 
lp:~twom/launchpad/rework-git-permissions-for-shadowing into lp:launchpad.

Commit message:
Rework git branch permissions to improve shadowing for multiple grants

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~twom/launchpad/rework-git-permissions-for-shadowing/+merge/357091
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of 
lp:~twom/launchpad/rework-git-permissions-for-shadowing into lp:launchpad.
=== modified file 'lib/lp/code/interfaces/gitapi.py'
--- lib/lp/code/interfaces/gitapi.py	2018-09-28 13:53:41 +
+++ lib/lp/code/interfaces/gitapi.py	2018-10-18 13:49:45 +
@@ -73,3 +73,10 @@
 
 :returns: A list of rules for the user in the specified repository
 """
+
+def checkRefPermissions(self, repository, ref_paths, user):
+"""Return a list of ref rules for a `user` in a `repository` that
+match the input refs.
+
+:returns: A list of rules for the user in the specified repository
+"""

=== modified file 'lib/lp/code/interfaces/gitrepository.py'
--- lib/lp/code/interfaces/gitrepository.py	2018-10-16 10:10:10 +
+++ lib/lp/code/interfaces/gitrepository.py	2018-10-18 13:49:45 +
@@ -748,16 +748,6 @@
 :param user: The `IPerson` who is moving the rule.
 """
 
-def findRuleGrantsByGrantee(grantee):
-"""Find the grants for a grantee applied to this repository.
-
-:param grantee: The Person affected
-"""
-
-def findRuleGrantsForRepositoryOwner():
-"""Find the grants of type REPOSITORY_OWNER applied to this repository.
-"""
-
 @export_read_operation()
 @operation_for_version("devel")
 def canBeDeleted():

=== modified file 'lib/lp/code/interfaces/gitrule.py'
--- lib/lp/code/interfaces/gitrule.py	2018-10-16 15:29:37 +
+++ lib/lp/code/interfaces/gitrule.py	2018-10-18 13:49:45 +
@@ -71,6 +71,16 @@
 
 grants = Attribute("The access grants for this rule.")
 
+def findRuleGrantsByGrantee(grantee):
+"""Find the grants for a grantee applied to this repository.
+
+:param grantee: The Person affected
+"""
+
+def findRuleGrantsForRepositoryOwner():
+"""Find the grants of type REPOSITORY_OWNER applied to this repository.
+"""
+
 
 class IGitRuleEditableAttributes(Interface):
 """`IGitRule` attributes that can be edited.

=== modified file 'lib/lp/code/model/gitrepository.py'
--- lib/lp/code/model/gitrepository.py	2018-10-16 10:10:10 +
+++ lib/lp/code/model/gitrepository.py	2018-10-18 13:49:45 +
@@ -72,7 +72,6 @@
 from lp.app.interfaces.services import IService
 from lp.code.enums import (
 BranchMergeProposalStatus,
-GitGranteeType,
 GitObjectType,
 GitRepositoryType,
 )
@@ -1194,20 +1193,6 @@
 return Store.of(self).find(
 GitRuleGrant, GitRuleGrant.repository_id == self.id)
 
-def findRuleGrantsByGrantee(self, grantee):
-"""See `IGitRepository`."""
-clauses = [
-GitRuleGrant.grantee_type == GitGranteeType.PERSON,
-TeamParticipation.person == grantee,
-GitRuleGrant.grantee == TeamParticipation.teamID
-]
-return self.grants.find(*clauses).config(distinct=True)
-
-def findRuleGrantsForRepositoryOwner(self):
-"""See `IGitRepository`."""
-return self.grants.find(
-GitRuleGrant.grantee_type == GitGranteeType.REPOSITORY_OWNER)
-
 def getActivity(self, changed_after=None):
 """See `IGitRepository`."""
 clauses = [GitActivity.repository_id == self.id]

=== modified file 'lib/lp/code/model/gitrule.py'
--- lib/lp/code/model/gitrule.py	2018-10-16 15:29:37 +
+++ lib/lp/code/model/gitrule.py	2018-10-18 13:49:45 +
@@ -54,6 +54,7 @@
 validate_person,
 validate_public_person,
 )
+from lp.registry.model.teammembership import TeamParticipation
 from lp.services.database.constants import (
 DEFAULT,
 UTC_NOW,
@@ -127,6 +128,20 @@
 return Store.of(self).find(
 GitRuleGrant, GitRuleGrant.rule_id == self.id)
 
+def findRuleGrantsByGrantee(self, grantee):
+"""See `IGitRule`."""
+clauses = [
+GitRuleGrant.grantee_type == GitGranteeType.PERSON,
+TeamParticipation.person == grantee,
+GitRuleGrant.grantee == TeamParticipation.teamID
+]
+return self.grants.find(*clauses).config(distinct=True)
+
+def findRuleGrantsForRepositoryOwner(self):
+"""See `IGitRule`."""
+return self.grants.find(
+GitRuleGrant.grantee_type == GitGranteeType.REPOSITORY_OWNER)
+
 def addGrant(self, grantee, grantor, can_create=False, can_push=False,
  can_force_push=False):
 """See `IGitRule`."""

=== modified file 'lib/lp/code/xmlrpc/git.py'
--- lib/lp/code/xmlrpc/git.py	2018-10-17