Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
328626a
VED-981 Add base infrastructure for the MNS Publisher feature (#1191)
dlzhry2nhs Feb 12, 2026
605eb2f
VED-981 (Part 2) Add DLQ, redrive policy, and encryption to queues (#…
dlzhry2nhs Feb 16, 2026
7dff1b2
VED-982: Create POST MNS Notification (#1211)
Akol125 Mar 6, 2026
0be8254
VED-000: Refactor Api_clients Authentication (#1278)
amarauzoma Mar 13, 2026
295a1d5
Modify mns publisher infra to account properly for test queue (#1288)
dlzhry2nhs Mar 13, 2026
b49dfe4
remove default apigee env (#1297)
Akol125 Mar 16, 2026
44eef2a
added tests and refactored calculate age for vaccination from bday (#…
avshetty1980 Mar 16, 2026
c101aea
initial commit
FimranNHS Mar 16, 2026
85f7fbc
VED-982: Consolidate MNS Staging and Master (#1300)
Akol125 Mar 17, 2026
ab211a7
updating tests and fix formatting issue
FimranNHS Mar 17, 2026
52fbb5c
Merge remote-tracking branch 'origin/staging/VED-16-mns-vacc-event-no…
FimranNHS Mar 17, 2026
e969ecb
Merge branch 'master' into feature/VED-1098
Akol125 Mar 17, 2026
adf74c5
updated e2e ymal with aws account id variable to pass to tests
FimranNHS Mar 17, 2026
5791cbf
final test update
FimranNHS Mar 17, 2026
cc7aafb
Merge branch 'master' into feature/VED-1098
Akol125 Mar 17, 2026
2ff4ab1
updated the message read time
FimranNHS Mar 17, 2026
32191c8
Merge branch 'feature/VED-1098' of https://github.com/NHSDigital/immu…
FimranNHS Mar 17, 2026
9b39295
update
FimranNHS Mar 17, 2026
2dd7c92
add try catch in purge all queues
FimranNHS Mar 18, 2026
f9e374e
update nhs number from testdata file
FimranNHS Mar 18, 2026
ea23d19
Merge branch 'master' into feature/VED-1098
FimranNHS Mar 18, 2026
4d73173
fix broken tests
FimranNHS Mar 18, 2026
d3e906a
Merge branch 'feature/VED-1098' of https://github.com/NHSDigital/immu…
FimranNHS Mar 18, 2026
690dafa
fix broken tests
FimranNHS Mar 18, 2026
27447c1
fix broken tests
FimranNHS Mar 18, 2026
eaa4202
removed unnecessary dead letter validation
FimranNHS Mar 18, 2026
8dc4be7
Merge branch 'master' into feature/VED-1098
FimranNHS Mar 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/workflows/quality-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,17 @@ jobs:
poetry run coverage run --source=src -m unittest discover || echo "mesh_processor tests failed" >> ../../failed_tests.txt
poetry run coverage xml -o ../../mesh_processor-coverage.xml
- name: Run unittest with mns_publisher
working-directory: lambdas/mns_publisher
id: mnspublisher
env:
PYTHONPATH: ${{ env.LAMBDA_PATH }}/mns_publisher/src:${{ env.LAMBDA_PATH }}/mns_publisher/tests:${{ env.SHARED_PATH }}/src
continue-on-error: true
run: |
poetry install
poetry run coverage run --source=src -m unittest discover || echo "mns_publisher tests failed" >> ../../failed_tests.txt
poetry run coverage xml -o ../../mns_publisher-coverage.xml
- name: Run unittest with coverage-mns-subscription
working-directory: lambdas/mns_subscription
id: mns_subscription
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/run-e2e-automation-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ jobs:
SONAR_client_Secret: ${{ secrets.SONAR_client_Secret }}
MEDICUS_client_Id: ${{ secrets.MEDICUS_client_Id }}
MEDICUS_client_Secret: ${{ secrets.MEDICUS_client_Secret }}
aws_token_refresh: "False"
aws_account_id: ${{ vars.AWS_ACCOUNT_ID }}
TEST_PATH: ${{ inputs.service_under_test == 'batch' && 'features/batchTests' || inputs.service_under_test == 'fhir_api' && 'features/APITests' || 'features' }}
TEST_FILTER: ${{ inputs.suite_to_run == 'proxy_smoke' && 'Status_feature' || inputs.suite_to_run }}
run: poetry run pytest "$TEST_PATH" -m "$TEST_FILTER" --junitxml=output/test-results.xml --alluredir=output/allure-results
Expand Down
27 changes: 13 additions & 14 deletions infrastructure/instance/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions infrastructure/instance/dynamodb.tf
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ resource "aws_dynamodb_table" "delta-dynamodb-table" {
name = "imms-${local.resource_scope}-delta"
billing_mode = "PAY_PER_REQUEST"
hash_key = "PK"
stream_enabled = true
stream_view_type = "NEW_IMAGE"
deletion_protection_enabled = !local.is_temp

attribute {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ environment = "dev"
immunisation_account_id = "345594581768"
dspp_core_account_id = "603871901111"
pds_environment = "int"
mns_environment = "dev"
error_alarm_notifications_enabled = true
create_mesh_processor = false
has_sub_environment_scope = true
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ environment = "dev"
immunisation_account_id = "345594581768"
dspp_core_account_id = "603871901111"
pds_environment = "int"
mns_environment = "dev"
error_alarm_notifications_enabled = false
create_mesh_processor = false
has_sub_environment_scope = true
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ environment = "dev"
immunisation_account_id = "345594581768"
dspp_core_account_id = "603871901111"
pds_environment = "int"
mns_environment = "dev"
error_alarm_notifications_enabled = false
create_mesh_processor = false
has_sub_environment_scope = true
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ environment = "dev"
immunisation_account_id = "345594581768"
dspp_core_account_id = "603871901111"
pds_environment = "ref"
mns_environment = "dev"
error_alarm_notifications_enabled = true
create_mesh_processor = false
has_sub_environment_scope = true
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ environment = "preprod"
immunisation_account_id = "084828561157"
dspp_core_account_id = "603871901111"
pds_environment = "int"
mns_environment = "int"
error_alarm_notifications_enabled = true

# mesh no invocation period metric set to 3 days (in seconds) for preprod environment i.e 3 * 24 * 60 * 60
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ environment = "preprod"
immunisation_account_id = "084828561157"
dspp_core_account_id = "603871901111"
pds_environment = "int"
mns_environment = "int"
error_alarm_notifications_enabled = true

# mesh no invocation period metric set to 3 days (in seconds) for preprod environment i.e 3 * 24 * 60 * 60
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ immunisation_account_id = "664418956997"
dspp_core_account_id = "232116723729"
mns_account_id = "758334270304"
pds_environment = "prod"
mns_environment = "prod"
error_alarm_notifications_enabled = true

# mesh no invocation period metric set to 1 day (in seconds) for prod environment i.e 1 * 24 * 60 * 60
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ immunisation_account_id = "664418956997"
dspp_core_account_id = "232116723729"
mns_account_id = "758334270304"
pds_environment = "prod"
mns_environment = "prod"
error_alarm_notifications_enabled = true

# mesh no invocation period metric set to 1 day (in seconds) for prod environment i.e 1 * 24 * 60 * 60
Expand Down
29 changes: 29 additions & 0 deletions infrastructure/instance/mns_publisher.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
module "mns_publisher" {
source = "./modules/mns_publisher"

ddb_delta_stream_arn = aws_dynamodb_table.delta-dynamodb-table.stream_arn
dynamo_kms_encryption_key_arn = data.aws_kms_key.existing_dynamo_encryption_key.arn
enable_lambda_alarm = var.error_alarm_notifications_enabled
immunisation_account_id = var.immunisation_account_id
is_temp = local.is_temp
enable_mns_test_queue = var.mns_environment == "dev"
resource_scope = local.resource_scope
imms_base_path = strcontains(var.sub_environment, "pr-") ? "immunisation-fhir-api/FHIR/R4-${var.sub_environment}" : "immunisation-fhir-api/FHIR/R4"
lambda_kms_encryption_key_arn = data.aws_kms_key.existing_lambda_encryption_key.arn
mns_publisher_resource_name_prefix = "${local.resource_scope}-mns-outbound-events"
mns_test_notification_name_prefix = "${local.resource_scope}-mns-test-notification"
secrets_manager_policy_path = "${local.policy_path}/secret_manager.json"
account_id = data.aws_caller_identity.current.account_id
pds_environment = var.pds_environment
mns_environment = var.mns_environment

private_subnet_ids = local.private_subnet_ids
security_group_id = data.aws_security_group.existing_securitygroup.id

shared_dir_sha = local.shared_dir_sha
splunk_firehose_stream_name = module.splunk.firehose_stream_name

short_prefix = local.short_prefix

system_alarm_sns_topic_arn = data.aws_sns_topic.imms_system_alert_errors.arn
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# IAM Role for EventBridge Pipe
resource "aws_iam_role" "mns_outbound_events_eb_pipe" {
name = "${var.mns_publisher_resource_name_prefix}-eventbridge-pipe-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "pipes.amazonaws.com"
}
Condition = {
StringEquals = {
"aws:SourceAccount" = var.immunisation_account_id
}
}
}
]
})
}

resource "aws_iam_role_policy" "mns_outbound_events_eb_pipe_source_policy" {
role = aws_iam_role.mns_outbound_events_eb_pipe.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
"Effect" : "Allow",
"Action" : [
"dynamodb:DescribeStream",
"dynamodb:GetRecords",
"dynamodb:GetShardIterator",
"dynamodb:ListStreams"
],
"Resource" : var.ddb_delta_stream_arn
},
{
"Effect" : "Allow",
"Action" : [
"kms:Decrypt",
"kms:GenerateDataKey"
],
"Resource" : var.dynamo_kms_encryption_key_arn
},
]
})
}

resource "aws_iam_role_policy" "mns_outbound_events_eb_pipe_target_policy" {
role = aws_iam_role.mns_outbound_events_eb_pipe.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"sqs:GetQueueAttributes",
"sqs:SendMessage",
],
Resource = [
aws_sqs_queue.mns_outbound_events.arn,
]
},
]
})
}

