From 8a7215be6e94565a3a70107f577dc959a919adc0 Mon Sep 17 00:00:00 2001 From: TOEL2 Date: Fri, 30 Jan 2026 11:46:25 +0000 Subject: [PATCH 1/6] ELI-623 changed to look for product id in header --- src/eligibility_signposting_api/config/constants.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/eligibility_signposting_api/config/constants.py b/src/eligibility_signposting_api/config/constants.py index 6deb0b4ec..026d15ec6 100644 --- a/src/eligibility_signposting_api/config/constants.py +++ b/src/eligibility_signposting_api/config/constants.py @@ -3,5 +3,5 @@ URL_PREFIX = "patient-check" RULE_STOP_DEFAULT = False NHS_NUMBER_HEADER = "nhs-login-nhs-number" -CONSUMER_ID = "nhsd-application-id" # "Nhsd-Application-Id" +CONSUMER_ID = "nhse-product-id" # "NHSE-Product-ID" ALLOWED_CONDITIONS = Literal["COVID", "FLU", "MMR", "RSV"] From 4e7d2a2c79c6263b92dedf27e8f43e7d9a9793c1 Mon Sep 17 00:00:00 2001 From: TOEL2 Date: Fri, 30 Jan 2026 14:32:23 +0000 Subject: [PATCH 2/6] (ELI-623) fixing escaping error --- tests/integration/conftest.py | 2 +- .../lambda/test_app_running_as_lambda.py | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index 9ba0968d3..cda54b509 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -50,7 +50,7 @@ AWS_CURRENT_SECRET = "test_value" # noqa: S105 AWS_PREVIOUS_SECRET = "test_value_old" # noqa: S105 -UNIQUE_CONSUMER_HEADER = "nhsd-application-id" +UNIQUE_CONSUMER_HEADER = "nhse-product-id" @pytest.fixture(scope="session") diff --git a/tests/integration/lambda/test_app_running_as_lambda.py b/tests/integration/lambda/test_app_running_as_lambda.py index 09953f4ca..2d77c045c 100644 --- a/tests/integration/lambda/test_app_running_as_lambda.py +++ b/tests/integration/lambda/test_app_running_as_lambda.py @@ -207,7 +207,8 @@ def test_given_nhs_number_in_path_matches_with_nhs_number_in_headers_and_check_i "x_request_id": "x_request_id", "x_correlation_id": "x_correlation_id", "nhsd_end_user_organisation_ods": "nhsd_end_user_organisation_ods", - "nhsd-application-id": consumer_id, + "nhsd-application-id": "nhsd-application-id", + "nhse-product-id": consumer_id, }, params={"includeActions": "Y"}, timeout=10, @@ -229,7 +230,7 @@ def test_given_nhs_number_in_path_matches_with_nhs_number_in_headers_and_check_i "xRequestId": "x_request_id", "xCorrelationId": "x_correlation_id", "nhsdEndUserOrganisationOds": "nhsd_end_user_organisation_ods", - "nhsdApplicationId": consumer_id, + "nhsdApplicationId": "nhsd-application-id", } expected_query_params = {"category": None, "conditions": None, "includeActions": "Y"} @@ -455,7 +456,8 @@ def test_given_person_has_unique_status_for_different_conditions_with_audit( # "x_request_id": "x_request_id", "x_correlation_id": "x_correlation_id", "nhsd_end_user_organisation_ods": "nhsd_end_user_organisation_ods", - "nhsd_application_id": consumer_id, + "nhsd-application-id": "nhsd-application-id", + "nhse-product-id": consumer_id, }, params={"includeActions": "Y", "category": "VACCINATIONS", "conditions": "COVID,FLU,RSV"}, timeout=10, @@ -475,7 +477,7 @@ def test_given_person_has_unique_status_for_different_conditions_with_audit( # "xRequestId": "x_request_id", "xCorrelationId": "x_correlation_id", "nhsdEndUserOrganisationOds": "nhsd_end_user_organisation_ods", - "nhsdApplicationId": consumer_id, + "nhsdApplicationId": "nhsd-application-id", } expected_query_params = {"category": "VACCINATIONS", "conditions": "COVID,FLU,RSV", "includeActions": "Y"} @@ -597,7 +599,8 @@ def test_no_active_iteration_returns_empty_processed_suggestions( "x_request_id": "x_request_id", "x_correlation_id": "x_correlation_id", "nhsd_end_user_organisation_ods": "nhsd_end_user_organisation_ods", - "nhsd_application_id": consumer_id, + "nhsd-application-id": "nhsd-application-id", + "nhse-product-id": consumer_id, }, params={"includeActions": "Y", "category": "VACCINATIONS", "conditions": "COVID,FLU,RSV"}, timeout=10, From bc9aa0f7b564c40560d28c639b6e940df2fd4c89 Mon Sep 17 00:00:00 2001 From: TOEL2 Date: Fri, 30 Jan 2026 16:08:04 +0000 Subject: [PATCH 3/6] (ELI-623) adding logging and auditng to lambda and api gateway --- src/eligibility_signposting_api/audit/audit_context.py | 1 + src/eligibility_signposting_api/audit/audit_models.py | 1 + src/eligibility_signposting_api/logging/logs_helper.py | 2 ++ tests/integration/lambda/test_app_running_as_lambda.py | 2 ++ 4 files changed, 6 insertions(+) diff --git a/src/eligibility_signposting_api/audit/audit_context.py b/src/eligibility_signposting_api/audit/audit_context.py index 8de980888..53358b4d6 100644 --- a/src/eligibility_signposting_api/audit/audit_context.py +++ b/src/eligibility_signposting_api/audit/audit_context.py @@ -48,6 +48,7 @@ def add_request_details(request: Request) -> None: x_correlation_id=request.headers.get("X-Correlation-ID"), nhsd_end_user_organisation_ods=request.headers.get("NHSD-End-User-Organisation-ODS"), nhsd_application_id=request.headers.get("nhsd-application-id"), + nhse_product_id=request.headers.get("nhse-product-id"), ) ), query_params=( diff --git a/src/eligibility_signposting_api/audit/audit_models.py b/src/eligibility_signposting_api/audit/audit_models.py index 2f1b0ee2d..a9d3f8896 100644 --- a/src/eligibility_signposting_api/audit/audit_models.py +++ b/src/eligibility_signposting_api/audit/audit_models.py @@ -17,6 +17,7 @@ class RequestAuditHeader(CamelCaseBaseModel): x_correlation_id: str | None = None nhsd_end_user_organisation_ods: str | None = None nhsd_application_id: str | None = None + nhse_product_id: str | None = None class RequestAuditQueryParams(CamelCaseBaseModel): diff --git a/src/eligibility_signposting_api/logging/logs_helper.py b/src/eligibility_signposting_api/logging/logs_helper.py index 12d8a48db..8f37b44be 100644 --- a/src/eligibility_signposting_api/logging/logs_helper.py +++ b/src/eligibility_signposting_api/logging/logs_helper.py @@ -20,6 +20,8 @@ def wrapper(event: LambdaEvent, context: LambdaContext) -> dict[str, Any] | None "x_request_id": headers.get("X-Request-ID"), "x_correlation_id": headers.get("X-Correlation-ID"), "gateway_request_id": gateway_request_id, + "nhse_product_id": headers.get("nhse-product-id"), + "nhsd_application_id": headers.get("nhsd-application-id"), }, ) return func(event, context) diff --git a/tests/integration/lambda/test_app_running_as_lambda.py b/tests/integration/lambda/test_app_running_as_lambda.py index 2d77c045c..180fb8762 100644 --- a/tests/integration/lambda/test_app_running_as_lambda.py +++ b/tests/integration/lambda/test_app_running_as_lambda.py @@ -231,6 +231,7 @@ def test_given_nhs_number_in_path_matches_with_nhs_number_in_headers_and_check_i "xCorrelationId": "x_correlation_id", "nhsdEndUserOrganisationOds": "nhsd_end_user_organisation_ods", "nhsdApplicationId": "nhsd-application-id", + "nhseProductId": consumer_id, } expected_query_params = {"category": None, "conditions": None, "includeActions": "Y"} @@ -478,6 +479,7 @@ def test_given_person_has_unique_status_for_different_conditions_with_audit( # "xCorrelationId": "x_correlation_id", "nhsdEndUserOrganisationOds": "nhsd_end_user_organisation_ods", "nhsdApplicationId": "nhsd-application-id", + "nhseProductId": consumer_id, } expected_query_params = {"category": "VACCINATIONS", "conditions": "COVID,FLU,RSV", "includeActions": "Y"} From fd42022473000874ee98df14a7fdf1e109101898 Mon Sep 17 00:00:00 2001 From: karthikeyannhs <174426205+Karthikeyannhs@users.noreply.github.com> Date: Mon, 2 Feb 2026 14:57:08 +0000 Subject: [PATCH 4/6] access logs using jsoncode --- infrastructure/stacks/api-layer/api_gateway.tf | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/infrastructure/stacks/api-layer/api_gateway.tf b/infrastructure/stacks/api-layer/api_gateway.tf index 46ccfb6f3..910d5426a 100644 --- a/infrastructure/stacks/api-layer/api_gateway.tf +++ b/infrastructure/stacks/api-layer/api_gateway.tf @@ -56,7 +56,23 @@ resource "aws_api_gateway_stage" "eligibility-signposting-api" { # A subscription filter (see csoc_log_forwarding.tf) forwards these logs to CSOC access_log_settings { destination_arn = module.eligibility_signposting_api_gateway.cloudwatch_destination_arn - format = "{ \"requestId\":\"$context.requestId\", \"ip\": \"$context.identity.sourceIp\", \"caller\":\"$context.identity.caller\", \"user\":\"$context.identity.user\", \"requestTime\":\"$context.requestTime\", \"httpMethod\":\"$context.httpMethod\", \"resourcePath\":\"$context.resourcePath\", \"status\":\"$context.status\", \"protocol\":\"$context.protocol\", \"responseLength\":\"$context.responseLength\", \"accountId\":\"$context.accountId\", \"apiId\":\"$context.apiId\", \"stage\":\"$context.stage\", \"api_key\":\"$context.identity.apiKey\" }" + format = jsonencode({ + requestId = "$context.requestId" + ip = "$context.identity.sourceIp" + caller = "$context.identity.caller" + user = "$context.identity.user" + requestTime = "$context.requestTime" + httpMethod = "$context.httpMethod" + resourcePath = "$context.resourcePath" + status = "$context.status" + protocol = "$context.protocol" + responseLength = "$context.responseLength" + accountId = "$context.accountId" + apiId = "$context.apiId" + stage = "$context.stage" + api_key = "$context.identity.apiKey" + nhse_product_id = "$context.request.header.nhse-product-id" + }) } depends_on = [ From 7118db03710ce2ba1b215ab26bbd318ca4d65a5d Mon Sep 17 00:00:00 2001 From: karthikeyannhs <174426205+Karthikeyannhs@users.noreply.github.com> Date: Mon, 2 Feb 2026 15:23:02 +0000 Subject: [PATCH 5/6] revert back to EOF --- .../stacks/api-layer/api_gateway.tf | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/infrastructure/stacks/api-layer/api_gateway.tf b/infrastructure/stacks/api-layer/api_gateway.tf index 910d5426a..092d38372 100644 --- a/infrastructure/stacks/api-layer/api_gateway.tf +++ b/infrastructure/stacks/api-layer/api_gateway.tf @@ -56,23 +56,25 @@ resource "aws_api_gateway_stage" "eligibility-signposting-api" { # A subscription filter (see csoc_log_forwarding.tf) forwards these logs to CSOC access_log_settings { destination_arn = module.eligibility_signposting_api_gateway.cloudwatch_destination_arn - format = jsonencode({ - requestId = "$context.requestId" - ip = "$context.identity.sourceIp" - caller = "$context.identity.caller" - user = "$context.identity.user" - requestTime = "$context.requestTime" - httpMethod = "$context.httpMethod" - resourcePath = "$context.resourcePath" - status = "$context.status" - protocol = "$context.protocol" - responseLength = "$context.responseLength" - accountId = "$context.accountId" - apiId = "$context.apiId" - stage = "$context.stage" - api_key = "$context.identity.apiKey" - nhse_product_id = "$context.request.header.nhse-product-id" - }) + format = < Date: Thu, 5 Feb 2026 11:26:13 +0000 Subject: [PATCH 6/6] eli 623 - nhse-product-id re-cased --- infrastructure/stacks/api-layer/api_gateway.tf | 1 - src/eligibility_signposting_api/config/constants.py | 2 +- src/eligibility_signposting_api/logging/logs_helper.py | 4 +++- tests/integration/lambda/test_app_running_as_lambda.py | 6 +++--- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/infrastructure/stacks/api-layer/api_gateway.tf b/infrastructure/stacks/api-layer/api_gateway.tf index 092d38372..c39cf9f9d 100644 --- a/infrastructure/stacks/api-layer/api_gateway.tf +++ b/infrastructure/stacks/api-layer/api_gateway.tf @@ -64,7 +64,6 @@ resource "aws_api_gateway_stage" "eligibility-signposting-api" { "caller": "$context.identity.caller", "httpMethod": "$context.httpMethod", "ip": "$context.identity.sourceIp", - "nhse_product_id": "$context.request.header.nhse-product-id", "protocol": "$context.protocol", "requestId": "$context.requestId", "requestTime": "$context.requestTime", diff --git a/src/eligibility_signposting_api/config/constants.py b/src/eligibility_signposting_api/config/constants.py index 026d15ec6..1594d6d6f 100644 --- a/src/eligibility_signposting_api/config/constants.py +++ b/src/eligibility_signposting_api/config/constants.py @@ -3,5 +3,5 @@ URL_PREFIX = "patient-check" RULE_STOP_DEFAULT = False NHS_NUMBER_HEADER = "nhs-login-nhs-number" -CONSUMER_ID = "nhse-product-id" # "NHSE-Product-ID" +CONSUMER_ID = "NHSE-Product-ID" ALLOWED_CONDITIONS = Literal["COVID", "FLU", "MMR", "RSV"] diff --git a/src/eligibility_signposting_api/logging/logs_helper.py b/src/eligibility_signposting_api/logging/logs_helper.py index 8f37b44be..a10e1f050 100644 --- a/src/eligibility_signposting_api/logging/logs_helper.py +++ b/src/eligibility_signposting_api/logging/logs_helper.py @@ -5,6 +5,8 @@ from mangum.types import LambdaContext, LambdaEvent +from eligibility_signposting_api.config.constants import CONSUMER_ID + logger = logging.getLogger(__name__) @@ -20,7 +22,7 @@ def wrapper(event: LambdaEvent, context: LambdaContext) -> dict[str, Any] | None "x_request_id": headers.get("X-Request-ID"), "x_correlation_id": headers.get("X-Correlation-ID"), "gateway_request_id": gateway_request_id, - "nhse_product_id": headers.get("nhse-product-id"), + "nhse_product_id": headers.get(CONSUMER_ID), "nhsd_application_id": headers.get("nhsd-application-id"), }, ) diff --git a/tests/integration/lambda/test_app_running_as_lambda.py b/tests/integration/lambda/test_app_running_as_lambda.py index 180fb8762..08618038b 100644 --- a/tests/integration/lambda/test_app_running_as_lambda.py +++ b/tests/integration/lambda/test_app_running_as_lambda.py @@ -208,7 +208,7 @@ def test_given_nhs_number_in_path_matches_with_nhs_number_in_headers_and_check_i "x_correlation_id": "x_correlation_id", "nhsd_end_user_organisation_ods": "nhsd_end_user_organisation_ods", "nhsd-application-id": "nhsd-application-id", - "nhse-product-id": consumer_id, + "NHSE-Product-ID": consumer_id, }, params={"includeActions": "Y"}, timeout=10, @@ -458,7 +458,7 @@ def test_given_person_has_unique_status_for_different_conditions_with_audit( # "x_correlation_id": "x_correlation_id", "nhsd_end_user_organisation_ods": "nhsd_end_user_organisation_ods", "nhsd-application-id": "nhsd-application-id", - "nhse-product-id": consumer_id, + "NHSE-Product-ID": consumer_id, }, params={"includeActions": "Y", "category": "VACCINATIONS", "conditions": "COVID,FLU,RSV"}, timeout=10, @@ -602,7 +602,7 @@ def test_no_active_iteration_returns_empty_processed_suggestions( "x_correlation_id": "x_correlation_id", "nhsd_end_user_organisation_ods": "nhsd_end_user_organisation_ods", "nhsd-application-id": "nhsd-application-id", - "nhse-product-id": consumer_id, + "NHSE-Product-ID": consumer_id, }, params={"includeActions": "Y", "category": "VACCINATIONS", "conditions": "COVID,FLU,RSV"}, timeout=10,