def is_approved_child(self, review_request):
        """Check approval for a child review request"""
        if review_request.shipit_count == 0:
            return False, 'A suitable reviewer has not given a "Ship It!"'

        if review_request.issue_open_count > 0:
            return False, 'The review request has open issues.'

        # TODO: Add a check that we have executed a try build of some kind.

        author_mrp = get_profile(review_request.submitter)

        # TODO: Make these "has_..." methods return the set of reviews
        # which match the criteria so we can indicate which reviews
        # actually gave the permission to land.
        if author_mrp.has_scm_ldap_group('scm_level_3'):
            # In the case of a level 3 user we really only care that they've
            # received a single ship-it, which is still current, from any
            # user. If they need to wait for reviews from other people
            # before landing we trust them to wait.
            if not has_valid_shipit(review_request):
                return False, 'A suitable reviewer has not given a "Ship It!"'
        else:
            if not has_l3_shipit(review_request):
                return False, 'A suitable reviewer has not given a "Ship It!"'

        return True
    def is_approved_child(self, review_request):
        """Check approval for a child review request"""
        if review_request.shipit_count == 0:
            return False, 'A suitable reviewer has not given a "Ship It!"'

        if review_request.issue_open_count > 0:
            return False, 'The review request has open issues.'

        # TODO: Add a check that we have executed a try build of some kind.

        author_mrp = get_profile(review_request.submitter)

        # TODO: Make these "has_..." methods return the set of reviews
        # which match the criteria so we can indicate which reviews
        # actually gave the permission to land.
        if author_mrp.has_scm_ldap_group('scm_level_3'):
            # In the case of a level 3 user we really only care that they've
            # received a single ship-it, which is still current, from any
            # user. If they need to wait for reviews from other people
            # before landing we trust them to wait.
            if not has_valid_shipit(review_request):
                return False, 'A suitable reviewer has not given a "Ship It!"'
        else:
            if not has_l3_shipit(review_request):
                return False, 'A suitable reviewer has not given a "Ship It!"'

        return True
    def update(self, request, ldap_username, *args, **kwargs):
        """Associate an ldap username with a user.

        The only users authorized to perform this operation are those with
        the `mozreview.modify_ldap_association` permission. Users are *not*
        allowed to update their own ldap_username association as it
        represents that the Review Board user has been proven to own the ldap
        account.
        """
        logger.info('Request to update ldap association made by user: %s' % (
                    request.user.id))
        if not request.user.has_perm('mozreview.modify_ldap_association'):
            logger.info('Could not update ldap association: permission '
                        'denied for user: %s' % (request.user.id))
            return PERMISSION_DENIED

        try:
            user = resources.user.get_object(request, *args, **kwargs)
        except ObjectDoesNotExist:
            logger.info('Could not update ldap association: target user %s '
                        'does not exist.' % (user))
            return DOES_NOT_EXIST

        mozreview_profile = get_profile(user)
        mozreview_profile.ldap_username = ldap_username
        mozreview_profile.save()

        logger.info('Associating user: %s with ldap_username: %s' % (user,
                    ldap_username))

        return 200, self.create_item_payload(request, user, mozreview_profile)
def has_l3_shipit(review_request):
    """Return whether the review request has received a current L3 ship it.

    A boolean will be returned indicating if the review request has received
    a ship-it from an L3 user that is still valid. In order to be valid the
    ship-it must have been provided after the latest diff has been uploaded.
    """
    diffset_history = review_request.diffset_history

    if not diffset_history:
        # There aren't any published diffs so we should just consider
        # any ship-its meaningless.
        return False

    if not diffset_history.last_diff_updated:
        # Although I'm not certain when this field will be empty
        # it has "blank=true, null=True" - we'll assume there is
        # no published diff.
        return False

    for review in gen_latest_reviews(review_request):
        if not review.ship_it:
            continue
        if get_profile(review.user).has_scm_ldap_group('scm_level_3'):
            return True

    return False
def has_l3_shipit(review_request):
    """Return whether the review request has received a current L3 ship it.

    A boolean will be returned indicating if the review request has received
    a ship-it from an L3 user that is still valid. In order to be valid the
    ship-it must have been provided after the latest diff has been uploaded.
    """
    diffset_history = review_request.diffset_history

    if not diffset_history:
        # There aren't any published diffs so we should just consider
        # any ship-its meaningless.
        return False

    if not diffset_history.last_diff_updated:
        # Although I'm not certain when this field will be empty
        # it has "blank=true, null=True" - we'll assume there is
        # no published diff.
        return False

    for review in gen_latest_reviews(review_request):
        if not review.ship_it:
            continue
        if get_profile(review.user).has_scm_ldap_group("scm_level_3"):
            return True

    return False
    def update(self, request, ldap_username, *args, **kwargs):
        """Associate an ldap username with a user.

        The only users authorized to perform this operation are those with
        the `mozreview.modify_ldap_association` permission. Users are *not*
        allowed to update their own ldap_username association as it
        represents that the Review Board user has been proven to own the ldap
        account.
        """
        logger.info('Request to update ldap association made by user: %s' %
                    (request.user.id))
        if not request.user.has_perm('mozreview.modify_ldap_association'):
            logger.info('Could not update ldap association: permission '
                        'denied for user: %s' % (request.user.id))
            return PERMISSION_DENIED

        try:
            user = resources.user.get_object(request, *args, **kwargs)
        except ObjectDoesNotExist:
            logger.info('Could not update ldap association: target user %s '
                        'does not exist.' % (user))
            return DOES_NOT_EXIST

        mozreview_profile = get_profile(user)
        mozreview_profile.ldap_username = ldap_username
        mozreview_profile.save()

        logger.info('Associating user: %s with ldap_username: %s' %
                    (user, ldap_username))

        return 200, self.create_item_payload(request, user, mozreview_profile)
