From e6ba613fdafc2697304723769bc735b81c7628dc Mon Sep 17 00:00:00 2001
From: Gareth Allan <157592212+gareth-allan@users.noreply.github.com>
Date: Fri, 6 Mar 2026 13:37:31 +0000
Subject: [PATCH 01/15] CCM-14325: Make PDM uploader use PDM mock
---
.../components/dl/aws_api_gateway_deployment_pdm_mock.tf | 2 +-
.../aws_api_gateway_integration_create_document_reference.tf | 2 +-
.../dl/aws_api_gateway_integration_get_document_reference.tf | 2 +-
.../dl/aws_api_gateway_method_create_document_reference.tf | 2 +-
.../dl/aws_api_gateway_method_get_document_reference.tf | 2 +-
.../dl/aws_api_gateway_resource_document_reference.tf | 2 +-
.../dl/aws_api_gateway_resource_document_reference_id.tf | 2 +-
.../terraform/components/dl/aws_api_gateway_resource_fhir.tf | 2 +-
.../dl/aws_api_gateway_resource_patient_data_manager.tf | 2 +-
.../terraform/components/dl/aws_api_gateway_resource_r4.tf | 2 +-
.../components/dl/aws_api_gateway_rest_api_pdm_mock.tf | 2 +-
.../terraform/components/dl/aws_api_gateway_stage_pdm_mock.tf | 2 +-
.../dl/aws_cloudwatch_log_group_pdm_mock_gateway.tf | 2 +-
.../components/dl/aws_lambda_permission_pdm_mock_gateway.tf | 2 +-
infrastructure/terraform/components/dl/locals.tf | 2 +-
.../terraform/components/dl/module_lambda_pdm_mock.tf | 4 ++--
.../terraform/components/dl/module_lambda_pdm_poll.tf | 2 +-
.../terraform/components/dl/module_lambda_pdm_uploader.tf | 2 +-
18 files changed, 19 insertions(+), 19 deletions(-)
diff --git a/infrastructure/terraform/components/dl/aws_api_gateway_deployment_pdm_mock.tf b/infrastructure/terraform/components/dl/aws_api_gateway_deployment_pdm_mock.tf
index c6c39b1b0..b3d9a305f 100644
--- a/infrastructure/terraform/components/dl/aws_api_gateway_deployment_pdm_mock.tf
+++ b/infrastructure/terraform/components/dl/aws_api_gateway_deployment_pdm_mock.tf
@@ -1,5 +1,5 @@
resource "aws_api_gateway_deployment" "pdm_mock" {
- count = local.deploy_pdm_mock ? 1 : 0
+ count = var.enable_pdm_mock ? 1 : 0
depends_on = [
aws_api_gateway_integration.create_document_reference,
diff --git a/infrastructure/terraform/components/dl/aws_api_gateway_integration_create_document_reference.tf b/infrastructure/terraform/components/dl/aws_api_gateway_integration_create_document_reference.tf
index 3d8568b4b..4db48b6cc 100644
--- a/infrastructure/terraform/components/dl/aws_api_gateway_integration_create_document_reference.tf
+++ b/infrastructure/terraform/components/dl/aws_api_gateway_integration_create_document_reference.tf
@@ -1,5 +1,5 @@
resource "aws_api_gateway_integration" "create_document_reference" {
- count = local.deploy_pdm_mock ? 1 : 0
+ count = var.enable_pdm_mock ? 1 : 0
rest_api_id = aws_api_gateway_rest_api.pdm_mock[0].id
resource_id = aws_api_gateway_resource.document_reference[0].id
diff --git a/infrastructure/terraform/components/dl/aws_api_gateway_integration_get_document_reference.tf b/infrastructure/terraform/components/dl/aws_api_gateway_integration_get_document_reference.tf
index 6ac602e68..67a329e69 100644
--- a/infrastructure/terraform/components/dl/aws_api_gateway_integration_get_document_reference.tf
+++ b/infrastructure/terraform/components/dl/aws_api_gateway_integration_get_document_reference.tf
@@ -1,5 +1,5 @@
resource "aws_api_gateway_integration" "get_document_reference" {
- count = local.deploy_pdm_mock ? 1 : 0
+ count = var.enable_pdm_mock ? 1 : 0
rest_api_id = aws_api_gateway_rest_api.pdm_mock[0].id
resource_id = aws_api_gateway_resource.document_reference_id[0].id
diff --git a/infrastructure/terraform/components/dl/aws_api_gateway_method_create_document_reference.tf b/infrastructure/terraform/components/dl/aws_api_gateway_method_create_document_reference.tf
index c2d1d30c9..773b9f2eb 100644
--- a/infrastructure/terraform/components/dl/aws_api_gateway_method_create_document_reference.tf
+++ b/infrastructure/terraform/components/dl/aws_api_gateway_method_create_document_reference.tf
@@ -1,5 +1,5 @@
resource "aws_api_gateway_method" "create_document_reference" {
- count = local.deploy_pdm_mock ? 1 : 0
+ count = var.enable_pdm_mock ? 1 : 0
rest_api_id = aws_api_gateway_rest_api.pdm_mock[0].id
resource_id = aws_api_gateway_resource.document_reference[0].id
diff --git a/infrastructure/terraform/components/dl/aws_api_gateway_method_get_document_reference.tf b/infrastructure/terraform/components/dl/aws_api_gateway_method_get_document_reference.tf
index 56ac1b430..f8bb677fe 100644
--- a/infrastructure/terraform/components/dl/aws_api_gateway_method_get_document_reference.tf
+++ b/infrastructure/terraform/components/dl/aws_api_gateway_method_get_document_reference.tf
@@ -1,5 +1,5 @@
resource "aws_api_gateway_method" "get_document_reference" {
- count = local.deploy_pdm_mock ? 1 : 0
+ count = var.enable_pdm_mock ? 1 : 0
rest_api_id = aws_api_gateway_rest_api.pdm_mock[0].id
resource_id = aws_api_gateway_resource.document_reference_id[0].id
diff --git a/infrastructure/terraform/components/dl/aws_api_gateway_resource_document_reference.tf b/infrastructure/terraform/components/dl/aws_api_gateway_resource_document_reference.tf
index e3238ab02..aafefe818 100644
--- a/infrastructure/terraform/components/dl/aws_api_gateway_resource_document_reference.tf
+++ b/infrastructure/terraform/components/dl/aws_api_gateway_resource_document_reference.tf
@@ -1,5 +1,5 @@
resource "aws_api_gateway_resource" "document_reference" {
- count = local.deploy_pdm_mock ? 1 : 0
+ count = var.enable_pdm_mock ? 1 : 0
rest_api_id = aws_api_gateway_rest_api.pdm_mock[0].id
parent_id = aws_api_gateway_resource.r4[0].id
diff --git a/infrastructure/terraform/components/dl/aws_api_gateway_resource_document_reference_id.tf b/infrastructure/terraform/components/dl/aws_api_gateway_resource_document_reference_id.tf
index bdc24b46e..5ebe66d6a 100644
--- a/infrastructure/terraform/components/dl/aws_api_gateway_resource_document_reference_id.tf
+++ b/infrastructure/terraform/components/dl/aws_api_gateway_resource_document_reference_id.tf
@@ -1,5 +1,5 @@
resource "aws_api_gateway_resource" "document_reference_id" {
- count = local.deploy_pdm_mock ? 1 : 0
+ count = var.enable_pdm_mock ? 1 : 0
rest_api_id = aws_api_gateway_rest_api.pdm_mock[0].id
parent_id = aws_api_gateway_resource.document_reference[0].id
diff --git a/infrastructure/terraform/components/dl/aws_api_gateway_resource_fhir.tf b/infrastructure/terraform/components/dl/aws_api_gateway_resource_fhir.tf
index 24dbdbb49..e11412ab1 100644
--- a/infrastructure/terraform/components/dl/aws_api_gateway_resource_fhir.tf
+++ b/infrastructure/terraform/components/dl/aws_api_gateway_resource_fhir.tf
@@ -1,5 +1,5 @@
resource "aws_api_gateway_resource" "fhir" {
- count = local.deploy_pdm_mock ? 1 : 0
+ count = var.enable_pdm_mock ? 1 : 0
rest_api_id = aws_api_gateway_rest_api.pdm_mock[0].id
parent_id = aws_api_gateway_resource.patient_data_manager[0].id
diff --git a/infrastructure/terraform/components/dl/aws_api_gateway_resource_patient_data_manager.tf b/infrastructure/terraform/components/dl/aws_api_gateway_resource_patient_data_manager.tf
index d08d6b43c..bc3b1326a 100644
--- a/infrastructure/terraform/components/dl/aws_api_gateway_resource_patient_data_manager.tf
+++ b/infrastructure/terraform/components/dl/aws_api_gateway_resource_patient_data_manager.tf
@@ -1,5 +1,5 @@
resource "aws_api_gateway_resource" "patient_data_manager" {
- count = local.deploy_pdm_mock ? 1 : 0
+ count = var.enable_pdm_mock ? 1 : 0
rest_api_id = aws_api_gateway_rest_api.pdm_mock[0].id
parent_id = aws_api_gateway_rest_api.pdm_mock[0].root_resource_id
diff --git a/infrastructure/terraform/components/dl/aws_api_gateway_resource_r4.tf b/infrastructure/terraform/components/dl/aws_api_gateway_resource_r4.tf
index e5075157e..e008f32b9 100644
--- a/infrastructure/terraform/components/dl/aws_api_gateway_resource_r4.tf
+++ b/infrastructure/terraform/components/dl/aws_api_gateway_resource_r4.tf
@@ -1,5 +1,5 @@
resource "aws_api_gateway_resource" "r4" {
- count = local.deploy_pdm_mock ? 1 : 0
+ count = var.enable_pdm_mock ? 1 : 0
rest_api_id = aws_api_gateway_rest_api.pdm_mock[0].id
parent_id = aws_api_gateway_resource.fhir[0].id
diff --git a/infrastructure/terraform/components/dl/aws_api_gateway_rest_api_pdm_mock.tf b/infrastructure/terraform/components/dl/aws_api_gateway_rest_api_pdm_mock.tf
index b9dd89141..14053b9ac 100644
--- a/infrastructure/terraform/components/dl/aws_api_gateway_rest_api_pdm_mock.tf
+++ b/infrastructure/terraform/components/dl/aws_api_gateway_rest_api_pdm_mock.tf
@@ -1,5 +1,5 @@
resource "aws_api_gateway_rest_api" "pdm_mock" {
- count = local.deploy_pdm_mock ? 1 : 0
+ count = var.enable_pdm_mock ? 1 : 0
name = "${var.project}-${var.environment}-pdm-mock"
description = "PDM Mock API for testing integration with Patient Data Manager"
diff --git a/infrastructure/terraform/components/dl/aws_api_gateway_stage_pdm_mock.tf b/infrastructure/terraform/components/dl/aws_api_gateway_stage_pdm_mock.tf
index 28cfd8d7b..439b2877f 100644
--- a/infrastructure/terraform/components/dl/aws_api_gateway_stage_pdm_mock.tf
+++ b/infrastructure/terraform/components/dl/aws_api_gateway_stage_pdm_mock.tf
@@ -1,5 +1,5 @@
resource "aws_api_gateway_stage" "pdm_mock" {
- count = local.deploy_pdm_mock ? 1 : 0
+ count = var.enable_pdm_mock ? 1 : 0
deployment_id = aws_api_gateway_deployment.pdm_mock[0].id
rest_api_id = aws_api_gateway_rest_api.pdm_mock[0].id
diff --git a/infrastructure/terraform/components/dl/aws_cloudwatch_log_group_pdm_mock_gateway.tf b/infrastructure/terraform/components/dl/aws_cloudwatch_log_group_pdm_mock_gateway.tf
index fe9f3bd9c..be8b2710e 100644
--- a/infrastructure/terraform/components/dl/aws_cloudwatch_log_group_pdm_mock_gateway.tf
+++ b/infrastructure/terraform/components/dl/aws_cloudwatch_log_group_pdm_mock_gateway.tf
@@ -1,5 +1,5 @@
resource "aws_cloudwatch_log_group" "pdm_mock_gateway" {
- count = local.deploy_pdm_mock ? 1 : 0
+ count = var.enable_pdm_mock ? 1 : 0
name = "/aws/apigateway/${var.project}-${var.environment}-pdm-mock"
retention_in_days = var.log_retention_in_days
diff --git a/infrastructure/terraform/components/dl/aws_lambda_permission_pdm_mock_gateway.tf b/infrastructure/terraform/components/dl/aws_lambda_permission_pdm_mock_gateway.tf
index 92000d638..30ed8dd15 100644
--- a/infrastructure/terraform/components/dl/aws_lambda_permission_pdm_mock_gateway.tf
+++ b/infrastructure/terraform/components/dl/aws_lambda_permission_pdm_mock_gateway.tf
@@ -1,5 +1,5 @@
resource "aws_lambda_permission" "pdm_mock_gateway" {
- count = local.deploy_pdm_mock ? 1 : 0
+ count = var.enable_pdm_mock ? 1 : 0
statement_id = "AllowAPIGatewayInvoke"
action = "lambda:InvokeFunction"
diff --git a/infrastructure/terraform/components/dl/locals.tf b/infrastructure/terraform/components/dl/locals.tf
index 5838de640..aff937496 100644
--- a/infrastructure/terraform/components/dl/locals.tf
+++ b/infrastructure/terraform/components/dl/locals.tf
@@ -4,7 +4,7 @@ locals {
apim_keystore_s3_bucket = "nhs-${var.aws_account_id}-${var.region}-${var.environment}-${var.component}-static-assets"
apim_private_key_ssm_parameter_name = "/${var.component}/${var.environment}/apim/private_key"
aws_lambda_functions_dir_path = "../../../../lambdas"
- deploy_pdm_mock = var.enable_pdm_mock
+ pdm_url = var.enable_pdm_mock ? aws_api_gateway_stage.pdm_mock[0].invoke_url : var.apim_base_url
firehose_output_path_prefix = "kinesis-firehose-output"
log_destination_arn = "arn:aws:logs:${var.region}:${var.shared_infra_account_id}:destination:nhs-main-obs-firehose-logs"
mock_mesh_endpoint = "s3://${module.s3bucket_non_pii_data.bucket}/mock-mesh"
diff --git a/infrastructure/terraform/components/dl/module_lambda_pdm_mock.tf b/infrastructure/terraform/components/dl/module_lambda_pdm_mock.tf
index b4ce63136..f2ca8c596 100644
--- a/infrastructure/terraform/components/dl/module_lambda_pdm_mock.tf
+++ b/infrastructure/terraform/components/dl/module_lambda_pdm_mock.tf
@@ -1,5 +1,5 @@
module "pdm_mock" {
- count = local.deploy_pdm_mock ? 1 : 0
+ count = var.enable_pdm_mock ? 1 : 0
source = "https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.29/terraform-lambda.zip"
function_name = "pdm-mock"
@@ -37,7 +37,7 @@ module "pdm_mock" {
}
data "aws_iam_policy_document" "pdm_mock" {
- count = local.deploy_pdm_mock ? 1 : 0
+ count = var.enable_pdm_mock ? 1 : 0
statement {
sid = "KMSPermissions"
diff --git a/infrastructure/terraform/components/dl/module_lambda_pdm_poll.tf b/infrastructure/terraform/components/dl/module_lambda_pdm_poll.tf
index 5ee748b1b..e61ce63cc 100644
--- a/infrastructure/terraform/components/dl/module_lambda_pdm_poll.tf
+++ b/infrastructure/terraform/components/dl/module_lambda_pdm_poll.tf
@@ -35,7 +35,7 @@ module "pdm_poll" {
log_subscription_role_arn = local.acct.log_subscription_role_arn
lambda_env_vars = {
- "APIM_BASE_URL" = local.deploy_pdm_mock ? aws_api_gateway_stage.pdm_mock[0].invoke_url : var.apim_base_url
+ "APIM_BASE_URL" = local.pdm_url
"APIM_ACCESS_TOKEN_SSM_PARAMETER_NAME" = local.apim_access_token_ssm_parameter_name
"EVENT_PUBLISHER_EVENT_BUS_ARN" = aws_cloudwatch_event_bus.main.arn
"EVENT_PUBLISHER_DLQ_URL" = module.sqs_event_publisher_errors.sqs_queue_url
diff --git a/infrastructure/terraform/components/dl/module_lambda_pdm_uploader.tf b/infrastructure/terraform/components/dl/module_lambda_pdm_uploader.tf
index 6bf6bb396..1afbe733e 100644
--- a/infrastructure/terraform/components/dl/module_lambda_pdm_uploader.tf
+++ b/infrastructure/terraform/components/dl/module_lambda_pdm_uploader.tf
@@ -35,7 +35,7 @@ module "pdm_uploader" {
log_subscription_role_arn = local.acct.log_subscription_role_arn
lambda_env_vars = {
- "APIM_BASE_URL" = var.apim_base_url
+ "APIM_BASE_URL" = local.pdm_url
"APIM_ACCESS_TOKEN_SSM_PARAMETER_NAME" = local.apim_access_token_ssm_parameter_name
"EVENT_PUBLISHER_EVENT_BUS_ARN" = aws_cloudwatch_event_bus.main.arn
"EVENT_PUBLISHER_DLQ_URL" = module.sqs_event_publisher_errors.sqs_queue_url
From 33c3e948e1a9a83f5a09825481269dc7ba88a90c Mon Sep 17 00:00:00 2001
From: Gareth Allan <157592212+gareth-allan@users.noreply.github.com>
Date: Fri, 6 Mar 2026 14:37:52 +0000
Subject: [PATCH 02/15] CCM-14325: Dependency updates
---
docs/package-lock.json | 15 ++++++-----
package-lock.json | 33 ++++++++++++++++--------
src/eventcatalog/package-lock.json | 41 ++++++++++++++++--------------
src/eventcatalog/package.json | 6 ++++-
4 files changed, 59 insertions(+), 36 deletions(-)
diff --git a/docs/package-lock.json b/docs/package-lock.json
index 76c905173..9f15a54f7 100644
--- a/docs/package-lock.json
+++ b/docs/package-lock.json
@@ -1911,10 +1911,13 @@
}
},
"node_modules/dompurify": {
- "version": "3.3.1",
- "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.1.tgz",
- "integrity": "sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==",
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.2.tgz",
+ "integrity": "sha512-6obghkliLdmKa56xdbLOpUZ43pAR6xFy1uOrxBaIDjT+yaRuuybLjGS9eVBoSR/UPU5fq3OXClEHLJNGvbxKpQ==",
"license": "(MPL-2.0 OR Apache-2.0)",
+ "engines": {
+ "node": ">=20"
+ },
"optionalDependencies": {
"@types/trusted-types": "^2.0.7"
}
@@ -2195,9 +2198,9 @@
}
},
"node_modules/immutable": {
- "version": "5.1.4",
- "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.4.tgz",
- "integrity": "sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==",
+ "version": "5.1.5",
+ "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.5.tgz",
+ "integrity": "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==",
"dev": true,
"license": "MIT"
},
diff --git a/package-lock.json b/package-lock.json
index 1844d3128..e3f1e01d1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -6169,13 +6169,13 @@
}
},
"node_modules/@aws-sdk/xml-builder": {
- "version": "3.972.8",
- "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.8.tgz",
- "integrity": "sha512-Ql8elcUdYCha83Ol7NznBsgN5GVZnv3vUd86fEc6waU6oUdY0T1O9NODkEEOS/Uaogr87avDrUC6DSeM4oXjZg==",
+ "version": "3.972.10",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.10.tgz",
+ "integrity": "sha512-OnejAIVD+CxzyAUrVic7lG+3QRltyja9LoNqCE/1YVs8ichoTbJlVSaZ9iSMcnHLyzrSNtvaOGjSDRP+d/ouFA==",
"license": "Apache-2.0",
"dependencies": {
"@smithy/types": "^4.13.0",
- "fast-xml-parser": "5.3.6",
+ "fast-xml-parser": "5.4.1",
"tslib": "^2.6.2"
},
"engines": {
@@ -13109,10 +13109,22 @@
],
"license": "BSD-3-Clause"
},
+ "node_modules/fast-xml-builder": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.0.0.tgz",
+ "integrity": "sha512-fpZuDogrAgnyt9oDDz+5DBz0zgPdPZz6D4IR7iESxRXElrlGTRkHJ9eEt+SACRJwT0FNFrt71DFQIUFBJfX/uQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/NaturalIntelligence"
+ }
+ ],
+ "license": "MIT"
+ },
"node_modules/fast-xml-parser": {
- "version": "5.3.6",
- "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.3.6.tgz",
- "integrity": "sha512-QNI3sAvSvaOiaMl8FYU4trnEzCwiRr8XMWgAHzlrWpTSj+QaCSvOf1h82OEP1s4hiAXhnbXSyFWCf4ldZzZRVA==",
+ "version": "5.4.1",
+ "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.4.1.tgz",
+ "integrity": "sha512-BQ30U1mKkvXQXXkAGcuyUA/GA26oEB7NzOtsxCDtyu62sjGw5QraKFhx2Em3WQNjPw9PG6MQ9yuIIgkSDfGu5A==",
"funding": [
{
"type": "github",
@@ -13121,6 +13133,7 @@
],
"license": "MIT",
"dependencies": {
+ "fast-xml-builder": "^1.0.0",
"strnum": "^2.1.2"
},
"bin": {
@@ -19912,9 +19925,9 @@
}
},
"node_modules/strnum": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.2.tgz",
- "integrity": "sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ==",
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.2.0.tgz",
+ "integrity": "sha512-Y7Bj8XyJxnPAORMZj/xltsfo55uOiyHcU2tnAVzHUnSJR/KsEX+9RoDeXEnsXtl/CX4fAcrt64gZ13aGaWPeBg==",
"funding": [
{
"type": "github",
diff --git a/src/eventcatalog/package-lock.json b/src/eventcatalog/package-lock.json
index d4b8fde44..363f85268 100644
--- a/src/eventcatalog/package-lock.json
+++ b/src/eventcatalog/package-lock.json
@@ -11402,10 +11402,13 @@
}
},
"node_modules/dompurify": {
- "version": "3.3.1",
- "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.1.tgz",
- "integrity": "sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==",
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.2.tgz",
+ "integrity": "sha512-6obghkliLdmKa56xdbLOpUZ43pAR6xFy1uOrxBaIDjT+yaRuuybLjGS9eVBoSR/UPU5fq3OXClEHLJNGvbxKpQ==",
"license": "(MPL-2.0 OR Apache-2.0)",
+ "engines": {
+ "node": ">=20"
+ },
"optionalDependencies": {
"@types/trusted-types": "^2.0.7"
}
@@ -14490,9 +14493,9 @@
}
},
"node_modules/jsonpath": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/jsonpath/-/jsonpath-1.2.1.tgz",
- "integrity": "sha512-Jl6Jhk0jG+kP3yk59SSeGq7LFPR4JQz1DU0K+kXTysUhMostbhU3qh5mjTuf0PqFcXpAT7kvmMt9WxV10NyIgQ==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/jsonpath/-/jsonpath-1.3.0.tgz",
+ "integrity": "sha512-0kjkYHJBkAy50Z5QzArZ7udmvxrJzkpKYW27fiF//BrMY7TQibYLl+FYIXN2BiYmwMIVzSfD8aDRj6IzgBX2/w==",
"license": "MIT",
"dependencies": {
"esprima": "1.2.5",
@@ -22151,9 +22154,9 @@
"license": "MIT"
},
"node_modules/sax": {
- "version": "1.4.4",
- "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.4.tgz",
- "integrity": "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==",
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/sax/-/sax-1.5.0.tgz",
+ "integrity": "sha512-21IYA3Q5cQf089Z6tgaUTr7lDAyzoTPx5HRtbhsME8Udispad8dC/+sziTNugOEx54ilvatQ9YCzl4KQLPcRHA==",
"license": "BlueOak-1.0.0",
"engines": {
"node": ">=11.0.0"
@@ -23047,9 +23050,9 @@
}
},
"node_modules/svgo": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.0.tgz",
- "integrity": "sha512-VvrHQ+9uniE+Mvx3+C9IEe/lWasXCU0nXMY2kZeLrHNICuRiC8uMPyM14UEaMOFA5mhyQqEkB02VoQ16n3DLaw==",
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.1.tgz",
+ "integrity": "sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w==",
"license": "MIT",
"dependencies": {
"commander": "^11.1.0",
@@ -23058,7 +23061,7 @@
"css-what": "^6.1.0",
"csso": "^5.0.5",
"picocolors": "^1.1.1",
- "sax": "^1.4.1"
+ "sax": "^1.5.0"
},
"bin": {
"svgo": "bin/svgo.js"
@@ -23198,9 +23201,9 @@
}
},
"node_modules/tar": {
- "version": "7.5.9",
- "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.9.tgz",
- "integrity": "sha512-BTLcK0xsDh2+PUe9F6c2TlRp4zOOBMTkoQHQIWSIzI0R7KG46uEwq4OPk2W7bZcprBMsuaeFsqwYr7pjh6CuHg==",
+ "version": "7.5.10",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.10.tgz",
+ "integrity": "sha512-8mOPs1//5q/rlkNSPcCegA6hiHJYDmSLEI8aMH/CdSQJNWztHC9WHNam5zdQlfpTwB9Xp7IBEsHfV5LKMJGVAw==",
"license": "BlueOak-1.0.0",
"dependencies": {
"@isaacs/fs-minipass": "^4.0.0",
@@ -23613,9 +23616,9 @@
"license": "MIT"
},
"node_modules/underscore": {
- "version": "1.13.6",
- "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz",
- "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==",
+ "version": "1.13.8",
+ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.8.tgz",
+ "integrity": "sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ==",
"license": "MIT"
},
"node_modules/undici": {
diff --git a/src/eventcatalog/package.json b/src/eventcatalog/package.json
index b2fc0fb5d..8bc324488 100644
--- a/src/eventcatalog/package.json
+++ b/src/eventcatalog/package.json
@@ -7,7 +7,11 @@
},
"name": "digital-letters",
"overrides": {
- "minimatch": "^10.2.4"
+ "astro-compress": {
+ "svgo": "^4.0.1"
+ },
+ "minimatch": "^10.2.4",
+ "underscore": "^1.13.8"
},
"private": true,
"scripts": {
From b54e094789cac569aca9afc6d8ccfaa1a9e123b1 Mon Sep 17 00:00:00 2001
From: Gareth Allan <157592212+gareth-allan@users.noreply.github.com>
Date: Fri, 6 Mar 2026 15:33:26 +0000
Subject: [PATCH 03/15] CCM-14325: Remove authentication from PDM mock
---
.../terraform/components/dl/README.md | 2 -
.../terraform/components/dl/locals.tf | 1 +
.../components/dl/module_lambda_pdm_poll.tf | 2 +-
.../dl/module_lambda_pdm_uploader.tf | 2 +-
.../dl/ssm_parameter_access_token.tf | 5 +-
.../terraform/components/dl/variables.tf | 12 ---
lambdas/pdm-mock-lambda/README.md | 4 -
.../src/__tests__/authenticator.test.ts | 74 -------------------
.../src/__tests__/container.test.ts | 15 ----
.../src/__tests__/index.test.ts | 30 +-------
lambdas/pdm-mock-lambda/src/authenticator.ts | 66 -----------------
lambdas/pdm-mock-lambda/src/container.ts | 5 --
lambdas/pdm-mock-lambda/src/index.ts | 9 +--
13 files changed, 7 insertions(+), 220 deletions(-)
delete mode 100644 lambdas/pdm-mock-lambda/src/__tests__/authenticator.test.ts
delete mode 100644 lambdas/pdm-mock-lambda/src/authenticator.ts
diff --git a/infrastructure/terraform/components/dl/README.md b/infrastructure/terraform/components/dl/README.md
index 959d5e6a1..786ba961e 100644
--- a/infrastructure/terraform/components/dl/README.md
+++ b/infrastructure/terraform/components/dl/README.md
@@ -40,8 +40,6 @@ No requirements.
| [mesh\_poll\_schedule](#input\_mesh\_poll\_schedule) | Schedule to poll MESH for messages | `string` | `"rate(5 minutes)"` | no |
| [metadata\_refresh\_schedule](#input\_metadata\_refresh\_schedule) | Schedule for refreshing reporting metadata. | `string` | `"cron(10 6-22 * * ? *)"` | no |
| [parent\_acct\_environment](#input\_parent\_acct\_environment) | Name of the environment responsible for the acct resources used, affects things like DNS zone. Useful for named dev environments | `string` | `"main"` | no |
-| [pdm\_mock\_access\_token](#input\_pdm\_mock\_access\_token) | Mock access token for PDM API authentication (used in local/dev environments) | `string` | `"mock-pdm-token"` | no |
-| [pdm\_use\_non\_mock\_token](#input\_pdm\_use\_non\_mock\_token) | Whether to use the shared APIM access token from SSM (/component/environment/apim/access\_token) instead of the mock token | `bool` | `false` | no |
| [pii\_data\_retention\_policy\_days](#input\_pii\_data\_retention\_policy\_days) | The number of days for data retention policy for PII | `number` | `534` | no |
| [project](#input\_project) | The name of the tfscaffold project | `string` | n/a | yes |
| [queue\_batch\_size](#input\_queue\_batch\_size) | maximum number of queue items to process | `number` | `10` | no |
diff --git a/infrastructure/terraform/components/dl/locals.tf b/infrastructure/terraform/components/dl/locals.tf
index aff937496..30c199a62 100644
--- a/infrastructure/terraform/components/dl/locals.tf
+++ b/infrastructure/terraform/components/dl/locals.tf
@@ -4,6 +4,7 @@ locals {
apim_keystore_s3_bucket = "nhs-${var.aws_account_id}-${var.region}-${var.environment}-${var.component}-static-assets"
apim_private_key_ssm_parameter_name = "/${var.component}/${var.environment}/apim/private_key"
aws_lambda_functions_dir_path = "../../../../lambdas"
+ pdm_access_token_ssm_parameter_name = var.enable_pdm_mock ? "" : "${local.apim_access_token_ssm_parameter_name}"
pdm_url = var.enable_pdm_mock ? aws_api_gateway_stage.pdm_mock[0].invoke_url : var.apim_base_url
firehose_output_path_prefix = "kinesis-firehose-output"
log_destination_arn = "arn:aws:logs:${var.region}:${var.shared_infra_account_id}:destination:nhs-main-obs-firehose-logs"
diff --git a/infrastructure/terraform/components/dl/module_lambda_pdm_poll.tf b/infrastructure/terraform/components/dl/module_lambda_pdm_poll.tf
index e61ce63cc..c4172356d 100644
--- a/infrastructure/terraform/components/dl/module_lambda_pdm_poll.tf
+++ b/infrastructure/terraform/components/dl/module_lambda_pdm_poll.tf
@@ -36,7 +36,7 @@ module "pdm_poll" {
lambda_env_vars = {
"APIM_BASE_URL" = local.pdm_url
- "APIM_ACCESS_TOKEN_SSM_PARAMETER_NAME" = local.apim_access_token_ssm_parameter_name
+ "APIM_ACCESS_TOKEN_SSM_PARAMETER_NAME" = local.pdm_access_token_ssm_parameter_name
"EVENT_PUBLISHER_EVENT_BUS_ARN" = aws_cloudwatch_event_bus.main.arn
"EVENT_PUBLISHER_DLQ_URL" = module.sqs_event_publisher_errors.sqs_queue_url
"POLL_MAX_RETRIES" = 10
diff --git a/infrastructure/terraform/components/dl/module_lambda_pdm_uploader.tf b/infrastructure/terraform/components/dl/module_lambda_pdm_uploader.tf
index 1afbe733e..ca3d8a983 100644
--- a/infrastructure/terraform/components/dl/module_lambda_pdm_uploader.tf
+++ b/infrastructure/terraform/components/dl/module_lambda_pdm_uploader.tf
@@ -36,7 +36,7 @@ module "pdm_uploader" {
lambda_env_vars = {
"APIM_BASE_URL" = local.pdm_url
- "APIM_ACCESS_TOKEN_SSM_PARAMETER_NAME" = local.apim_access_token_ssm_parameter_name
+ "APIM_ACCESS_TOKEN_SSM_PARAMETER_NAME" = local.pdm_access_token_ssm_parameter_name
"EVENT_PUBLISHER_EVENT_BUS_ARN" = aws_cloudwatch_event_bus.main.arn
"EVENT_PUBLISHER_DLQ_URL" = module.sqs_event_publisher_errors.sqs_queue_url
}
diff --git a/infrastructure/terraform/components/dl/ssm_parameter_access_token.tf b/infrastructure/terraform/components/dl/ssm_parameter_access_token.tf
index 06bcc66fd..8bc514985 100644
--- a/infrastructure/terraform/components/dl/ssm_parameter_access_token.tf
+++ b/infrastructure/terraform/components/dl/ssm_parameter_access_token.tf
@@ -2,9 +2,8 @@ resource "aws_ssm_parameter" "access_token" {
name = local.apim_access_token_ssm_parameter_name
description = "Access token for APIM"
type = "SecureString"
- value = jsonencode({
- tokens = []
- })
+ value = jsonencode({})
+
tags = merge(local.default_tags, { Backup = "true" })
lifecycle {
diff --git a/infrastructure/terraform/components/dl/variables.tf b/infrastructure/terraform/components/dl/variables.tf
index f00728d99..700e1e666 100644
--- a/infrastructure/terraform/components/dl/variables.tf
+++ b/infrastructure/terraform/components/dl/variables.tf
@@ -122,18 +122,6 @@ variable "ttl_poll_schedule" {
default = "rate(10 minutes)" # Every 10 minutes
}
-variable "pdm_mock_access_token" {
- type = string
- description = "Mock access token for PDM API authentication (used in local/dev environments)"
- default = "mock-pdm-token"
-}
-
-variable "pdm_use_non_mock_token" {
- type = bool
- description = "Whether to use the shared APIM access token from SSM (/component/environment/apim/access_token) instead of the mock token"
- default = false
-}
-
variable "apim_base_url" {
type = string
description = "The URL used to send requests to PDM"
diff --git a/lambdas/pdm-mock-lambda/README.md b/lambdas/pdm-mock-lambda/README.md
index c0ec5b0cd..18367161b 100644
--- a/lambdas/pdm-mock-lambda/README.md
+++ b/lambdas/pdm-mock-lambda/README.md
@@ -19,7 +19,6 @@ Creates a new PDM DocumentReference.
```bash
curl -X POST https:///patient-data-manager/FHIR/R4/DocumentReference \
- -H "Authorization: Bearer " \
-H "Content-Type: application/fhir+json" \
-H "X-Request-ID: 4a0e5f18-1747-4438-ac52-5ba2c21575f5" \
-d '{}'
@@ -27,7 +26,6 @@ curl -X POST https:///patient-data-manager/FHIR/R4/DocumentRefe
**Headers:**
-- `Authorization: Bearer ` - Authentication token is not validated and can be any string value.
- `Content-Type: application/fhir+json` - Required content type.
- `X-Request-ID: ` - This uuid will be used as the DocumentReference `id` in the response.
@@ -69,14 +67,12 @@ Retrieves a specific PDM DocumentReference by ID.
```bash
curl https:///patient-data-manager/FHIR/R4/DocumentReference/test-id \
- -H "Authorization: Bearer " \
-H "Content-Type: application/fhir+json" \
-H "X-Request-ID: 848b67ea-eeaa-3620-a388-e4e8594ff2e3"
```
**Headers:**
-- `Authorization: Bearer ` - Authentication token is not validated and can be any string value.
- `Content-Type: application/fhir+json` - Required content type.
- `X-Request-ID: ` - Used for request tracking and correlation. This isn't part of the ID or response that gets returned.
diff --git a/lambdas/pdm-mock-lambda/src/__tests__/authenticator.test.ts b/lambdas/pdm-mock-lambda/src/__tests__/authenticator.test.ts
deleted file mode 100644
index 86db5e8c3..000000000
--- a/lambdas/pdm-mock-lambda/src/__tests__/authenticator.test.ts
+++ /dev/null
@@ -1,74 +0,0 @@
-import type { Logger } from 'utils';
-import { createAuthenticator } from 'authenticator';
-
-const mockLogger: Logger = {
- debug: jest.fn(),
- info: jest.fn(),
- warn: jest.fn(),
- error: jest.fn(),
- child: jest.fn(),
-} as any;
-
-describe('Authenticator', () => {
- beforeEach(() => {
- jest.clearAllMocks();
- });
-
- describe('with mock token', () => {
- it('should authenticate successfully with valid Bearer token', async () => {
- const authenticator = createAuthenticator(mockLogger);
-
- const result = await authenticator({
- headers: { Authorization: 'Bearer test-token' },
- });
-
- expect(result.isValid).toBe(true);
- });
-
- it('should reject request with missing Authorization header', async () => {
- const authenticator = createAuthenticator(mockLogger);
-
- const result = await authenticator({ headers: {} });
-
- expect(result.isValid).toBe(false);
- expect(result).toHaveProperty('error');
- expect((result as { isValid: false; error: any }).error).toBeDefined();
- expect((result as { isValid: false; error: any }).error.statusCode).toBe(
- 401,
- );
- expect((result as { isValid: false; error: any }).error.body).toContain(
- 'ACCESS_DENIED',
- );
- expect((result as { isValid: false; error: any }).error.body).toContain(
- 'Missing Authentication Token',
- );
- });
-
- it('should reject request with invalid token type', async () => {
- const authenticator = createAuthenticator(mockLogger);
-
- const result = await authenticator({
- headers: { Authorization: 'Basic test-token' },
- });
-
- expect(result.isValid).toBe(false);
- expect(result).toHaveProperty('error');
- expect((result as { isValid: false; error: any }).error.statusCode).toBe(
- 401,
- );
- expect((result as { isValid: false; error: any }).error.body).toContain(
- 'Invalid Access Token',
- );
- });
-
- it('should handle lowercase authorization header', async () => {
- const authenticator = createAuthenticator(mockLogger);
-
- const result = await authenticator({
- headers: { authorization: 'Bearer test-token' },
- });
-
- expect(result.isValid).toBe(true);
- });
- });
-});
diff --git a/lambdas/pdm-mock-lambda/src/__tests__/container.test.ts b/lambdas/pdm-mock-lambda/src/__tests__/container.test.ts
index 4cfda0ac9..f46136ecd 100644
--- a/lambdas/pdm-mock-lambda/src/__tests__/container.test.ts
+++ b/lambdas/pdm-mock-lambda/src/__tests__/container.test.ts
@@ -35,16 +35,11 @@ describe('Container', () => {
it('should create a container with all required dependencies', () => {
expect(container).toBeDefined();
- expect(container.authenticator).toBeDefined();
expect(container.getResourceHandler).toBeDefined();
expect(container.createResourceHandler).toBeDefined();
expect(container.logger).toBeDefined();
});
- it('should create an authenticator function', () => {
- expect(typeof container.authenticator).toBe('function');
- });
-
it('should create a getResourceHandler function', () => {
expect(typeof container.getResourceHandler).toBe('function');
});
@@ -74,14 +69,4 @@ describe('Container', () => {
expect(result).toBeDefined();
expect(result.statusCode).toBeDefined();
});
-
- it('should create authenticator that can be called', async () => {
- const mockEvent = {
- headers: { Authorization: 'Bearer test-token' },
- };
-
- const result = await container.authenticator(mockEvent);
- expect(result).toBeDefined();
- expect(result.isValid).toBeDefined();
- });
});
diff --git a/lambdas/pdm-mock-lambda/src/__tests__/index.test.ts b/lambdas/pdm-mock-lambda/src/__tests__/index.test.ts
index a056396bc..2453cacdd 100644
--- a/lambdas/pdm-mock-lambda/src/__tests__/index.test.ts
+++ b/lambdas/pdm-mock-lambda/src/__tests__/index.test.ts
@@ -66,7 +66,6 @@ const createMockEvent = (
};
describe('Lambda Handler Integration', () => {
- let mockAuthenticator: jest.Mock;
let mockGetResourceHandler: jest.Mock;
let mockCreateResourceHandler: jest.Mock;
@@ -74,33 +73,11 @@ describe('Lambda Handler Integration', () => {
jest.clearAllMocks();
const container = createContainer();
- mockAuthenticator = container.authenticator as jest.Mock;
mockGetResourceHandler = container.getResourceHandler as jest.Mock;
mockCreateResourceHandler = container.createResourceHandler as jest.Mock;
});
- it('should return authentication error when authentication fails', async () => {
- mockAuthenticator.mockResolvedValue({
- isValid: false,
- error: {
- statusCode: 401,
- body: JSON.stringify({ error: 'Unauthorized' }),
- },
- });
-
- const event = createMockEvent();
- const response = (await handler(
- event,
- {} as Context,
- {} as Callback,
- )) as APIGatewayProxyResult;
-
- expect(response.statusCode).toBe(401);
- expect(mockGetResourceHandler).not.toHaveBeenCalled();
- });
-
it('should route GET requests to getResourceHandler', async () => {
- mockAuthenticator.mockResolvedValue({ isValid: true });
mockGetResourceHandler.mockResolvedValue({
statusCode: 200,
body: JSON.stringify({ id: 'test-id' }),
@@ -117,13 +94,11 @@ describe('Lambda Handler Integration', () => {
{} as Callback,
)) as APIGatewayProxyResult;
- expect(mockAuthenticator).toHaveBeenCalledWith(event);
expect(mockGetResourceHandler).toHaveBeenCalledWith(event);
expect(response.statusCode).toBe(200);
});
it('should route POST requests to createResourceHandler', async () => {
- mockAuthenticator.mockResolvedValue({ isValid: true });
mockCreateResourceHandler.mockResolvedValue({
statusCode: 201,
body: JSON.stringify({ id: 'new-id' }),
@@ -141,14 +116,11 @@ describe('Lambda Handler Integration', () => {
{} as Callback,
)) as APIGatewayProxyResult;
- expect(mockAuthenticator).toHaveBeenCalledWith(event);
expect(mockCreateResourceHandler).toHaveBeenCalledWith(event);
expect(response.statusCode).toBe(201);
});
it('should return 404 for unsupported endpoints', async () => {
- mockAuthenticator.mockResolvedValue({ isValid: true });
-
const event = createMockEvent({
httpMethod: 'DELETE',
path: '/unsupported',
@@ -165,7 +137,7 @@ describe('Lambda Handler Integration', () => {
});
it('should handle unexpected errors gracefully', async () => {
- mockAuthenticator.mockRejectedValue(new Error('Unexpected error'));
+ mockGetResourceHandler.mockRejectedValue(new Error('Unexpected error'));
const event = createMockEvent();
const response = (await handler(
diff --git a/lambdas/pdm-mock-lambda/src/authenticator.ts b/lambdas/pdm-mock-lambda/src/authenticator.ts
deleted file mode 100644
index 000de2dbe..000000000
--- a/lambdas/pdm-mock-lambda/src/authenticator.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-import type { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
-import type { Logger } from 'utils';
-
-export type AuthResult =
- | { isValid: true }
- | { isValid: false; error: APIGatewayProxyResult };
-
-export const createAuthenticator = (logger: Logger) => {
- return async (
- event: Pick,
- ): Promise => {
- const authHeader =
- event.headers?.Authorization || event.headers?.authorization;
-
- if (!authHeader) {
- logger.warn('Missing Authorization header');
- return {
- isValid: false,
- error: {
- statusCode: 401,
- body: JSON.stringify({
- resourceType: 'OperationOutcome',
- issue: [
- {
- severity: 'error',
- code: 'forbidden',
- details: {
- coding: [{ code: 'ACCESS_DENIED' }],
- },
- diagnostics: 'Missing Authentication Token',
- },
- ],
- }),
- },
- };
- }
-
- const [tokenType] = authHeader.split(' ');
-
- if (tokenType !== 'Bearer') {
- logger.warn(tokenType, 'Invalid token type');
- return {
- isValid: false,
- error: {
- statusCode: 401,
- body: JSON.stringify({
- resourceType: 'OperationOutcome',
- issue: [
- {
- severity: 'error',
- code: 'forbidden',
- details: {
- coding: [{ code: 'ACCESS_DENIED' }],
- },
- diagnostics: 'Invalid Access Token',
- },
- ],
- }),
- },
- };
- }
-
- logger.debug('Authentication successful');
- return { isValid: true };
- };
-};
diff --git a/lambdas/pdm-mock-lambda/src/container.ts b/lambdas/pdm-mock-lambda/src/container.ts
index 2824c4652..c8e8caea6 100644
--- a/lambdas/pdm-mock-lambda/src/container.ts
+++ b/lambdas/pdm-mock-lambda/src/container.ts
@@ -1,25 +1,20 @@
import { logger } from 'utils';
-import { createAuthenticator } from 'authenticator';
import {
createCreateResourceHandler,
createGetResourceHandler,
} from 'handlers';
export interface Container {
- authenticator: ReturnType;
getResourceHandler: ReturnType;
createResourceHandler: ReturnType;
logger: typeof logger;
}
export const createContainer = (): Container => {
- const authenticator = createAuthenticator(logger);
-
const getResourceHandler = createGetResourceHandler(logger);
const createResourceHandler = createCreateResourceHandler(logger);
return {
- authenticator,
getResourceHandler,
createResourceHandler,
logger,
diff --git a/lambdas/pdm-mock-lambda/src/index.ts b/lambdas/pdm-mock-lambda/src/index.ts
index d1d185d1e..49b36cefb 100644
--- a/lambdas/pdm-mock-lambda/src/index.ts
+++ b/lambdas/pdm-mock-lambda/src/index.ts
@@ -11,8 +11,7 @@ export const handler: Handler<
APIGatewayProxyEvent,
APIGatewayProxyResult
> = async (event: APIGatewayProxyEvent): Promise => {
- const { authenticator, createResourceHandler, getResourceHandler, logger } =
- container;
+ const { createResourceHandler, getResourceHandler, logger } = container;
try {
const { requestId } = event.requestContext;
@@ -26,12 +25,6 @@ export const handler: Handler<
hasAuth: !!event.headers?.Authorization,
});
- const authResult = await authenticator(event);
- if (!authResult.isValid) {
- logger.warn('Authentication failed', { requestId, httpMethod, path });
- return authResult.error;
- }
-
if (
httpMethod === 'GET' &&
path.includes('/patient-data-manager/FHIR/R4/DocumentReference/')
From 4f007c98bd7269690d4d712cb37286214822468f Mon Sep 17 00:00:00 2001
From: Gareth Allan <157592212+gareth-allan@users.noreply.github.com>
Date: Mon, 9 Mar 2026 12:10:48 +0000
Subject: [PATCH 04/15] CCM-14325: Update PDM upload rejected component test
---
infrastructure/terraform/components/dl/locals.tf | 2 +-
.../pdm-uploader.component.spec.ts | 9 ++-------
2 files changed, 3 insertions(+), 8 deletions(-)
diff --git a/infrastructure/terraform/components/dl/locals.tf b/infrastructure/terraform/components/dl/locals.tf
index 30c199a62..07f8842f7 100644
--- a/infrastructure/terraform/components/dl/locals.tf
+++ b/infrastructure/terraform/components/dl/locals.tf
@@ -4,7 +4,7 @@ locals {
apim_keystore_s3_bucket = "nhs-${var.aws_account_id}-${var.region}-${var.environment}-${var.component}-static-assets"
apim_private_key_ssm_parameter_name = "/${var.component}/${var.environment}/apim/private_key"
aws_lambda_functions_dir_path = "../../../../lambdas"
- pdm_access_token_ssm_parameter_name = var.enable_pdm_mock ? "" : "${local.apim_access_token_ssm_parameter_name}"
+ pdm_access_token_ssm_parameter_name = var.enable_pdm_mock ? "" : local.apim_access_token_ssm_parameter_name
pdm_url = var.enable_pdm_mock ? aws_api_gateway_stage.pdm_mock[0].invoke_url : var.apim_base_url
firehose_output_path_prefix = "kinesis-firehose-output"
log_destination_arn = "arn:aws:logs:${var.region}:${var.shared_infra_account_id}:destination:nhs-main-obs-firehose-logs"
diff --git a/tests/playwright/digital-letters-component-tests/pdm-uploader.component.spec.ts b/tests/playwright/digital-letters-component-tests/pdm-uploader.component.spec.ts
index 276c9ffd7..ce5eab2bc 100644
--- a/tests/playwright/digital-letters-component-tests/pdm-uploader.component.spec.ts
+++ b/tests/playwright/digital-letters-component-tests/pdm-uploader.component.spec.ts
@@ -114,20 +114,15 @@ test.describe('Digital Letters - Upload to PDM', () => {
});
test('should send a pdm.resource.submission.rejected event following an error from PDM', async () => {
- // Note: I suspect this will fail once we are using the PDM Mock and will need amending.
const eventId = uuidv4();
const letterId = uuidv4();
const resourceKey = `test/${letterId}`;
const messageUri = `s3://${LETTERS_S3_BUCKET_NAME}/${resourceKey}`;
- const messageReference = uuidv4();
+ const messageReference = 'error-500-internal'; // This reference causes the PDM mock to return an error.
const senderId = SENDER_ID_SKIPS_NOTIFY;
const meshMessageId = '12345';
- const invalidPdmRequest = {
- ...pdmRequest,
- unexpectedField: 'I should not be here',
- };
- await putDataS3(invalidPdmRequest, {
+ await putDataS3(pdmRequest, {
Bucket: LETTERS_S3_BUCKET_NAME,
Key: resourceKey,
});
From 2fe819e77bbc5dc896c7d2a5d6ea39145db2b07e Mon Sep 17 00:00:00 2001
From: Gareth Allan <157592212+gareth-allan@users.noreply.github.com>
Date: Mon, 9 Mar 2026 13:51:38 +0000
Subject: [PATCH 05/15] CCM-14325: Disable PDM mock by default
---
infrastructure/terraform/components/dl/README.md | 2 +-
infrastructure/terraform/components/dl/variables.tf | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/infrastructure/terraform/components/dl/README.md b/infrastructure/terraform/components/dl/README.md
index 786ba961e..37fb64fb8 100644
--- a/infrastructure/terraform/components/dl/README.md
+++ b/infrastructure/terraform/components/dl/README.md
@@ -23,7 +23,7 @@ No requirements.
| [enable\_event\_anomaly\_detection](#input\_enable\_event\_anomaly\_detection) | Enable CloudWatch anomaly detection alarm for core notifier queue message reception | `bool` | `true` | no |
| [enable\_event\_cache](#input\_enable\_event\_cache) | Enable caching of events to an S3 bucket | `bool` | `true` | no |
| [enable\_mock\_mesh](#input\_enable\_mock\_mesh) | Enable mock mesh access (dev only). Grants lambda permission to read mock-mesh prefix in non-pii bucket. | `bool` | `false` | no |
-| [enable\_pdm\_mock](#input\_enable\_pdm\_mock) | Flag indicating whether to deploy PDM mock API (should be false in production environments) | `bool` | `true` | no |
+| [enable\_pdm\_mock](#input\_enable\_pdm\_mock) | Flag indicating whether to deploy PDM mock API (should be false in production environments) | `bool` | `false` | no |
| [enable\_sns\_delivery\_logging](#input\_enable\_sns\_delivery\_logging) | Enable SNS Delivery Failure Notifications | `bool` | `true` | no |
| [environment](#input\_environment) | The name of the tfscaffold environment | `string` | n/a | yes |
| [event\_anomaly\_band\_width](#input\_event\_anomaly\_band\_width) | The width of the anomaly detection band. Higher values (e.g. 4-6) reduce sensitivity and noise, lower values (e.g. 2-3) increase sensitivity. Recommended: 2-4. | `number` | `3` | no |
diff --git a/infrastructure/terraform/components/dl/variables.tf b/infrastructure/terraform/components/dl/variables.tf
index 700e1e666..1c68e5134 100644
--- a/infrastructure/terraform/components/dl/variables.tf
+++ b/infrastructure/terraform/components/dl/variables.tf
@@ -166,7 +166,7 @@ variable "force_destroy" {
variable "enable_pdm_mock" {
type = bool
description = "Flag indicating whether to deploy PDM mock API (should be false in production environments)"
- default = true
+ default = false
}
variable "aws_account_type" {
From 128076f1b0592c9a19146f86c6151a60d4af7188 Mon Sep 17 00:00:00 2001
From: Gareth Allan <157592212+gareth-allan@users.noreply.github.com>
Date: Mon, 9 Mar 2026 16:43:13 +0000
Subject: [PATCH 06/15] CCM-14325: Fix core notifier in fresh dynamic
environments
---
infrastructure/terraform/components/dl/README.md | 1 +
.../components/dl/module_lambda_core_notifier.tf | 2 +-
infrastructure/terraform/components/dl/variables.tf | 11 +++++++++++
3 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/infrastructure/terraform/components/dl/README.md b/infrastructure/terraform/components/dl/README.md
index 37fb64fb8..fc6491069 100644
--- a/infrastructure/terraform/components/dl/README.md
+++ b/infrastructure/terraform/components/dl/README.md
@@ -19,6 +19,7 @@ No requirements.
| [core\_notify\_url](#input\_core\_notify\_url) | The URL used to send requests to Notify | `string` | `"https://sandbox.api.service.nhs.uk"` | no |
| [default\_cloudwatch\_event\_bus\_name](#input\_default\_cloudwatch\_event\_bus\_name) | The name of the default cloudwatch event bus. This is needed as GuardDuty Scan Result events are sent to the default bus | `string` | `"default"` | no |
| [default\_tags](#input\_default\_tags) | A map of default tags to apply to all taggable resources within the component | `map(string)` | `{}` | no |
+| [enable\_core\_notify\_auth](#input\_enable\_core\_notify\_auth) | Whether to send auth tokens with core notify API calls. | `bool` | `true` | no |
| [enable\_dynamodb\_delete\_protection](#input\_enable\_dynamodb\_delete\_protection) | Enable DynamoDB Delete Protection on all Tables | `bool` | `true` | no |
| [enable\_event\_anomaly\_detection](#input\_enable\_event\_anomaly\_detection) | Enable CloudWatch anomaly detection alarm for core notifier queue message reception | `bool` | `true` | no |
| [enable\_event\_cache](#input\_enable\_event\_cache) | Enable caching of events to an S3 bucket | `bool` | `true` | no |
diff --git a/infrastructure/terraform/components/dl/module_lambda_core_notifier.tf b/infrastructure/terraform/components/dl/module_lambda_core_notifier.tf
index b8afbba60..f1a62b1ad 100644
--- a/infrastructure/terraform/components/dl/module_lambda_core_notifier.tf
+++ b/infrastructure/terraform/components/dl/module_lambda_core_notifier.tf
@@ -36,7 +36,7 @@ module "core_notifier" {
lambda_env_vars = {
"APIM_BASE_URL" = var.core_notify_url
- "APIM_ACCESS_TOKEN_SSM_PARAMETER_NAME" = local.apim_access_token_ssm_parameter_name
+ "APIM_ACCESS_TOKEN_SSM_PARAMETER_NAME" = var.enable_core_notify_auth ? local.apim_access_token_ssm_parameter_name : ""
"EVENT_PUBLISHER_EVENT_BUS_ARN" = aws_cloudwatch_event_bus.main.arn
"EVENT_PUBLISHER_DLQ_URL" = module.sqs_event_publisher_errors.sqs_queue_url
"ENVIRONMENT" = var.environment
diff --git a/infrastructure/terraform/components/dl/variables.tf b/infrastructure/terraform/components/dl/variables.tf
index 1c68e5134..64439ee8c 100644
--- a/infrastructure/terraform/components/dl/variables.tf
+++ b/infrastructure/terraform/components/dl/variables.tf
@@ -134,6 +134,17 @@ variable "core_notify_url" {
default = "https://sandbox.api.service.nhs.uk"
}
+variable "enable_core_notify_auth" {
+ type = bool
+ description = "Whether to send auth tokens with core notify API calls."
+ default = true
+
+ validation {
+ condition = var.environment == "prod" ? var.enable_core_notify_auth == true : true
+ error_message = "enable_core_notify_auth must be set to true when environment is 'prod'."
+ }
+}
+
variable "apim_auth_token_url" {
type = string
description = "URL to generate an APIM auth token"
From 4e11eaca70f501e71da97eda96cdd739c3bd441a Mon Sep 17 00:00:00 2001
From: Gareth Allan <157592212+gareth-allan@users.noreply.github.com>
Date: Tue, 10 Mar 2026 11:56:40 +0000
Subject: [PATCH 07/15] CCM-14325: Code review fixes
---
lambdas/pdm-mock-lambda/src/__tests__/index.test.ts | 2 --
.../pdm-uploader.component.spec.ts | 6 +++++-
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/lambdas/pdm-mock-lambda/src/__tests__/index.test.ts b/lambdas/pdm-mock-lambda/src/__tests__/index.test.ts
index 2453cacdd..a00e58362 100644
--- a/lambdas/pdm-mock-lambda/src/__tests__/index.test.ts
+++ b/lambdas/pdm-mock-lambda/src/__tests__/index.test.ts
@@ -8,7 +8,6 @@ import { createContainer } from 'container';
import { handler } from '..';
jest.mock('container', () => {
- const mockAuthenticator = jest.fn();
const mockGetResourceHandler = jest.fn();
const mockCreateResourceHandler = jest.fn();
const mockLogger = {
@@ -21,7 +20,6 @@ jest.mock('container', () => {
return {
createContainer: jest.fn(() => ({
- authenticator: mockAuthenticator,
getResourceHandler: mockGetResourceHandler,
createResourceHandler: mockCreateResourceHandler,
logger: mockLogger,
diff --git a/tests/playwright/digital-letters-component-tests/pdm-uploader.component.spec.ts b/tests/playwright/digital-letters-component-tests/pdm-uploader.component.spec.ts
index ce5eab2bc..f45c43aac 100644
--- a/tests/playwright/digital-letters-component-tests/pdm-uploader.component.spec.ts
+++ b/tests/playwright/digital-letters-component-tests/pdm-uploader.component.spec.ts
@@ -121,8 +121,12 @@ test.describe('Digital Letters - Upload to PDM', () => {
const messageReference = 'error-500-internal'; // This reference causes the PDM mock to return an error.
const senderId = SENDER_ID_SKIPS_NOTIFY;
const meshMessageId = '12345';
+ const invalidPdmRequest = {
+ ...pdmRequest,
+ unexpectedField: 'I should not be here',
+ };
- await putDataS3(pdmRequest, {
+ await putDataS3(invalidPdmRequest, {
Bucket: LETTERS_S3_BUCKET_NAME,
Key: resourceKey,
});
From 76e993323aa5486e5a0af8a8b582023a88996aa6 Mon Sep 17 00:00:00 2001
From: Gareth Allan <157592212+gareth-allan@users.noreply.github.com>
Date: Tue, 10 Mar 2026 11:59:43 +0000
Subject: [PATCH 08/15] CCM-14325: Update flag name
---
infrastructure/terraform/components/dl/README.md | 2 +-
.../terraform/components/dl/module_lambda_core_notifier.tf | 2 +-
infrastructure/terraform/components/dl/variables.tf | 6 +++---
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/infrastructure/terraform/components/dl/README.md b/infrastructure/terraform/components/dl/README.md
index fc6491069..c399ebf32 100644
--- a/infrastructure/terraform/components/dl/README.md
+++ b/infrastructure/terraform/components/dl/README.md
@@ -16,10 +16,10 @@ No requirements.
| [aws\_account\_id](#input\_aws\_account\_id) | The AWS Account ID (numeric) | `string` | n/a | yes |
| [aws\_account\_type](#input\_aws\_account\_type) | The AWS Account Type | `string` | n/a | yes |
| [component](#input\_component) | The variable encapsulating the name of this component | `string` | `"dl"` | no |
+| [core\_notify\_include\_auth\_header](#input\_core\_notify\_include\_auth\_header) | Whether to send auth tokens with core notify API calls. | `bool` | `true` | no |
| [core\_notify\_url](#input\_core\_notify\_url) | The URL used to send requests to Notify | `string` | `"https://sandbox.api.service.nhs.uk"` | no |
| [default\_cloudwatch\_event\_bus\_name](#input\_default\_cloudwatch\_event\_bus\_name) | The name of the default cloudwatch event bus. This is needed as GuardDuty Scan Result events are sent to the default bus | `string` | `"default"` | no |
| [default\_tags](#input\_default\_tags) | A map of default tags to apply to all taggable resources within the component | `map(string)` | `{}` | no |
-| [enable\_core\_notify\_auth](#input\_enable\_core\_notify\_auth) | Whether to send auth tokens with core notify API calls. | `bool` | `true` | no |
| [enable\_dynamodb\_delete\_protection](#input\_enable\_dynamodb\_delete\_protection) | Enable DynamoDB Delete Protection on all Tables | `bool` | `true` | no |
| [enable\_event\_anomaly\_detection](#input\_enable\_event\_anomaly\_detection) | Enable CloudWatch anomaly detection alarm for core notifier queue message reception | `bool` | `true` | no |
| [enable\_event\_cache](#input\_enable\_event\_cache) | Enable caching of events to an S3 bucket | `bool` | `true` | no |
diff --git a/infrastructure/terraform/components/dl/module_lambda_core_notifier.tf b/infrastructure/terraform/components/dl/module_lambda_core_notifier.tf
index f1a62b1ad..048c4d289 100644
--- a/infrastructure/terraform/components/dl/module_lambda_core_notifier.tf
+++ b/infrastructure/terraform/components/dl/module_lambda_core_notifier.tf
@@ -36,7 +36,7 @@ module "core_notifier" {
lambda_env_vars = {
"APIM_BASE_URL" = var.core_notify_url
- "APIM_ACCESS_TOKEN_SSM_PARAMETER_NAME" = var.enable_core_notify_auth ? local.apim_access_token_ssm_parameter_name : ""
+ "APIM_ACCESS_TOKEN_SSM_PARAMETER_NAME" = var.core_notify_include_auth_header ? local.apim_access_token_ssm_parameter_name : ""
"EVENT_PUBLISHER_EVENT_BUS_ARN" = aws_cloudwatch_event_bus.main.arn
"EVENT_PUBLISHER_DLQ_URL" = module.sqs_event_publisher_errors.sqs_queue_url
"ENVIRONMENT" = var.environment
diff --git a/infrastructure/terraform/components/dl/variables.tf b/infrastructure/terraform/components/dl/variables.tf
index 64439ee8c..7cb28ff09 100644
--- a/infrastructure/terraform/components/dl/variables.tf
+++ b/infrastructure/terraform/components/dl/variables.tf
@@ -134,14 +134,14 @@ variable "core_notify_url" {
default = "https://sandbox.api.service.nhs.uk"
}
-variable "enable_core_notify_auth" {
+variable "core_notify_include_auth_header" {
type = bool
description = "Whether to send auth tokens with core notify API calls."
default = true
validation {
- condition = var.environment == "prod" ? var.enable_core_notify_auth == true : true
- error_message = "enable_core_notify_auth must be set to true when environment is 'prod'."
+ condition = var.environment != "dev" ? var.core_notify_include_auth_header == true : true
+ error_message = "core_notify_include_auth_header must be set to true when environment is not 'dev'."
}
}
From 26ea8ae01de504078b78cef761ba7a37330f7eb6 Mon Sep 17 00:00:00 2001
From: Gareth Allan <157592212+gareth-allan@users.noreply.github.com>
Date: Tue, 10 Mar 2026 14:11:01 +0000
Subject: [PATCH 09/15] CCM-14325: Fix variable validation
---
infrastructure/terraform/components/dl/variables.tf | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/infrastructure/terraform/components/dl/variables.tf b/infrastructure/terraform/components/dl/variables.tf
index 7cb28ff09..61cc23bbb 100644
--- a/infrastructure/terraform/components/dl/variables.tf
+++ b/infrastructure/terraform/components/dl/variables.tf
@@ -140,8 +140,8 @@ variable "core_notify_include_auth_header" {
default = true
validation {
- condition = var.environment != "dev" ? var.core_notify_include_auth_header == true : true
- error_message = "core_notify_include_auth_header must be set to true when environment is not 'dev'."
+ condition = var.environment == "prod" ? var.core_notify_include_auth_header == true : true
+ error_message = "core_notify_include_auth_header must be set to true when environment is 'prod'."
}
}
From ac43ee55fb6368e9d54a8e4522314083a4770212 Mon Sep 17 00:00:00 2001
From: Ian Hodges
Date: Fri, 13 Mar 2026 08:16:14 +0000
Subject: [PATCH 10/15] CCM-14325: update mock PDM to allow unique error
trigger values
---
.../pdm-mock-lambda/src/__tests__/handlers.test.ts | 14 +++++++-------
lambdas/pdm-mock-lambda/src/handlers.ts | 4 ++--
.../pdm-uploader.component.spec.ts | 10 ++++++++--
3 files changed, 17 insertions(+), 11 deletions(-)
diff --git a/lambdas/pdm-mock-lambda/src/__tests__/handlers.test.ts b/lambdas/pdm-mock-lambda/src/__tests__/handlers.test.ts
index d70357243..3743aa4e6 100644
--- a/lambdas/pdm-mock-lambda/src/__tests__/handlers.test.ts
+++ b/lambdas/pdm-mock-lambda/src/__tests__/handlers.test.ts
@@ -157,37 +157,37 @@ describe('GET Resource Handler', () => {
describe('error scenarios', () => {
it.each([
{
- id: 'error-400-invalid',
+ id: 'error-400-invalid-a1b2c3',
expectedStatus: 400,
expectedCode: 'INVALID_VALUE',
},
{
- id: 'error-401-unauthorized',
+ id: 'error-401-unauthorized-d4e5f6',
expectedStatus: 401,
expectedCode: 'UNAUTHORISED',
},
{
- id: 'error-403-forbidden',
+ id: 'error-403-forbidden-7g8h9i',
expectedStatus: 403,
expectedCode: 'FORBIDDEN',
},
{
- id: 'error-404-notfound',
+ id: 'error-404-notfound-a1b2c3',
expectedStatus: 404,
expectedCode: 'RESOURCE_NOT_FOUND',
},
{
- id: 'error-429-ratelimit',
+ id: 'error-429-ratelimit-j8f6l1',
expectedStatus: 429,
expectedCode: 'TOO_MANY_REQUESTS',
},
{
- id: 'error-500-internal',
+ id: 'error-500-internal-i9j0k1',
expectedStatus: 500,
expectedCode: 'INTERNAL_ERROR',
},
{
- id: 'error-503-unavailable',
+ id: 'error-503-unavailable-j1k2l3',
expectedStatus: 503,
expectedCode: 'SERVICE_UNAVAILABLE',
},
diff --git a/lambdas/pdm-mock-lambda/src/handlers.ts b/lambdas/pdm-mock-lambda/src/handlers.ts
index a7b5ad1d2..6d8d257fe 100644
--- a/lambdas/pdm-mock-lambda/src/handlers.ts
+++ b/lambdas/pdm-mock-lambda/src/handlers.ts
@@ -225,7 +225,7 @@ export const createGetResourceHandler = (logger: Logger) => {
);
}
- const errorScenario = ERROR_SCENARIOS.find((s) => s.id === resourceId);
+ const errorScenario = ERROR_SCENARIOS.find((s) => s.id.startsWith(resourceId));
if (errorScenario) {
logger.debug('Triggering error scenario', {
resourceId,
@@ -293,7 +293,7 @@ export const createCreateResourceHandler = (logger: Logger) => {
requestId,
});
- const errorScenario = ERROR_SCENARIOS.find((s) => s.id === resourceId);
+ const errorScenario = ERROR_SCENARIOS.find((s) => s.id.startsWith(resourceId));
if (errorScenario) {
logger.debug('Triggering error scenario', {
resourceId,
diff --git a/tests/playwright/digital-letters-component-tests/pdm-uploader.component.spec.ts b/tests/playwright/digital-letters-component-tests/pdm-uploader.component.spec.ts
index 4a9d0c146..b01d6b12f 100644
--- a/tests/playwright/digital-letters-component-tests/pdm-uploader.component.spec.ts
+++ b/tests/playwright/digital-letters-component-tests/pdm-uploader.component.spec.ts
@@ -114,16 +114,22 @@ test.describe('Digital Letters - Upload to PDM', () => {
});
test('should send a pdm.resource.submission.rejected event following an error from PDM', async () => {
+ // Two mechanisms are used to trigger errors from PDM in this test
+ // - the first is a specific messageReference which the mock PDM is configured to return an error for.
+ // - the second is an unexpected field in the PDM request which causes the real PDM to return an error.
+ const messageReference = `error-500-internal-${uuidv4()}`;
+ const unexpectedField = 'I should not be here';
+
const eventId = uuidv4();
const letterId = uuidv4();
const resourceKey = `test/${letterId}`;
const messageUri = `s3://${LETTERS_S3_BUCKET_NAME}/${resourceKey}`;
- const messageReference = 'error-500-internal'; // This reference causes the PDM mock to return an error.
const senderId = SENDER_ID_SKIPS_NOTIFY;
const meshMessageId = '12345';
+
const invalidPdmRequest = {
...pdmRequest,
- unexpectedField: 'I should not be here',
+ unexpectedField
};
await putDataS3(invalidPdmRequest, {
From 48c7556686c5d0ed42bdadf23babb88abb91ae44 Mon Sep 17 00:00:00 2001
From: Ian Hodges
Date: Fri, 13 Mar 2026 08:16:58 +0000
Subject: [PATCH 11/15] CCM-14325: fix for incorrect file prefix
---
.../terraform/components/dl/module_lambda_file_scanner.tf | 2 +-
.../file-scanner.component.spec.ts | 5 +++--
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/infrastructure/terraform/components/dl/module_lambda_file_scanner.tf b/infrastructure/terraform/components/dl/module_lambda_file_scanner.tf
index f5aa878c1..8c82c5caf 100644
--- a/infrastructure/terraform/components/dl/module_lambda_file_scanner.tf
+++ b/infrastructure/terraform/components/dl/module_lambda_file_scanner.tf
@@ -37,7 +37,7 @@ module "file_scanner" {
lambda_env_vars = {
"DOCUMENT_REFERENCE_BUCKET" = module.s3bucket_pii_data.bucket
"UNSCANNED_FILES_BUCKET" = local.unscanned_files_bucket
- "UNSCANNED_FILES_PATH_PREFIX" = var.environment
+ "UNSCANNED_FILES_PATH_PREFIX" = local.csi
"EVENT_PUBLISHER_EVENT_BUS_ARN" = aws_cloudwatch_event_bus.main.arn
"EVENT_PUBLISHER_DLQ_URL" = module.sqs_event_publisher_errors.sqs_queue_url
}
diff --git a/tests/playwright/digital-letters-component-tests/file-scanner.component.spec.ts b/tests/playwright/digital-letters-component-tests/file-scanner.component.spec.ts
index 1a394d32e..48b277fb7 100644
--- a/tests/playwright/digital-letters-component-tests/file-scanner.component.spec.ts
+++ b/tests/playwright/digital-letters-component-tests/file-scanner.component.spec.ts
@@ -2,6 +2,7 @@ import { expect, test } from '@playwright/test';
import {
ENV,
FILE_SCANNER_DLQ_NAME,
+ PREFIX_DL_FILES,
REGION,
} from 'constants/backend-constants';
import itemDequeuedValidator from 'digital-letters-events/ItemDequeued.js';
@@ -28,7 +29,7 @@ test.describe('File Scanner', () => {
test('should extract PDF from DocumentReference and store in unscanned bucket with metadata', async () => {
const messageReference = uuidv4();
const senderId = 'TEST_SENDER_001';
- const documentReferenceKey = messageReference;
+ const documentReferenceKey = `${PREFIX_DL_FILES}${messageReference}`;
const pdfContent = Buffer.from('Sample PDF content for test');
const documentReference = {
@@ -80,7 +81,7 @@ test('should extract PDF from DocumentReference and store in unscanned bucket wi
);
await expectToPassEventually(async () => {
- const expectedKey = `${ENV}/${messageReference}.pdf`;
+ const expectedKey = `${PREFIX_DL_FILES}${messageReference}.pdf`;
const expectedUri = `s3://${UNSCANNED_FILES_BUCKET}/${expectedKey}`;
const storedPdf = await getS3ObjectBufferFromUri(expectedUri);
From dddd7a51fc9b76324a7ca0b21f8195a2a163c6a3 Mon Sep 17 00:00:00 2001
From: Ian Hodges
Date: Fri, 13 Mar 2026 08:24:42 +0000
Subject: [PATCH 12/15] CCM-14325: linting
---
lambdas/pdm-mock-lambda/src/handlers.ts | 8 ++++++--
.../pdm-uploader.component.spec.ts | 2 +-
2 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/lambdas/pdm-mock-lambda/src/handlers.ts b/lambdas/pdm-mock-lambda/src/handlers.ts
index 6d8d257fe..bb0334963 100644
--- a/lambdas/pdm-mock-lambda/src/handlers.ts
+++ b/lambdas/pdm-mock-lambda/src/handlers.ts
@@ -225,7 +225,9 @@ export const createGetResourceHandler = (logger: Logger) => {
);
}
- const errorScenario = ERROR_SCENARIOS.find((s) => s.id.startsWith(resourceId));
+ const errorScenario = ERROR_SCENARIOS.find((s) =>
+ s.id.startsWith(resourceId),
+ );
if (errorScenario) {
logger.debug('Triggering error scenario', {
resourceId,
@@ -293,7 +295,9 @@ export const createCreateResourceHandler = (logger: Logger) => {
requestId,
});
- const errorScenario = ERROR_SCENARIOS.find((s) => s.id.startsWith(resourceId));
+ const errorScenario = ERROR_SCENARIOS.find((s) =>
+ s.id.startsWith(resourceId),
+ );
if (errorScenario) {
logger.debug('Triggering error scenario', {
resourceId,
diff --git a/tests/playwright/digital-letters-component-tests/pdm-uploader.component.spec.ts b/tests/playwright/digital-letters-component-tests/pdm-uploader.component.spec.ts
index b01d6b12f..e5ba36dcd 100644
--- a/tests/playwright/digital-letters-component-tests/pdm-uploader.component.spec.ts
+++ b/tests/playwright/digital-letters-component-tests/pdm-uploader.component.spec.ts
@@ -129,7 +129,7 @@ test.describe('Digital Letters - Upload to PDM', () => {
const invalidPdmRequest = {
...pdmRequest,
- unexpectedField
+ unexpectedField,
};
await putDataS3(invalidPdmRequest, {
From 2603d12cd705a5d092d2746808bd686d382c2d16 Mon Sep 17 00:00:00 2001
From: Ian Hodges
Date: Fri, 13 Mar 2026 08:34:31 +0000
Subject: [PATCH 13/15] CCM-14325: fix logic
---
lambdas/pdm-mock-lambda/src/handlers.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lambdas/pdm-mock-lambda/src/handlers.ts b/lambdas/pdm-mock-lambda/src/handlers.ts
index bb0334963..cf3519fd6 100644
--- a/lambdas/pdm-mock-lambda/src/handlers.ts
+++ b/lambdas/pdm-mock-lambda/src/handlers.ts
@@ -226,7 +226,7 @@ export const createGetResourceHandler = (logger: Logger) => {
}
const errorScenario = ERROR_SCENARIOS.find((s) =>
- s.id.startsWith(resourceId),
+ resourceId.startsWith(s.id),
);
if (errorScenario) {
logger.debug('Triggering error scenario', {
@@ -296,7 +296,7 @@ export const createCreateResourceHandler = (logger: Logger) => {
});
const errorScenario = ERROR_SCENARIOS.find((s) =>
- s.id.startsWith(resourceId),
+ resourceId.startsWith(s.id),
);
if (errorScenario) {
logger.debug('Triggering error scenario', {
From ca62294c691edba62e848a91e02d657b0c52b223 Mon Sep 17 00:00:00 2001
From: Ian Hodges
Date: Tue, 17 Mar 2026 11:50:58 +0000
Subject: [PATCH 14/15] CCM-14325: revert tf module downgrade
---
infrastructure/terraform/components/dl/README.md | 2 +-
.../terraform/components/dl/module_lambda_pdm_mock.tf | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/infrastructure/terraform/components/dl/README.md b/infrastructure/terraform/components/dl/README.md
index 8cfd41bca..114d77e76 100644
--- a/infrastructure/terraform/components/dl/README.md
+++ b/infrastructure/terraform/components/dl/README.md
@@ -70,7 +70,7 @@ No requirements.
| [mesh\_download](#module\_mesh\_download) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/3.0.6/terraform-lambda.zip | n/a |
| [mesh\_poll](#module\_mesh\_poll) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/3.0.6/terraform-lambda.zip | n/a |
| [move\_scanned\_files](#module\_move\_scanned\_files) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/3.0.6/terraform-lambda.zip | n/a |
-| [pdm\_mock](#module\_pdm\_mock) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.29/terraform-lambda.zip | n/a |
+| [pdm\_mock](#module\_pdm\_mock) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/3.0.6/terraform-lambda.zip | n/a |
| [pdm\_poll](#module\_pdm\_poll) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/3.0.6/terraform-lambda.zip | n/a |
| [pdm\_uploader](#module\_pdm\_uploader) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/3.0.6/terraform-lambda.zip | n/a |
| [print\_analyser](#module\_print\_analyser) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/3.0.6/terraform-lambda.zip | n/a |
diff --git a/infrastructure/terraform/components/dl/module_lambda_pdm_mock.tf b/infrastructure/terraform/components/dl/module_lambda_pdm_mock.tf
index f2ca8c596..e4f04231c 100644
--- a/infrastructure/terraform/components/dl/module_lambda_pdm_mock.tf
+++ b/infrastructure/terraform/components/dl/module_lambda_pdm_mock.tf
@@ -1,6 +1,6 @@
module "pdm_mock" {
count = var.enable_pdm_mock ? 1 : 0
- source = "https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.29/terraform-lambda.zip"
+ source = "https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/3.0.6/terraform-lambda.zip"
function_name = "pdm-mock"
description = "A lambda function for mocking PDM (Patient Data Manager) API endpoints"
From 15404a0745f0dd9869ead347b57f8712ee65319a Mon Sep 17 00:00:00 2001
From: Ian Hodges
Date: Tue, 17 Mar 2026 12:10:56 +0000
Subject: [PATCH 15/15] CCM-14325: trivy fixes
---
.../assets/ADR-003/examples/python/requirements.txt | 2 +-
package-lock.json | 4 +++-
src/eventcatalog/package-lock.json | 12 ++++++------
3 files changed, 10 insertions(+), 8 deletions(-)
diff --git a/docs/adr/assets/ADR-003/examples/python/requirements.txt b/docs/adr/assets/ADR-003/examples/python/requirements.txt
index b7e317b4b..2217ba554 100644
--- a/docs/adr/assets/ADR-003/examples/python/requirements.txt
+++ b/docs/adr/assets/ADR-003/examples/python/requirements.txt
@@ -1,2 +1,2 @@
-PyJWT==2.8.0
+PyJWT==2.12.0
requests==2.32.4
diff --git a/package-lock.json b/package-lock.json
index 4f719db40..177d60c7a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -13677,7 +13677,9 @@
}
},
"node_modules/flatted": {
- "version": "3.3.3",
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.1.tgz",
+ "integrity": "sha512-IxfVbRFVlV8V/yRaGzk0UVIcsKKHMSfYw66T/u4nTwlWteQePsxe//LjudR1AMX4tZW3WFCh3Zqa/sjlqpbURQ==",
"dev": true,
"license": "ISC"
},
diff --git a/src/eventcatalog/package-lock.json b/src/eventcatalog/package-lock.json
index c47f88334..6ca1bd378 100644
--- a/src/eventcatalog/package-lock.json
+++ b/src/eventcatalog/package-lock.json
@@ -12206,9 +12206,9 @@
"license": "Apache-2.0"
},
"node_modules/flatted": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
- "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.1.tgz",
+ "integrity": "sha512-IxfVbRFVlV8V/yRaGzk0UVIcsKKHMSfYw66T/u4nTwlWteQePsxe//LjudR1AMX4tZW3WFCh3Zqa/sjlqpbURQ==",
"license": "ISC"
},
"node_modules/flattie": {
@@ -23622,9 +23622,9 @@
"license": "MIT"
},
"node_modules/undici": {
- "version": "7.22.0",
- "resolved": "https://registry.npmjs.org/undici/-/undici-7.22.0.tgz",
- "integrity": "sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg==",
+ "version": "7.24.4",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-7.24.4.tgz",
+ "integrity": "sha512-BM/JzwwaRXxrLdElV2Uo6cTLEjhSb3WXboncJamZ15NgUURmvlXvxa6xkwIOILIjPNo9i8ku136ZvWV0Uly8+w==",
"license": "MIT",
"engines": {
"node": ">=20.18.1"