From 759afd8e1bb2f5bcfbf976e5bed608516414bbc6 Mon Sep 17 00:00:00 2001 From: karthikeyannhs <174426205+Karthikeyannhs@users.noreply.github.com> Date: Fri, 16 Jan 2026 16:54:50 +0000 Subject: [PATCH] nhs number validation fix --- .../common/request_validator.py | 4 +- .../in_process/test_eligibility_endpoint.py | 50 +++++++++++++++++++ tests/unit/common/test_request_validator.py | 16 ++++-- 3 files changed, 65 insertions(+), 5 deletions(-) diff --git a/src/eligibility_signposting_api/common/request_validator.py b/src/eligibility_signposting_api/common/request_validator.py index e4fe7ab7..c012861a 100644 --- a/src/eligibility_signposting_api/common/request_validator.py +++ b/src/eligibility_signposting_api/common/request_validator.py @@ -60,8 +60,8 @@ def validate_request_params() -> Callable: def decorator(func: Callable) -> Callable: @wraps(func) def wrapper(*args, **kwargs) -> ResponseReturnValue: # noqa:ANN002,ANN003 - path_nhs_number = str(kwargs.get("nhs_number")) - header_nhs_no = str(request.headers.get(NHS_NUMBER_HEADER)) + path_nhs_number = str(kwargs.get("nhs_number")) if kwargs.get("nhs_number") else None + header_nhs_no = str(request.headers.get(NHS_NUMBER_HEADER)) if request.headers.get(NHS_NUMBER_HEADER) else None if not validate_nhs_number(path_nhs_number, header_nhs_no): message = "You are not authorised to request information for the supplied NHS Number" diff --git a/tests/integration/in_process/test_eligibility_endpoint.py b/tests/integration/in_process/test_eligibility_endpoint.py index 4e5cdbfb..625ddd95 100644 --- a/tests/integration/in_process/test_eligibility_endpoint.py +++ b/tests/integration/in_process/test_eligibility_endpoint.py @@ -1,5 +1,6 @@ from http import HTTPStatus +import pytest from botocore.client import BaseClient from brunns.matchers.data import json_matching as is_json_that from brunns.matchers.werkzeug import is_werkzeug_response as is_response @@ -39,6 +40,55 @@ def test_nhs_number_given( is_response().with_status_code(HTTPStatus.OK).and_text(is_json_that(has_key("processedSuggestions"))), ) + @pytest.mark.parametrize( + "headers", + [ + {"nhs-login-nhs-number": None}, # header present but empty + {}, # header missing entirely + {"nhs-login-nhs-number": ""}, # header present but blank + ], + ) + def test_nhs_number_given_but_no_nhs_number_in_header( + self, + client: FlaskClient, + persisted_person: NHSNumber, + campaign_config: CampaignConfig, # noqa: ARG002 + secretsmanager_client: BaseClient, # noqa: ARG002 + headers: dict, + ): + # Given + # When + response = client.get(f"/patient-check/{persisted_person}", headers=headers) + + # Then + assert_that( + response, + is_response() + .with_status_code(HTTPStatus.OK) + .and_text(is_json_that(has_key("processedSuggestions"))), + ) + + def test_nhs_number_given_but_header_nhs_number_doesnt_match( + self, + client: FlaskClient, + persisted_person: NHSNumber, + campaign_config: CampaignConfig, # noqa: ARG002 + secretsmanager_client: BaseClient, # noqa: ARG002 + ): + # Given + headers = {"nhs-login-nhs-number": f"123{str(persisted_person)}"} + + # When + response = client.get(f"/patient-check/{persisted_person}", headers=headers) + + # Then + assert_that( + response, + is_response() + .with_status_code(HTTPStatus.FORBIDDEN) + .and_text(is_json_that(has_entries(resourceType="OperationOutcome"))), + ) + def test_no_nhs_number_given(self, client: FlaskClient): # Given diff --git a/tests/unit/common/test_request_validator.py b/tests/unit/common/test_request_validator.py index e04392eb..a158b10a 100644 --- a/tests/unit/common/test_request_validator.py +++ b/tests/unit/common/test_request_validator.py @@ -21,8 +21,9 @@ class TestValidateNHSNumber: ("path_nhs", "header_nhs", "expected_result", "expected_log_msg"), [ (None, None, False, "NHS number is not present in path"), - ("1234567890", None, True, None), (None, "1234567890", False, "NHS number is not present in path"), + ("1234567890", None, True, None), + ("1234567890", "", True, None), ("1234567890", "0987654321", False, "NHS number mismatch"), ("1234567890", "1234567890", True, None), ], @@ -40,7 +41,16 @@ def test_validate_nhs_number(self, path_nhs, header_nhs, expected_result, expect class TestValidateRequestParams: - def test_validate_request_params_success(self, app, caplog): + @pytest.mark.parametrize( + "headers", + [ + {"nhs-login-nhs-number": None}, # header present but empty + {}, # header missing entirely + {"nhs-login-nhs-number": ""}, # header present but blank + {"nhs-login-nhs-number": "1234567890"} # present and matches + ], + ) + def test_validate_request_params_success(self, headers, app, caplog): mock_api = MagicMock(return_value="success") decorator = request_validator.validate_request_params() @@ -48,7 +58,7 @@ def test_validate_request_params_success(self, app, caplog): with app.test_request_context( "/dummy?id=1234567890", - headers={"nhs-login-nhs-number": "1234567890"}, + headers=headers, method="GET", ): with caplog.at_level(logging.INFO):