Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/dhfs/adapters/outbound/central.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,15 @@ def _auth_headers(self) -> dict[str, str]:
"""Create an authorization header with a bearer token containing a fresh JWT"""
return {"Authorization": f"Bearer {self._make_jwt()}"}

def _log_if_upgrade_required(self, status_code: int) -> None:
"""Log a hard-coded message if the Central API indicates DHFS is outdated."""
if status_code == 426:
log.error(
"The GHGA Central API has rejected this request (HTTP 426): this DHFS"
" installation is outdated. Please upgrade DHFS by following GHGA's"
" upgrade documentation."
)

def _response_to_object_id_list(self, response: httpx.Response) -> list[str]:
"""Returns a list of strings from an httpx Response.

Expand Down Expand Up @@ -148,6 +157,7 @@ async def fetch_new_uploads(self) -> list[models.FileUpload]:
response = retry_error.last_attempt.result()

if (status_code := response.status_code) != 200:
self._log_if_upgrade_required(status_code)
error = self.CentralAPIError(url=url, status_code=status_code)
log.error(error)
raise error
Expand Down Expand Up @@ -178,6 +188,7 @@ async def get_removable_files(self, *, object_ids: list[str]) -> list[str]:
response = retry_error.last_attempt.result()

if (status_code := response.status_code) != 200:
self._log_if_upgrade_required(status_code)
error = self.CentralAPIError(url=url, status_code=status_code)
log.error(error)
raise error
Expand Down Expand Up @@ -218,6 +229,7 @@ async def submit_interrogation_report(
response = retry_error.last_attempt.result()

if (status_code := response.status_code) != 201:
self._log_if_upgrade_required(status_code)
error = self.CentralAPIError(url=url, status_code=status_code)
log.error(error)
raise error
Expand Down
28 changes: 28 additions & 0 deletions tests/unit/test_central.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import base64
import json
import logging
import os
from collections.abc import AsyncGenerator
from datetime import datetime, timedelta
Expand Down Expand Up @@ -175,6 +176,33 @@ async def test_500_response_handling(
await central_client.submit_interrogation_report(report=report)


@pytest.mark.httpx_mock(can_send_already_matched_responses=True)
async def test_426_response_handling(
config: Config, central_client, httpx_mock: HTTPXMock, caplog
):
"""Test that 426 responses trigger a CentralAPIError and log the upgrade message."""
upgrade_message = "The GHGA Central API has rejected this request (HTTP 426)"
httpx_mock.add_response(status_code=426)

with pytest.raises(CentralClient.CentralAPIError):
with caplog.at_level(logging.ERROR):
await central_client.fetch_new_uploads()
assert upgrade_message in caplog.text
caplog.clear()

with pytest.raises(CentralClient.CentralAPIError):
with caplog.at_level(logging.ERROR):
await central_client.get_removable_files(object_ids=[])
assert upgrade_message in caplog.text
caplog.clear()

with pytest.raises(CentralClient.CentralAPIError):
with caplog.at_level(logging.ERROR):
report = make_interrogation_success_report(config.storage_alias)
await central_client.submit_interrogation_report(report=report)
assert upgrade_message in caplog.text


async def test_report_submission(config: Config, central_client, httpx_mock: HTTPXMock):
"""Test that the secret submitted inside the InterrogationReport is encrypted
with the Central API public key, as well as that other fields are submitted.
Expand Down
Loading