Exemple #7
0
def associate_employee_ldap(user, ldap_connection=None):
    """Assoicate the user if we find them in the employee LDAP scope.

    For the given user object, find a matching Mozilla employee's
    LDAP address (both the mail and bugzillaEmail LDAP attributes will be
    checked), and associate the user to LDAP.

    Raises an exception if no matches or multiple matches were found.
    Returns the found LDAP username, and a boolean indicating if the user
    was updated.
    """

    from mozreview.models import get_profile
    mozreview_profile = get_profile(user)

    # Don't overwrite existing and valid associations.
    if mozreview_profile.ldap_username and user_exists(
            mozreview_profile.ldap_username, ldap_connection):
        return mozreview_profile.ldap_username, False

    ldap_users = find_employee_ldap(user.email, ldap_connection)

    if not ldap_users:
        raise LDAPAssociationException(
            'Failed to find match for %s' % user.email)

    if len(ldap_users) > 1:
        raise LDAPAssociationException(
            'More than one match for %s' % user.email)

    ldap_username = ldap_users[0]
    updated = False
    if mozreview_profile.ldap_username != ldap_username:
        if mozreview_profile.ldap_username:
            logging.info("Existing ldap association '%s' replaced by '%s'"
                         % (mozreview_profile.ldap_username, ldap_username))
        else:
            logging.info('Associating user: %s with ldap_username: %s'
                         % (user.email, ldap_username))

        mozreview_profile.ldap_username = ldap_username
        mozreview_profile.save()
        updated = True

    return ldap_username, updated
    def get(self, request, *args, **kwargs):
        """Return the ldap association for a particular user."""
        if not self.has_access_permissions(request, *args, **kwargs):
            return PERMISSION_DENIED

        try:
            # Since this resources uri_object_key matches that of the
            # UserResource we should properly query for the requested
            # username.
            user = resources.user.get_object(request, *args, **kwargs)
        except ObjectDoesNotExist:
            # This shouldn't be leaking any information about the existence
            # of users because if they are querying for a user that is not
            # themselves a PERMISSION_DENIED has already been returned.
            #
            # This case should really only happen when a user with the
            # 'mozreview.modify_ldap.association' is querying for a user
            # and they are allowed to know all user existence.
            return DOES_NOT_EXIST

        return 200, self.create_item_payload(request, user, get_profile(user))
    def get(self, request, *args, **kwargs):
        """Return the ldap association for a particular user."""
        if not self.has_access_permissions(request, *args, **kwargs):
            return PERMISSION_DENIED

        try:
            # Since this resources uri_object_key matches that of the
            # UserResource we should properly query for the requested
            # username.
            user = resources.user.get_object(request, *args, **kwargs)
        except ObjectDoesNotExist:
            # This shouldn't be leaking any information about the existence
            # of users because if they are querying for a user that is not
            # themselves a PERMISSION_DENIED has already been returned.
            #
            # This case should really only happen when a user with the
            # 'mozreview.modify_ldap.association' is querying for a user
            # and they are allowed to know all user existence.
            return DOES_NOT_EXIST

        return 200, self.create_item_payload(request, user, get_profile(user))
def associate_employee_ldap(user, ldap_connection=None):
    """Assoicate the user if we find them in the employee LDAP scope.

    For the given user object, find a matching Mozilla employee's
    LDAP address (both the mail and bugzillaEmail LDAP attributes will be
    checked), and associate the user to LDAP.

    Raises an exception if no matches or multiple matches were found.
    Returns the found LDAP username, and a boolean indicating if the user
    was updated.
    """

    from mozreview.models import get_profile
    ldap_users = find_employee_ldap(user.email, ldap_connection)

    if not ldap_users:
        raise LDAPAssociationException(
            'Failed to find match for %s' % user.email)

    if len(ldap_users) > 1:
        raise LDAPAssociationException(
            'More than one match for %s' % user.email)

    ldap_username = ldap_users[0]
    updated = False
    mozreview_profile = get_profile(user)
    if mozreview_profile.ldap_username != ldap_username:
        if mozreview_profile.ldap_username:
            logging.info("Existing ldap association '%s' replaced by '%s'"
                         % (mozreview_profile.ldap_username, ldap_username))
        else:
            logging.info('Associating user: %s with ldap_username: %s'
                         % (user.email, ldap_username))

        mozreview_profile.ldap_username = ldap_username
        mozreview_profile.save()
        updated = True

    return ldap_username, updated
Exemple #11
0
def has_l3_shipit(review_request):
    """Return whether the review request has received a current L3 ship it.

    A boolean will be returned indicating if the review request has received
    a ship-it from an L3 user that is still valid. In order to be valid the
    ship-it must have been provided after the latest diff has been uploaded.
    """
    diffset_history = review_request.diffset_history

    if not diffset_history:
        # There aren't any published diffs so we should just consider
        # any ship-its meaningless.
        return False

    if not diffset_history.last_diff_updated:
        # Although I'm not certain when this field will be empty
        # it has "blank=true, null=True" - we'll assume there is
        # no published diff.
        return False

    for review in gen_latest_reviews(review_request):
        if not review.ship_it:
            continue

        # TODO: We might want to add a required delay between when the
        # diff is posted and when a review is published - this would
        # avoid a malicious user from timing a diff publish immediately
        # before a reviewer publishes a ship-it on the previous diff
        # (Making it look like the ship-it came after the new diff)
        if review.timestamp <= diffset_history.last_diff_updated:
            continue

        if get_profile(review.user).has_scm_ldap_group('scm_level_3'):
            return True

    return False
    def process_request(self, request):
        if not request.user.is_authenticated():
            request.mozreview_profile = None
            return

        request.mozreview_profile = get_profile(request.user)
Exemple #13
0
def post_bugzilla_attachment(bugzilla, bug_id, review_request_draft,
                             review_request):
    # We publish attachments for each commit/child to Bugzilla so that
    # reviewers can easily track their requests.

    # The review request exposes a list of usernames for reviewers. We need
    # to convert these to Bugzilla emails in order to make the request into
    # Bugzilla.
    #
    # It may seem like there is a data syncing problem here where usernames
    # may get out of sync with the reality from Bugzilla. Fortunately,
    # Review Board is smarter than that. Internally, the target_people list
    # is stored with foreign keys into the numeric primary key of the user
    # table. If the RB username changes, this won't impact target_people
    # nor the stored mapping to the numeric Bugzilla ID, which is
    # immutable.
    #
    # But we do have a potential data syncing problem with the stored email
    # address. Review Board's stored email address could be stale. So
    # instead of using it directly, we query Bugzilla and map the stored,
    # immutable numeric Bugzilla userid into an email address. This lookup
    # could be avoided if Bugzilla accepted a numeric userid in the
    # requestee parameter when modifying an attachment.
    reviewers = {}

    for u in review_request_draft.target_people.all():
        bum = BugzillaUserMap.objects.get(user=u)

        user_data = bugzilla.get_user_from_userid(bum.bugzilla_user_id)

        # Since we're making the API call, we might as well ensure the
        # local database is up to date.
        users = get_or_create_bugzilla_users(user_data)
        reviewers[users[0].email] = False

    # TODO: This will require a database query per review request we're
    # publishing, which may cause performance problems. Cache this profile
    # object somewhere.
    submitter_profile = get_profile(review_request.submitter)

    # We will only carry forward ship-it reviews if the submitter
    # of the review request has L3 (They can be trusted to re-request
    # review if required).
    #
    # TODO: We're making an ldap query per review request we're
    # publishing; we should cache the returned value somewhere
    # instead.
    if submitter_profile.has_scm_ldap_group('scm_level_3'):
        last_user = None
        relevant_reviews = review_request.get_public_reviews().order_by(
            'user', '-timestamp')

        for review in relevant_reviews:
            if review.user == last_user:
                # We only care about the most recent review for each
                # particular user.
                continue

            last_user = review.user

            # The last review given by this reviewer had a ship-it, so we
            # will carry their r+ forward. If someone had manually changed
            # their flag on bugzilla, we may be setting it back to r+, but
            # we will consider the manual flag change on bugzilla user
            # error for now.
            if review.ship_it:
                reviewers[last_user.email] = True

    comment = review_request_draft.description

    if (review_request_draft.changedesc and
        review_request_draft.changedesc.text):
        if not comment.endswith('\n'):
            comment += '\n'

        comment += '\n%s' % review_request_draft.changedesc.text

    bugzilla.post_rb_url(bug_id,
                         review_request.id,
                         review_request_draft.summary,
                         comment,
                         get_obj_url(review_request),
                         reviewers)
Exemple #14
0
    def process_request(self, request):
        if not request.user.is_authenticated():
            request.mozreview_profile = None
            return

        request.mozreview_profile = get_profile(request.user)