resource "aws_iam_role_policy" "mns_outbound_events_eb_pipe_cw_log_policy" {
role = aws_iam_role.mns_outbound_events_eb_pipe.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
Resource = [
"arn:aws:logs:${var.aws_region}:${var.immunisation_account_id}:log-group:/aws/vendedlogs/pipes/${var.mns_publisher_resource_name_prefix}-pipe-logs:*",
]
},
]
})
}

resource "aws_cloudwatch_log_group" "mns_outbound_events_eb_pipe" {
name = "/aws/vendedlogs/pipes/${var.mns_publisher_resource_name_prefix}-pipe-logs"
retention_in_days = 30
}

resource "aws_pipes_pipe" "mns_outbound_events" {
depends_on = [
aws_iam_role_policy.mns_outbound_events_eb_pipe_source_policy,
aws_iam_role_policy.mns_outbound_events_eb_pipe_target_policy,
aws_iam_role_policy.mns_outbound_events_eb_pipe_cw_log_policy,
]
name = "${var.mns_publisher_resource_name_prefix}-pipe"
role_arn = aws_iam_role.mns_outbound_events_eb_pipe.arn
source = var.ddb_delta_stream_arn
target = aws_sqs_queue.mns_outbound_events.arn

source_parameters {
dynamodb_stream_parameters {
starting_position = "TRIM_HORIZON"
}
}

log_configuration {
include_execution_data = ["ALL"]
level = "ERROR"
cloudwatch_logs_log_destination {
log_group_arn = aws_cloudwatch_log_group.mns_outbound_events_eb_pipe.arn
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
resource "aws_kms_key" "mns_outbound_events" {
description = "KMS key for encrypting MNS outbound immunisation events in SQS"
key_usage = "ENCRYPT_DECRYPT"
enable_key_rotation = true

policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "EnableRootPermissions"
Effect = "Allow"
Principal = {
AWS = "arn:aws:iam::${var.immunisation_account_id}:root"
},
Action = [
"kms:Create*",
"kms:Describe*",
"kms:Enable*",
"kms:List*",
"kms:Put*",
"kms:Update*",
"kms:Revoke*",
"kms:Disable*",
"kms:Get*",
"kms:Delete*",
"kms:ScheduleKeyDeletion",
"kms:CancelKeyDeletion",
"kms:GenerateDataKey*",
"kms:Decrypt",
"kms:Tag*"
],
Resource = "*"
},
{
Sid = "AllowSQSUseOfKey"
Effect = "Allow"
Principal = {
Service = "sqs.amazonaws.com"
}
Action = [
"kms:GenerateDataKey",
"kms:Decrypt"
]
Resource = "*"
Condition = {
StringEquals = {
"kms:EncryptionContext:aws:sqs:queue_arn" = [
"arn:aws:sqs:${var.aws_region}:${var.immunisation_account_id}:${var.mns_publisher_resource_name_prefix}-queue",
"arn:aws:sqs:${var.aws_region}:${var.immunisation_account_id}:${var.mns_publisher_resource_name_prefix}-dead-letter-queue"
]
}
}
},
{
Sid = "AllowLambdaToDecrypt"
Effect = "Allow"
Principal = {
AWS = "arn:aws:iam::${var.immunisation_account_id}:role/${var.short_prefix}-mns-publisher-lambda-exec-role"
}
Action = [
"kms:Decrypt",
"kms:GenerateDataKey"
]
Resource = "*"
},
{
Sid = "AllowEventBridgePipesUseOfKey"
Effect = "Allow"
Principal = {
AWS = "arn:aws:iam::${var.immunisation_account_id}:role/${var.mns_publisher_resource_name_prefix}-eventbridge-pipe-role"
}
Action = [
"kms:GenerateDataKey",
"kms:Encrypt",
"kms:DescribeKey"

]
Resource = "*"
}
]
})
}

resource "aws_kms_alias" "mns_outbound_events_key" {
name = "alias/${var.mns_publisher_resource_name_prefix}-key"
target_key_id = aws_kms_key.mns_outbound_events.id
}
Loading
Loading