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
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) ]