From 4dcb4ce24840273358edff90ec061d8c8336f152 Mon Sep 17 00:00:00 2001 From: David Hamill <109090521+davidhamill1-nhs@users.noreply.github.com> Date: Tue, 7 Apr 2026 13:34:03 +0100 Subject: [PATCH 1/4] Add headers and log on receipt. --- gateway-api/src/gateway_api/app.py | 29 ++++++++++++++++++--- gateway-api/src/gateway_api/common/error.py | 4 --- proxygen/x-nhsd-apim.template.yaml | 3 +++ 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/gateway-api/src/gateway_api/app.py b/gateway-api/src/gateway_api/app.py index 3b7cd5c5..f69050d8 100644 --- a/gateway-api/src/gateway_api/app.py +++ b/gateway-api/src/gateway_api/app.py @@ -1,7 +1,7 @@ import os import traceback -from flask import Flask, request +from flask import Flask, Request, request from flask.wrappers import Response from gateway_api.common.error import AbstractCDGError, UnexpectedError @@ -11,6 +11,7 @@ ) app = Flask(__name__) +app.logger.setLevel("INFO") def get_app_host() -> str: @@ -29,19 +30,41 @@ def get_app_port() -> int: return int(port) +def log_request_received(request: Request) -> None: + log_details = { + "description": "Received request", + "method": request.method, + "path": request.path, + "headers": dict(request.headers), + "body": request.get_data(as_text=True), + } + app.logger.info(log_details) + + +def log_error(error: AbstractCDGError) -> None: + log_details = { + "description": "An error occurred", + "error_type": type(error).__name__, + "error_message": str(error), + "traceback": traceback.format_exc(), + } + app.logger.error(log_details) + + @app.route("/patient/$gpc.getstructuredrecord", methods=["POST"]) def get_structured_record() -> Response: + log_request_received(request) try: get_structured_record_request = GetStructuredRecordRequest(request) controller = Controller() flask_response = controller.run(request=get_structured_record_request) get_structured_record_request.set_response_from_flaskresponse(flask_response) except AbstractCDGError as e: - e.log() + log_error(e) return e.build_response() except Exception: error = UnexpectedError(traceback=traceback.format_exc()) - error.log() + log_error(error) return error.build_response() return get_structured_record_request.build_response() diff --git a/gateway-api/src/gateway_api/common/error.py b/gateway-api/src/gateway_api/common/error.py index 2e5c323b..6d2772eb 100644 --- a/gateway-api/src/gateway_api/common/error.py +++ b/gateway-api/src/gateway_api/common/error.py @@ -1,5 +1,4 @@ import json -import traceback from dataclasses import dataclass from enum import StrEnum from http.client import BAD_GATEWAY, BAD_REQUEST, INTERNAL_SERVER_ERROR, NOT_FOUND @@ -53,9 +52,6 @@ def build_response(self) -> Response: ) return response - def log(self) -> None: - print(traceback.format_exc(), flush=True) - @property def message(self) -> str: return self._message.format(**self.additional_details) diff --git a/proxygen/x-nhsd-apim.template.yaml b/proxygen/x-nhsd-apim.template.yaml index e8cba5a1..e2870ade 100644 --- a/proxygen/x-nhsd-apim.template.yaml +++ b/proxygen/x-nhsd-apim.template.yaml @@ -11,3 +11,6 @@ x-nhsd-apim: security: type: mtls secret: + target-identity: + - name: cis2-uuid + - name: cis2-urid From 9442f8c926e99f558f34e5187c6757a558ce0d1e Mon Sep 17 00:00:00 2001 From: David Hamill <109090521+davidhamill1-nhs@users.noreply.github.com> Date: Tue, 7 Apr 2026 14:17:29 +0100 Subject: [PATCH 2/4] Update docs. --- proxygen/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/proxygen/README.md b/proxygen/README.md index 6c960f85..40e27f6d 100644 --- a/proxygen/README.md +++ b/proxygen/README.md @@ -62,7 +62,8 @@ Proxygen deploys a proxy instance using an OpenAPI specification file. The speci * the **target endpoint URL** to which the proxy will forward traffic; * the **access controls** and scopes a user needs to access the proxy; -* the **mTLS secret name** pointing to the certificate the backend expects. +* the **mTLS secret name** pointing to the certificate the backend expects; +* the **target-identity** to add user identity headers to the request. At deploy time, this template is concatenated with the main API specification (`gateway-api/openapi.yaml`), the target URL and mTLS secret are injected, and the resulting file is passed to the Proxygen CLI. From d3930faa95259dd6c7a47860879243b19c77292a Mon Sep 17 00:00:00 2001 From: David Hamill <109090521+davidhamill1-nhs@users.noreply.github.com> Date: Tue, 7 Apr 2026 14:19:37 +0100 Subject: [PATCH 3/4] Remove potential to inject malicious code and prevent PII from being exposed. --- gateway-api/src/gateway_api/app.py | 1 - 1 file changed, 1 deletion(-) diff --git a/gateway-api/src/gateway_api/app.py b/gateway-api/src/gateway_api/app.py index f69050d8..28d97538 100644 --- a/gateway-api/src/gateway_api/app.py +++ b/gateway-api/src/gateway_api/app.py @@ -36,7 +36,6 @@ def log_request_received(request: Request) -> None: "method": request.method, "path": request.path, "headers": dict(request.headers), - "body": request.get_data(as_text=True), } app.logger.info(log_details) From c6cbcace19eaf4327cdf741719609653354acb79 Mon Sep 17 00:00:00 2001 From: David Hamill <109090521+davidhamill1-nhs@users.noreply.github.com> Date: Wed, 8 Apr 2026 09:59:20 +0100 Subject: [PATCH 4/4] Have default user with only one role. Reduces complexity of having to decide on role that the user is fulfilling at point of calling API --- gateway-api/tests/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gateway-api/tests/conftest.py b/gateway-api/tests/conftest.py index 851eee98..f77c729d 100644 --- a/gateway-api/tests/conftest.py +++ b/gateway-api/tests/conftest.py @@ -214,7 +214,7 @@ def _fetch_env_variable[T]( REMOTE_TEST_USERNAME_ENV_VAR = "REMOTE_TEST_USERNAME" -DEFAULT_REMOTE_TEST_USERNAME = "656005750104" +DEFAULT_REMOTE_TEST_USERNAME = "656005750101" def _get_remote_test_username() -> str: