Exemple #1
0
class Whitelist:
    def __init__(self):
        self.db = PersistentDict(hash_name="whitelist")

    @staticmethod
    def _is_packager(account_login: str) -> bool:
        """
        If GitHub username is same as FAS username this method checks if user is packager.
        User is considered to be packager when he/she has the badge:
         `If you build it... (Koji Success I)`
        :param account_login: str, Github username
        :return: bool
        """

        url = f"https://badges.fedoraproject.org/user/{account_login}/json"
        data = requests.get(url)
        if not data:
            return False
        assertions = data.json().get("assertions")
        if not assertions:
            return False
        for item in assertions:
            if "Succesfully completed a koji build." in item.get(
                    "description"):
                logger.info(f"User: {account_login} is a packager in Fedora!")
                return True
        logger.info(
            f"Cannot verify whether user: {account_login} is a packager in Fedora."
        )
        return False

    def get_account(self, account_name: str) -> Optional[dict]:
        """
        Get selected account from DB, return None if it's not there

        :param account_name: account name for approval
        """
        account = self.db[account_name]
        if not account:
            return None
        # patch status
        db_status = account["status"]
        if db_status.startswith("WhitelistStatus"):
            account["status"] = db_status.split(".", 1)[1]
            self.db[account_name] = account
        return account

    def add_account(self, github_app: InstallationEvent) -> bool:
        """
        Add account to whitelist, if automatic verification of user
        (check if user is packager in fedora) fails, account is still inserted in whitelist
         with status : `waiting`.
         Then a scripts in files/scripts have to be executed for manual approval
        :param github_app: github app installation info
        :return: was the account auto-whitelisted?
        """
        account = self.get_account(github_app.account_login)
        if account:
            # the account is already in DB
            return True
        # we want to verify if user who installed the application is packager
        if Whitelist._is_packager(github_app.sender_login):
            github_app.status = WhitelistStatus.approved_automatically
            self.db[github_app.account_login] = github_app.get_dict()
            logger.info(f"Account {github_app.account_login} whitelisted!")
            return True
        else:
            logger.error(
                "Failed to verify that user is Fedora packager. "
                "This could be caused by different github username than FAS username "
                "or that user is not a packager.")
            github_app.status = WhitelistStatus.waiting
            self.db[github_app.account_login] = github_app.get_dict()
            logger.info(f"Account {github_app.account_login} inserted "
                        f"to whitelist with status: waiting for approval")
            return False

    def approve_account(self, account_name: str) -> bool:
        """
        Approve user manually
        :param account_name: account name for approval
        :return:
        """
        account = self.get_account(account_name) or {}
        account["status"] = WhitelistStatus.approved_manually.value
        self.db[account_name] = account
        logger.info(f"Account {account_name} approved successfully")
        return True

    def is_approved(self, account_name: str) -> bool:
        """
        Check if user is approved in the whitelist
        :param account_name:
        :return:
        """
        if account_name in self.db:
            account = self.get_account(account_name)
            db_status = account["status"]
            s = WhitelistStatus(db_status)
            return (s == WhitelistStatus.approved_automatically
                    or s == WhitelistStatus.approved_manually)
        return False

    def remove_account(self, account_name: str) -> bool:
        """
        Remove account from whitelist.
        :param account_name: github login
        :return:
        """
        if account_name in self.db:
            del self.db[account_name]
            # TODO: delete all artifacts from copr
            logger.info(f"User: {account_name} removed from whitelist!")
            return True
        else:
            logger.info(f"User: {account_name} does not exists!")
            return False

    def accounts_waiting(self) -> list:
        """
        Get accounts waiting for approval
        :return: list of accounts waiting for approval
        """

        return [
            key for (key, item) in self.db.items()
            if WhitelistStatus(item["status"]) == WhitelistStatus.waiting
        ]

    def check_and_report(self, event: Optional[Any],
                         project: GitProject) -> bool:
        """
        Check if account is approved and report status back in case of PR
        :param event: PullRequest and Release TODO: handle more
        :param project: GitProject
        :return:
        """
        account_name = None
        if isinstance(event, PullRequestEvent):
            account_name = event.base_repo_namespace
        if isinstance(event, ReleaseEvent):
            account_name = event.repo_namespace

        if account_name:
            if not self.is_approved(account_name):
                logger.error(
                    f"User {account_name} is not approved on whitelist!")
                # TODO also check blacklist,
                # but for that we need to know who triggered the action
                if event.trigger == JobTriggerType.pull_request:
                    r = BuildStatusReporter(project, event.commit_sha, None)
                    msg = "Account is not whitelisted!"
                    r.report(
                        "failure",
                        msg,
                        url=FAQ_URL,
                        check_name=PRCheckName.get_build_check(),
                    )
                return False

        return True
