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/infrastructure/terraform/components/dl/README.md b/infrastructure/terraform/components/dl/README.md index 959d5e6a1..c399ebf32 100644 --- a/infrastructure/terraform/components/dl/README.md +++ b/infrastructure/terraform/components/dl/README.md @@ -16,6 +16,7 @@ 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 | @@ -23,7 +24,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 | @@ -40,8 +41,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/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..07f8842f7 100644 --- a/infrastructure/terraform/components/dl/locals.tf +++ b/infrastructure/terraform/components/dl/locals.tf @@ -4,7 +4,8 @@ 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_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" mock_mesh_endpoint = "s3://${module.s3bucket_non_pii_data.bucket}/mock-mesh" diff --git a/infrastructure/terraform/components/dl/module_lambda_core_notifier.tf b/infrastructure/terraform/components/dl/module_lambda_core_notifier.tf index b8afbba60..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" = 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/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..c4172356d 100644 --- a/infrastructure/terraform/components/dl/module_lambda_pdm_poll.tf +++ b/infrastructure/terraform/components/dl/module_lambda_pdm_poll.tf @@ -35,8 +35,8 @@ 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_ACCESS_TOKEN_SSM_PARAMETER_NAME" = local.apim_access_token_ssm_parameter_name + "APIM_BASE_URL" = local.pdm_url + "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 6bf6bb396..ca3d8a983 100644 --- a/infrastructure/terraform/components/dl/module_lambda_pdm_uploader.tf +++ b/infrastructure/terraform/components/dl/module_lambda_pdm_uploader.tf @@ -35,8 +35,8 @@ module "pdm_uploader" { log_subscription_role_arn = local.acct.log_subscription_role_arn lambda_env_vars = { - "APIM_BASE_URL" = var.apim_base_url - "APIM_ACCESS_TOKEN_SSM_PARAMETER_NAME" = local.apim_access_token_ssm_parameter_name + "APIM_BASE_URL" = local.pdm_url + "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..61cc23bbb 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" @@ -146,6 +134,17 @@ variable "core_notify_url" { default = "https://sandbox.api.service.nhs.uk" } +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.core_notify_include_auth_header == true : true + error_message = "core_notify_include_auth_header must be set to true when environment is 'prod'." + } +} + variable "apim_auth_token_url" { type = string description = "URL to generate an APIM auth token" @@ -178,7 +177,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" { 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..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, @@ -66,7 +64,6 @@ const createMockEvent = ( }; describe('Lambda Handler Integration', () => { - let mockAuthenticator: jest.Mock; let mockGetResourceHandler: jest.Mock; let mockCreateResourceHandler: jest.Mock; @@ -74,33 +71,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 +92,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 +114,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 +135,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/') 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": { 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..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 @@ -114,12 +114,11 @@ 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 = {