diff --git a/.env b/.env index 6fd5bba9d..64acb32ac 100644 --- a/.env +++ b/.env @@ -63,3 +63,6 @@ PUBLIC_API_GEO_COUNTRY_QUERY_ENDPOINT="/api/resources/3580bf65-1d11-4574-a2ca-90 #### TCHAP canal variable PUBLIC_CONTACT_URL="https://www.tchap.gouv.fr/#/room/!pwyfzLTDXyMeinVsgL:agent.dinum.tchap.gouv.fr" PUBLIC_CONTACT_EMAIL="equipe-ami@numerique.gouv.fr" + +# Github Personal Access Token to list open PRs +GITHUB_PERSONAL_ACCESS_TOKEN_REVIEW_APPS="" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8526df75d..983fdd647 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -301,3 +301,18 @@ For vite, we used to take advantage of `basicSsl` provided by a vitejs `plugin-b ```sh mkcert -install ``` + + +# Making authenticated requests to the Github API + +As explained in +https://github.com/numerique-gouv/ami-notifications-api/issues/417, we need to +make authenticated requests to the Github API, in the staging mobile apps. + +To do so, the env variable GITHUB_PERSONAL_ACCESS_TOKEN_REVIEW_APPS +needs to be set with a [Personal Access +Token](https://docs.github.com/en/authentication/keeping-your-account-and-data-s +ecure/managing-your-personal-access-tokens). + +This token can be generated on any user, and only needs the minimal access to +read public repositories. diff --git a/ami/settings.py b/ami/settings.py index 4e5cec892..73285d5ba 100644 --- a/ami/settings.py +++ b/ami/settings.py @@ -297,6 +297,11 @@ def before_send(event, hint): PARTNERS_PSL_OTV_JWT_CERT_PUBLIC_KEY = CONFIG.get("PARTNERS_PSL_OTV_JWT_CERT_PUBLIC_KEY", "") PARTNERS_PSL_OTV_JWE_PUBLIC_KEY = CONFIG.get("PARTNERS_PSL_OTV_JWE_PUBLIC_KEY", "") +# Github Personal Access Token to list open PRs +GITHUB_PERSONAL_ACCESS_TOKEN_REVIEW_APPS = CONFIG.get( + "GITHUB_PERSONAL_ACCESS_TOKEN_REVIEW_APPS", "" +) + # Channels CHANNEL_UNAUTHORIZED_CODE = 4001 diff --git a/ami/utils/api_views.py b/ami/utils/api_views.py index b842782e8..767621c03 100644 --- a/ami/utils/api_views.py +++ b/ami/utils/api_views.py @@ -55,14 +55,17 @@ def _dev_utils_recipient_fc_hash(request) -> HttpResponse: @api_view(["GET"]) def _dev_utils_review_apps(request) -> Response[list[dict[str, str | int]]]: """Returns a list of tuples: (review app url, pull request title).""" + headers = { + "Accept": "application/vnd.github+json", + "X-GitHub-Api-Version": "2022-11-28", + } + if settings.GITHUB_PERSONAL_ACCESS_TOKEN_REVIEW_APPS: + headers["Authorization"] = f"Bearer {settings.GITHUB_PERSONAL_ACCESS_TOKEN_REVIEW_APPS}" with httpxClient() as httpx_client: response = httpx_client.get( "https://api.github.com/repos/numerique-gouv/ami-notifications-api/pulls", params={"state": "open", "sort": "created", "per_page": 100}, - headers={ - "Accept": "application/vnd.github+json", - "X-GitHub-Api-Version": "2022-11-28", - }, + headers=headers, ) staging_app = { "url": "https://ami-back-staging.osc-fr1.scalingo.io/", diff --git a/ami/utils/tests/test_all.py b/ami/utils/tests/test_all.py index 8acae810f..6d40b6c7d 100644 --- a/ami/utils/tests/test_all.py +++ b/ami/utils/tests/test_all.py @@ -59,6 +59,20 @@ def test_review_apps_github_failure(app, httpx_mock: HTTPXMock) -> None: assert json_data[0]["title"] == "Staging" +def test_review_apps_with_personal_access_token(app, httpx_mock: HTTPXMock, settings) -> None: + httpx_mock.add_response( + method="GET", + url="https://api.github.com/repos/numerique-gouv/ami-notifications-api/pulls?state=open&sort=created&per_page=100", + json=TRUNCATED_GITHUB_JSON_RESPONSE, + ) + settings.GITHUB_PERSONAL_ACCESS_TOKEN_REVIEW_APPS = "some personal access token" + app.get("/dev-utils/review-apps") + # Make sure the request to the github API had the proper auth header + github_request = httpx_mock.get_request() + assert github_request is not None + assert github_request.headers["Authorization"] == "Bearer some personal access token" + + TRUNCATED_GITHUB_JSON_RESPONSE: list[dict[str, Any]] = [ { "url": "https://api.github.com/repos/numerique-gouv/ami-notifications-api/pulls/83",