Exemple #2
0
class Whitelist:
    def __init__(self):
        self.db = PersistentDict(hash_name="whitelist")

    @staticmethod
    def _is_packager(account_login: str) -> bool:
        """
        If GitHub username is same as FAS username this method checks if user is packager.
        User is considered to be packager when he/she has the badge:
         `If you build it... (Koji Success I)`
        :param account_login: str, Github username
        :return: bool
        """

        url = f"https://badges.fedoraproject.org/user/{account_login}/json"
        data = requests.get(url)
        if not data:
            return False
        assertions = data.json().get("assertions")
        if not assertions:
            return False
        for item in assertions:
            if "Succesfully completed a koji build." in item.get(
                    "description"):
                logger.info(f"User: {account_login} is a packager in Fedora!")
                return True
        logger.info(
            f"Cannot verify whether user: {account_login} is a packager in Fedora."
        )
        return False

    def add_account(self, github_app: GithubAppData) -> bool:
        """
        Add account to whitelist, if automatic verification of user
        (check if user is packager in fedora) fails, account is still inserted in whitelist
         with status : `waiting`.
         Then a scripts in files/scripts have to be executed for manual approval
        :param github_app: github app installation info
        :return:
        """
        # we want to verify if user who installed the application is packager
        if Whitelist._is_packager(github_app.sender_login):
            github_app.status = WhitelistStatus.approved_automatically
            self.db[github_app.account_login] = github_app.get_dict()
            logger.info(f"Account {github_app.account_login} whitelisted!")
            return True
        else:
            logger.error(
                "Failed to verify that user is Fedora packager. "
                "This could be caused by different github username than FAS username "
                "or that user is not a packager.")
            github_app.status = WhitelistStatus.waiting
            self.db[github_app.account_login] = github_app.get_dict()
            logger.info(f"Account {github_app.account_login} inserted "
                        f"to whitelist with status: waiting for approval")
            logger.info(self.db)
            return False

    def approve_account(self, account_name: str) -> bool:
        """
        Approve user manually
        :param account_name: account name for approval
        :return:
        """
        account = self.db[account_name] or {}
        account["status"] = str(WhitelistStatus.approved_manually)
        self.db[account_name] = account
        logger.info(f"Account {account_name} approved successfully")
        return True

    def is_approved(self, account_name: str) -> bool:
        """
        Check if user is approved in the whitelist
        :param account_name:
        :return:
        """
        if account_name in self.db:
            if self.db[account_name]["status"] == str(
                    WhitelistStatus.approved_manually
            ) or self.db[account_name]["status"] == str(
                    WhitelistStatus.approved_automatically):
                return True
        return False

    def remove_account(self, account_name: str) -> bool:
        """
        Remove account from whitelist.
        :param account_name: github login
        :return:
        """
        if account_name in self.db:
            del self.db[account_name]
            # TODO: delete all artifacts from copr
            logger.info(f"User: {account_name} removed from whitelist!")
            return True
        else:
            logger.info(f"User: {account_name} does not exists!")
            return False

    def accounts_waiting(self) -> list:
        """
        Get accounts waiting for approval
        :return: list of accounts waiting for approval
        """

        return [
            key for (key, item) in self.db.items()
            if item["status"] == str(WhitelistStatus.waiting)
        ]