From 4cefaae2d36e1eeb8d941c00e5a70373aa816d16 Mon Sep 17 00:00:00 2001 From: tstephen-nhs <231503406+tstephen-nhs@users.noreply.github.com> Date: Tue, 20 Jan 2026 11:19:09 +0000 Subject: [PATCH 01/13] feat: enable delegated access proxygen style --- packages/specification/prescriptions-for-patients.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/specification/prescriptions-for-patients.yaml b/packages/specification/prescriptions-for-patients.yaml index e2b36da6d..5dcb615ac 100644 --- a/packages/specification/prescriptions-for-patients.yaml +++ b/packages/specification/prescriptions-for-patients.yaml @@ -416,6 +416,7 @@ components: x-nhsd-apim: temporary: false monitoring: true + delegatedaccess: true access: - title: User Restricted grants: From f44b9eb618843dd932a41ffe5a5c198cb93281d0 Mon Sep 17 00:00:00 2001 From: tstephen-nhs <231503406+tstephen-nhs@users.noreply.github.com> Date: Tue, 20 Jan 2026 11:21:31 +0000 Subject: [PATCH 02/13] fix: updated header name for delegate access --- packages/getMyPrescriptions/src/getMyPrescriptions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/getMyPrescriptions/src/getMyPrescriptions.ts b/packages/getMyPrescriptions/src/getMyPrescriptions.ts index be6ec23cd..24f4025a0 100644 --- a/packages/getMyPrescriptions/src/getMyPrescriptions.ts +++ b/packages/getMyPrescriptions/src/getMyPrescriptions.ts @@ -44,7 +44,7 @@ const servicesCache: ServicesCache = {} const LAMBDA_TIMEOUT_MS = 10_000 const SPINE_TIMEOUT_MS = 9_000 const SERVICE_SEARCH_TIMEOUT_MS = 5_000 -export const DELEGATED_ACCESS_HDR = "delegatedaccess" +export const DELEGATED_ACCESS_HDR = "x-nhsd-delegated-access" export const DELEGATED_ACCESS_SUB_HDR = "x-nhsd-subject-nhs-number" export type GetMyPrescriptionsEvent = { From 0a828bdf9f6d5d2ea9e98a0d0b4f4b7f75572ab9 Mon Sep 17 00:00:00 2001 From: tstephen-nhs <231503406+tstephen-nhs@users.noreply.github.com> Date: Mon, 2 Feb 2026 15:53:26 +0000 Subject: [PATCH 03/13] fix: delegateacces --- packages/specification/prescriptions-for-patients.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/specification/prescriptions-for-patients.yaml b/packages/specification/prescriptions-for-patients.yaml index 8a1fb3854..85b26bb75 100644 --- a/packages/specification/prescriptions-for-patients.yaml +++ b/packages/specification/prescriptions-for-patients.yaml @@ -416,7 +416,7 @@ components: x-nhsd-apim: temporary: false monitoring: true - delegatedaccess: true + delegatedacces: true # sic: the misspelling is required access: - title: User Restricted grants: From 1307b6593af57986bc425b722e30c14dea5c0e96 Mon Sep 17 00:00:00 2001 From: tstephen-nhs <231503406+tstephen-nhs@users.noreply.github.com> Date: Thu, 5 Feb 2026 11:07:35 +0000 Subject: [PATCH 04/13] Revert "fix: delegateacces" This reverts commit 0a828bdf9f6d5d2ea9e98a0d0b4f4b7f75572ab9. --- packages/specification/prescriptions-for-patients.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/specification/prescriptions-for-patients.yaml b/packages/specification/prescriptions-for-patients.yaml index 85b26bb75..8a1fb3854 100644 --- a/packages/specification/prescriptions-for-patients.yaml +++ b/packages/specification/prescriptions-for-patients.yaml @@ -416,7 +416,7 @@ components: x-nhsd-apim: temporary: false monitoring: true - delegatedacces: true # sic: the misspelling is required + delegatedaccess: true access: - title: User Restricted grants: From 89d4a450e34b4a863cf212e00d5b7602925c72a1 Mon Sep 17 00:00:00 2001 From: tstephen-nhs <231503406+tstephen-nhs@users.noreply.github.com> Date: Thu, 5 Feb 2026 12:40:18 +0000 Subject: [PATCH 05/13] chore: bump regression tests --- .github/workflows/run_regression_tests.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/run_regression_tests.yml b/.github/workflows/run_regression_tests.yml index c370d83d4..ee2f713d0 100644 --- a/.github/workflows/run_regression_tests.yml +++ b/.github/workflows/run_regression_tests.yml @@ -79,8 +79,8 @@ jobs: GITHUB-TOKEN: ${{ steps.generate-token.outputs.token }} run: | if [[ "$TARGET_ENVIRONMENT" != "prod" && "$TARGET_ENVIRONMENT" != "ref" ]]; then - REGRESSION_TEST_REPO_TAG="v3.8.19" # This is the tag or branch of the regression test code to run, usually a version tag like v3.1.0 or a branch name - REGRESSION_TEST_WORKFLOW_TAG="v3.8.19" # This is the tag of the github workflow to run, usually the same as REGRESSION_TEST_REPO_TAG + REGRESSION_TEST_REPO_TAG="v3.8.30" # This is the tag or branch of the regression test code to run, usually a version tag like v3.1.0 or a branch name + REGRESSION_TEST_WORKFLOW_TAG="v3.8.30" # This is the tag of the github workflow to run, usually the same as REGRESSION_TEST_REPO_TAG if [[ -z "$REGRESSION_TEST_REPO_TAG" || -z "$REGRESSION_TEST_WORKFLOW_TAG" ]]; then echo "Error: One or both tag variables are not set" >&2 @@ -121,8 +121,8 @@ jobs: GITHUB-TOKEN: ${{ steps.generate-token.outputs.token }} run: | if [[ "$TARGET_ENVIRONMENT" != "prod" && "$TARGET_ENVIRONMENT" != "ref" ]]; then - REGRESSION_TEST_REPO_TAG="v3.8.19" # This is the tag or branch of the regression test code to run, usually a version tag like v3.1.0 or a branch name - REGRESSION_TEST_WORKFLOW_TAG="v3.8.19" # This is the tag of the github workflow to run, usually the same as REGRESSION_TEST_REPO_TAG + REGRESSION_TEST_REPO_TAG="v3.8.30" # This is the tag or branch of the regression test code to run, usually a version tag like v3.1.0 or a branch name + REGRESSION_TEST_WORKFLOW_TAG="v3.8.30" # This is the tag of the github workflow to run, usually the same as REGRESSION_TEST_REPO_TAG if [[ -z "$REGRESSION_TEST_REPO_TAG" || -z "$REGRESSION_TEST_WORKFLOW_TAG" ]]; then echo "Error: One or both tag variables are not set" >&2 From 280d9dc4c672fccff81dc3fe53b3a3265ba832ee Mon Sep 17 00:00:00 2001 From: tstephen-nhs <231503406+tstephen-nhs@users.noreply.github.com> Date: Thu, 5 Feb 2026 15:31:59 +0000 Subject: [PATCH 06/13] test: inject mock subject nhs number --- packages/getMyPrescriptions/src/getMyPrescriptions.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/getMyPrescriptions/src/getMyPrescriptions.ts b/packages/getMyPrescriptions/src/getMyPrescriptions.ts index 7991f9b45..3c2c49ee3 100644 --- a/packages/getMyPrescriptions/src/getMyPrescriptions.ts +++ b/packages/getMyPrescriptions/src/getMyPrescriptions.ts @@ -187,6 +187,13 @@ export function overrideNonProductionHeadersForProxygenRequests(headers: EventHe headers[NHS_LOGIN_HEADER] = headers["x-nhs-number"] logger.info("Set non production headers for Spine call", {headers}) } + if (headers["x-subject-nhs-number"] // mock subject for delegated access testing + && process.env.ALLOW_NHS_NUMBER_OVERRIDE === "true" + && headers["nhs-login-identity-proofing-level"] + ) { + headers[DELEGATED_ACCESS_SUB_HDR] = headers["x-subject-nhs-number"] + logger.info("Set non production headers for Spine call", {headers}) + } return headers } From 185ba87d1cf2fe29711043eb7f01ad29446cd3f5 Mon Sep 17 00:00:00 2001 From: tstephen-nhs <231503406+tstephen-nhs@users.noreply.github.com> Date: Thu, 5 Feb 2026 15:39:43 +0000 Subject: [PATCH 07/13] Revert "test: inject mock subject nhs number" This reverts commit 397a454234569c0ba3dad67b4489e9900dbd477d. --- packages/getMyPrescriptions/src/getMyPrescriptions.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/getMyPrescriptions/src/getMyPrescriptions.ts b/packages/getMyPrescriptions/src/getMyPrescriptions.ts index 3c2c49ee3..7991f9b45 100644 --- a/packages/getMyPrescriptions/src/getMyPrescriptions.ts +++ b/packages/getMyPrescriptions/src/getMyPrescriptions.ts @@ -187,13 +187,6 @@ export function overrideNonProductionHeadersForProxygenRequests(headers: EventHe headers[NHS_LOGIN_HEADER] = headers["x-nhs-number"] logger.info("Set non production headers for Spine call", {headers}) } - if (headers["x-subject-nhs-number"] // mock subject for delegated access testing - && process.env.ALLOW_NHS_NUMBER_OVERRIDE === "true" - && headers["nhs-login-identity-proofing-level"] - ) { - headers[DELEGATED_ACCESS_SUB_HDR] = headers["x-subject-nhs-number"] - logger.info("Set non production headers for Spine call", {headers}) - } return headers } From 454bd2bfbbecf53c93f5b54d46ad3a80fb44052c Mon Sep 17 00:00:00 2001 From: tstephen-nhs <231503406+tstephen-nhs@users.noreply.github.com> Date: Thu, 5 Feb 2026 15:42:04 +0000 Subject: [PATCH 08/13] fix: regular request coexist w delegated --- packages/getMyPrescriptions/src/getMyPrescriptions.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/getMyPrescriptions/src/getMyPrescriptions.ts b/packages/getMyPrescriptions/src/getMyPrescriptions.ts index 7991f9b45..065b113a9 100644 --- a/packages/getMyPrescriptions/src/getMyPrescriptions.ts +++ b/packages/getMyPrescriptions/src/getMyPrescriptions.ts @@ -200,7 +200,9 @@ export function adaptHeadersToSpine(headers: EventHeaders): EventHeaders { logger.info("Delegated access request detected") let subjectNHSNumber = headers[DELEGATED_ACCESS_SUB_HDR] if (!subjectNHSNumber) { - throw new NHSNumberValidationError(`${DELEGATED_ACCESS_SUB_HDR} header not present for delegated access`) + // assume non-delegated access request, just because DE enabled doesn't mean every request will be one + subjectNHSNumber = extractNHSNumberFromHeaders(headers) + // throw new NHSNumberValidationError(`${DELEGATED_ACCESS_SUB_HDR} header not present for delegated access`) } if (subjectNHSNumber.includes(":")) { logger.warn(`${DELEGATED_ACCESS_SUB_HDR} is not expected to be prefixed by proofing level, but is, removing it`) From 566af045c9364200d66aa54f5d02ed7102663b4c Mon Sep 17 00:00:00 2001 From: tstephen-nhs <231503406+tstephen-nhs@users.noreply.github.com> Date: Thu, 5 Feb 2026 16:00:42 +0000 Subject: [PATCH 09/13] test: non-delegated when DE enabled --- .../tests/adaptHeadersToSpine.test.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/getMyPrescriptions/tests/adaptHeadersToSpine.test.ts b/packages/getMyPrescriptions/tests/adaptHeadersToSpine.test.ts index fef0d98aa..3fc8e575f 100644 --- a/packages/getMyPrescriptions/tests/adaptHeadersToSpine.test.ts +++ b/packages/getMyPrescriptions/tests/adaptHeadersToSpine.test.ts @@ -111,17 +111,17 @@ describe("adaptHeadersToSpine", () => { expect(result["nhsd-nhslogin-user"]).toBe("P9:9999681778") }) - it("should throw NHSNumberValidationError when subject header is missing for delegated access", () => { + it("should perform non-delegated request when subject header is missing for delegated access", () => { const headers: EventHeaders = { [DELEGATED_ACCESS_HDR]: "true", "nhsd-nhslogin-user": "P9:9999681778" // Missing DELEGATED_ACCESS_SUB_HDR } - expect(() => adaptHeadersToSpine(headers)) - .toThrow(NHSNumberValidationError) - expect(() => adaptHeadersToSpine(headers)) - .toThrow(`${DELEGATED_ACCESS_SUB_HDR} header not present for delegated access`) + const result = adaptHeadersToSpine(headers) + + expect(result.nhsNumber).toBe("9999681778") + expect(result["nhsd-nhslogin-user"]).toBe("P9:9999681778") }) }) From 8b4079dd91abf9c4faf3af98ecbc60522dae6ebd Mon Sep 17 00:00:00 2001 From: tstephen-nhs <231503406+tstephen-nhs@users.noreply.github.com> Date: Thu, 5 Feb 2026 16:28:23 +0000 Subject: [PATCH 10/13] chore: tidy logging --- README.md | 2 +- packages/getMyPrescriptions/src/getMyPrescriptions.ts | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index a73dd7449..b23cc062c 100644 --- a/README.md +++ b/README.md @@ -201,7 +201,7 @@ Note - the command will keep running and should not be stopped. You can now call this api - note getMyPrescriptions requires an nhsd-nhslogin-user header ```bash -curl --header "nhsd-nhslogin-user: P9:9446041481" --header "x-request-id: $(uuid)" \ +curl --header "nhsd-nhslogin-user: P9:9446041481" --header "x-request-id: $(cat /proc/sys/kernel/random/uuid)" \ https://${stack_name}.dev.eps.national.nhs.uk/Bundle ``` diff --git a/packages/getMyPrescriptions/src/getMyPrescriptions.ts b/packages/getMyPrescriptions/src/getMyPrescriptions.ts index 065b113a9..80277934b 100644 --- a/packages/getMyPrescriptions/src/getMyPrescriptions.ts +++ b/packages/getMyPrescriptions/src/getMyPrescriptions.ts @@ -192,17 +192,15 @@ export function overrideNonProductionHeadersForProxygenRequests(headers: EventHe export function adaptHeadersToSpine(headers: EventHeaders): EventHeaders { // AEA-3344 introduces delegated access using different headers - logger.debug("Testing if delegated access enabled", {headers}) if (!headers[DELEGATED_ACCESS_HDR] || headers[DELEGATED_ACCESS_HDR].toLowerCase() !== "true") { - logger.info("Subject access request detected") + logger.info("Delegated access NOT enabled", {headers}) headers["nhsNumber"] = extractNHSNumberFromHeaders(headers) } else { - logger.info("Delegated access request detected") + logger.info("Delegated access enabled", {headers}) let subjectNHSNumber = headers[DELEGATED_ACCESS_SUB_HDR] if (!subjectNHSNumber) { - // assume non-delegated access request, just because DE enabled doesn't mean every request will be one + logger.info(`${DELEGATED_ACCESS_SUB_HDR} header missing, assuming non-delegated access request`, {headers}) subjectNHSNumber = extractNHSNumberFromHeaders(headers) - // throw new NHSNumberValidationError(`${DELEGATED_ACCESS_SUB_HDR} header not present for delegated access`) } if (subjectNHSNumber.includes(":")) { logger.warn(`${DELEGATED_ACCESS_SUB_HDR} is not expected to be prefixed by proofing level, but is, removing it`) From dd858cb90b2d418294f2e9dd4b1973e255d30250 Mon Sep 17 00:00:00 2001 From: tstephen-nhs <231503406+tstephen-nhs@users.noreply.github.com> Date: Thu, 5 Feb 2026 16:33:44 +0000 Subject: [PATCH 11/13] fix: opt in to subject header --- packages/specification/prescriptions-for-patients.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/specification/prescriptions-for-patients.yaml b/packages/specification/prescriptions-for-patients.yaml index 8a1fb3854..6a5ce3304 100644 --- a/packages/specification/prescriptions-for-patients.yaml +++ b/packages/specification/prescriptions-for-patients.yaml @@ -433,6 +433,8 @@ x-nhsd-apim: header: "nhsd-nhslogin-user" - name: nhs-login-identity-proofing-level header: "nhs-login-identity-proofing-level" + - name: X-NHSD-Subject-NHS-Number + header: "x-nhsd-subject-nhs-number" target-attributes: - name: developer.app.name required: false From 13bf5956cc660a2e555d106c0f2cfd1b7138967c Mon Sep 17 00:00:00 2001 From: tstephen-nhs <231503406+tstephen-nhs@users.noreply.github.com> Date: Thu, 5 Feb 2026 16:57:52 +0000 Subject: [PATCH 12/13] fix: tests reliant on debug logging --- .../getMyPrescriptions/tests/adaptHeadersToSpine.test.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/getMyPrescriptions/tests/adaptHeadersToSpine.test.ts b/packages/getMyPrescriptions/tests/adaptHeadersToSpine.test.ts index 3fc8e575f..1c0ad2081 100644 --- a/packages/getMyPrescriptions/tests/adaptHeadersToSpine.test.ts +++ b/packages/getMyPrescriptions/tests/adaptHeadersToSpine.test.ts @@ -37,7 +37,6 @@ describe("adaptHeadersToSpine", () => { expect(result.nhsNumber).toBe("9912003071") expect(result["nhsd-nhslogin-user"]).toBe("P9:9912003071") - expect(mockLoggerInfo).toHaveBeenCalledWith("Subject access request detected") expect(mockLoggerInfo).toHaveBeenCalledWith( "after setting subject nhsNumber", {headers: result} @@ -45,7 +44,6 @@ describe("adaptHeadersToSpine", () => { }) it("should process subject access when delegated access is false", () => { - const mockLoggerInfo = jest.spyOn(Logger.prototype, "info") const headers: EventHeaders = { [DELEGATED_ACCESS_HDR]: "false", "nhsd-nhslogin-user": "P9:9912003071" @@ -55,7 +53,6 @@ describe("adaptHeadersToSpine", () => { expect(result.nhsNumber).toBe("9912003071") expect(result["nhsd-nhslogin-user"]).toBe("P9:9912003071") - expect(mockLoggerInfo).toHaveBeenCalledWith("Subject access request detected") }) it("should preserve other headers in subject access", () => { @@ -87,7 +84,6 @@ describe("adaptHeadersToSpine", () => { expect(result.nhsNumber).toBe("9912003071") expect(result["nhsd-nhslogin-user"]).toBe("P9:9999681778") - expect(mockLoggerInfo).toHaveBeenCalledWith("Delegated access request detected") expect(mockLoggerInfo).toHaveBeenNthCalledWith(2, "after setting subject nhsNumber", {headers: result} @@ -152,7 +148,6 @@ describe("adaptHeadersToSpine", () => { describe("edge cases", () => { it("should be case insensitive for delegated access flag", () => { - const mockLoggerInfo = jest.spyOn(Logger.prototype, "info") const headers: EventHeaders = { [DELEGATED_ACCESS_HDR]: "TrUe", // permit any case "nhsd-nhslogin-user": "P9:9999681778", @@ -163,7 +158,6 @@ describe("adaptHeadersToSpine", () => { // Should be treated as delegated expect(result.nhsNumber).toBe("2219685934") - expect(mockLoggerInfo).toHaveBeenCalledWith("Delegated access request detected") }) it("should handle missing headers gracefully by throwing appropriate errors", () => { From 93d99020ae2ebd964bbda9dd6dca392e8742f2a8 Mon Sep 17 00:00:00 2001 From: tstephen-nhs <231503406+tstephen-nhs@users.noreply.github.com> Date: Thu, 5 Feb 2026 17:15:33 +0000 Subject: [PATCH 13/13] chore: alt subject header cfg --- packages/specification/prescriptions-for-patients.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/specification/prescriptions-for-patients.yaml b/packages/specification/prescriptions-for-patients.yaml index 6a5ce3304..f1feb8b6f 100644 --- a/packages/specification/prescriptions-for-patients.yaml +++ b/packages/specification/prescriptions-for-patients.yaml @@ -433,8 +433,6 @@ x-nhsd-apim: header: "nhsd-nhslogin-user" - name: nhs-login-identity-proofing-level header: "nhs-login-identity-proofing-level" - - name: X-NHSD-Subject-NHS-Number - header: "x-nhsd-subject-nhs-number" target-attributes: - name: developer.app.name required: false @@ -442,6 +440,9 @@ x-nhsd-apim: - name: developer.app.id required: false header: "nhsd-application-id" + - name: X-NHSD-Subject-NHS-Number + required: false + header: "x-nhsd-subject-nhs-number" ratelimiting: proxy: limit: 20000