def auth_flow( self, request: httpx.Request ) -> typing.Generator[httpx.Request, httpx.Response, None]: token = self.get_access_token() if token: request.headers["Authorization"] = f"token {token}" response = yield request if response.status_code != 401: # due to access_token return with self.response_body_read(): auth_response = yield self.build_access_token_request() if auth_response.status_code == 401: # due to jwt auth_response = yield self.build_access_token_request( force=True) if auth_response.status_code == 404: raise exceptions.MergifyNotInstalled() elif auth_response.status_code == 403: error_message = auth_response.json()["message"] if "This installation has been suspended" in error_message: LOG.debug( "Mergify installation suspended", gh_owner=self._owner_login, error_message=error_message, ) raise exceptions.MergifyNotInstalled() http.raise_for_status(auth_response) token = self._set_access_token(auth_response.json()) request.headers["Authorization"] = f"token {token}" yield request
async def _retrieve_subscription_from_db( cls: typing.Type[SubscriptionT], redis: utils.RedisCache, owner_id: int ) -> SubscriptionT: print(config.SUBSCRIPTION_BASE_URL) print(f"{config.SUBSCRIPTION_BASE_URL}/on-premise/subscription/{owner_id}") async with http.AsyncClient() as client: try: resp = await client.get( f"{config.SUBSCRIPTION_BASE_URL}/on-premise/subscription/{owner_id}", headers={"Authorization": f"token {config.SUBSCRIPTION_TOKEN}"}, ) except http.HTTPUnauthorized: LOG.critical( "The SUBSCRIPTION_TOKEN is invalid, the subscription can't be checked" ) raise exceptions.MergifyNotInstalled() except http.HTTPForbidden: LOG.critical( "The subscription attached to SUBSCRIPTION_TOKEN is not valid" ) raise exceptions.MergifyNotInstalled() else: sub = resp.json() if not sub["subscription_active"]: LOG.critical( "The subscription attached to SUBSCRIPTION_TOKEN is not active" ) raise exceptions.MergifyNotInstalled() return cls.from_dict(redis, owner_id, sub)
def auth_flow(self, request): if self.installation is None: with self.response_body_read(): installation_response = yield self.build_installation_request() if installation_response.status_code == 401: # due to jwt installation_response = yield self.build_installation_request( force=True ) if installation_response.is_redirect: installation_response = yield self.build_installation_request( url=installation_response.headers["Location"], ) if installation_response.status_code == 404: LOG.debug( "Mergify not installed", gh_owner=self.owner, error_message=installation_response.json()["message"], ) raise exceptions.MergifyNotInstalled() http.raise_for_status(installation_response) self._set_installation(installation_response) token = self._get_access_token() if token: request.headers["Authorization"] = f"token {token}" response = yield request if response.status_code != 401: # due to access_token return with self.response_body_read(): auth_response = yield self.build_access_token_request() if auth_response.status_code == 401: # due to jwt auth_response = yield self.build_access_token_request(force=True) if auth_response.status_code == 403: error_message = auth_response.json()["message"] if "This installation has been suspended" in error_message: LOG.debug( "Mergify installation suspended", gh_owner=self.owner, error_message=error_message, ) raise exceptions.MergifyNotInstalled() http.raise_for_status(auth_response) token = self._set_access_token(auth_response.json()) request.headers["Authorization"] = f"token {token}" yield request
def get_installation_by_id(self, installation_id): try: return self._get_installation( f"/app/installations/{installation_id}") except httpx.HTTPNotFound as e: LOG.debug( "mergify not installed", installation_id=installation_id, error_message=e.message, ) raise exceptions.MergifyNotInstalled()
async def _retrieve_subscription_from_db(cls: typing.Type[SubscriptionT], redis: utils.RedisCache, owner_id: int) -> SubscriptionT: async with dashboard.AsyncDashboardOnPremiseClient() as client: try: resp = await client.get(f"/on-premise/subscription/{owner_id}") except http.HTTPUnauthorized: LOG.critical( "The SUBSCRIPTION_TOKEN is invalid, the subscription can't be checked" ) raise exceptions.MergifyNotInstalled() except http.HTTPForbidden: LOG.critical( "The subscription attached to SUBSCRIPTION_TOKEN is not valid" ) raise exceptions.MergifyNotInstalled() else: sub = resp.json() return cls.from_dict(redis, owner_id, sub)
async def _retrieve_subscription_from_db(cls: typing.Type[SubscriptionT], redis: utils.RedisCache, owner_id: int) -> SubscriptionT: async with dashboard.AsyncDashboardSaasClient() as client: try: resp = await client.get(f"/engine/subscription/{owner_id}") except http.HTTPNotFound: raise exceptions.MergifyNotInstalled() else: sub = resp.json() return cls.from_dict(redis, owner_id, sub)
async def get_installation_from_id(installation_id): url = f"{config.GITHUB_API_URL}/app/installations/{installation_id}" async with http.AsyncClient(auth=GithubBearerAuth(), **http.DEFAULT_CLIENT_OPTIONS) as client: try: installation = (await client.get(url)).json() permissions_need_to_be_updated(installation) return installation except http.HTTPNotFound as e: LOG.debug( "Mergify not installed", error_message=e.message, ) raise exceptions.MergifyNotInstalled()
def permissions_need_to_be_updated(installation): expected_permissions = EXPECTED_MINIMAL_PERMISSIONS[installation["target_type"]] for perm_name, perm_level in expected_permissions.items(): if installation["permissions"].get(perm_name) != perm_level: LOG.debug( "The Mergify installation doesn't have the required permissions", gh_owner=installation["account"]["login"], permissions=installation["permissions"], ) # FIXME(sileht): Looks like ton of people have not all permissions # Or this is buggy, so disable it for now. if perm_name in ["checks", "pull_requests", "contents"]: raise exceptions.MergifyNotInstalled() return True return False
async def _retrieve_subscription_from_db(cls: typing.Type[SubscriptionT], redis: utils.RedisCache, owner_id: int) -> SubscriptionT: async with http.AsyncClient() as client: try: resp = await client.get( f"{config.SUBSCRIPTION_BASE_URL}/engine/subscription/{owner_id}", auth=(config.OAUTH_CLIENT_ID, config.OAUTH_CLIENT_SECRET), ) except http.HTTPNotFound: raise exceptions.MergifyNotInstalled() else: sub = resp.json() return cls.from_dict(redis, owner_id, sub)
async def get_installation(account): owner = account["login"] account_type = "users" if account["type"].lower() == "user" else "orgs" url = f"{config.GITHUB_API_URL}/{account_type}/{owner}/installation" async with http.AsyncClient(auth=GithubBearerAuth(), **http.DEFAULT_CLIENT_OPTIONS) as client: try: installation = (await client.get(url)).json() permissions_need_to_be_updated(installation) return installation except http.HTTPNotFound as e: LOG.debug( "Mergify not installed", gh_owner=owner, error_message=e.message, ) raise exceptions.MergifyNotInstalled()
async def get_installation_from_login( login: github_types.GitHubLogin, ) -> github_types.GitHubInstallation: async with AsyncGithubClient(auth=github_app.GithubBearerAuth()) as client: try: return typing.cast( github_types.GitHubInstallation, await client.item( f"{config.GITHUB_REST_API_URL}/users/{login}/installation" ), ) except http.HTTPNotFound as e: LOG.debug( "Mergify not installed", gh_owner=login, error_message=e.message, ) raise exceptions.MergifyNotInstalled()
def get_installation(self, owner, repo=None, account_type=None): if not account_type and not repo: raise RuntimeError("repo or account_type must be passed") if repo: url = f"/repos/{owner}/{repo}/installation" else: account_type = "users" if account_type.lower( ) == "user" else "orgs" url = f"/{account_type}/{owner}/installation" try: return self._get_installation(url) except httpx.HTTPNotFound as e: LOG.debug( "mergify not installed", gh_owner=owner, gh_repo=repo, error_message=e.message, ) raise exceptions.MergifyNotInstalled()
def get_installation(self, owner, repo=None, account_type=None): if not account_type and not repo: raise RuntimeError("repo or account_type must be passed") if repo: url = f"/repos/{owner}/{repo}/installation" else: account_type = "users" if account_type.lower( ) == "user" else "orgs" url = f"/{account_type}/{owner}/installation" try: installation = self.get(url).json() except httpx.HTTPNotFound as e: LOG.warning( "mergify not installed", gh_owner=owner, gh_repo=repo, error_message=e.message, ) raise exceptions.MergifyNotInstalled() expected_permissions = EXPECTED_MINIMAL_PERMISSIONS[ installation["target_type"]] for perm_name, perm_level in expected_permissions.items(): if installation["permissions"].get(perm_name) != perm_level: LOG.warning( "mergify installation doesn't have required permissions", gh_owner=owner, gh_repo=repo, permissions=installation["permissions"], ) # FIXME(sileht): Looks like ton of people have not all permissions # Or this is buggy, so disable it for now. # raise exceptions.MergifyNotInstalled() return installation