Skip to content

Commit f55ac54

Browse files
authored
Merge branch 'main' into feature/CCM-11597
2 parents cc06566 + 54b0fc2 commit f55ac54

29 files changed

+1419
-470
lines changed

infrastructure/terraform/components/api/README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,15 @@ No requirements.
3232

3333
| Name | Source | Version |
3434
|------|--------|---------|
35-
| <a name="module_authorizer_lambda"></a> [authorizer\_lambda](#module\_authorizer\_lambda) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.20/terraform-lambda.zip | n/a |
35+
| <a name="module_authorizer_lambda"></a> [authorizer\_lambda](#module\_authorizer\_lambda) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-lambda.zip | n/a |
3636
| <a name="module_domain_truststore"></a> [domain\_truststore](#module\_domain\_truststore) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.20/terraform-s3bucket.zip | n/a |
3737
| <a name="module_get_letter"></a> [get\_letter](#module\_get\_letter) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-lambda.zip | n/a |
3838
| <a name="module_get_letters"></a> [get\_letters](#module\_get\_letters) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.20/terraform-lambda.zip | n/a |
39+
| <a name="module_get_letter_data"></a> [get\_letter\_data](#module\_get\_letter\_data) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-lambda.zip | n/a |
40+
| <a name="module_get_letters"></a> [get\_letters](#module\_get\_letters) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-lambda.zip | n/a |
3941
| <a name="module_kms"></a> [kms](#module\_kms) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.20/terraform-kms.zip | n/a |
4042
| <a name="module_logging_bucket"></a> [logging\_bucket](#module\_logging\_bucket) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.20/terraform-s3bucket.zip | n/a |
41-
| <a name="module_patch_letter"></a> [patch\_letter](#module\_patch\_letter) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.20/terraform-lambda.zip | n/a |
43+
| <a name="module_patch_letter"></a> [patch\_letter](#module\_patch\_letter) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-lambda.zip | n/a |
4244
| <a name="module_s3bucket_test_letters"></a> [s3bucket\_test\_letters](#module\_s3bucket\_test\_letters) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.20/terraform-s3bucket.zip | n/a |
4345
| <a name="module_supplier_ssl"></a> [supplier\_ssl](#module\_supplier\_ssl) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.20/terraform-ssl.zip | n/a |
4446
## Outputs

infrastructure/terraform/components/api/iam_role_api_gateway_execution_role.tf

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ data "aws_iam_policy_document" "api_gateway_execution_policy" {
5151
module.authorizer_lambda.function_arn,
5252
module.get_letter.function_arn,
5353
module.get_letters.function_arn,
54-
module.patch_letter.function_arn
54+
module.patch_letter.function_arn,
55+
module.get_letter_data.function_arn
5556
]
5657
}
5758
}

infrastructure/terraform/components/api/locals.tf

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,17 @@ locals {
1010
AUTHORIZER_LAMBDA_ARN = module.authorizer_lambda.function_arn
1111
GET_LETTER_LAMBDA_ARN = module.get_letter.function_arn
1212
GET_LETTERS_LAMBDA_ARN = module.get_letters.function_arn
13+
GET_LETTER_DATA_LAMBDA_ARN = module.get_letter_data.function_arn
1314
PATCH_LETTER_LAMBDA_ARN = module.patch_letter.function_arn
1415
})
1516

1617
destination_arn = "arn:aws:logs:${var.region}:${var.shared_infra_account_id}:destination:nhs-main-obs-firehose-logs"
1718

1819
common_lambda_env_vars = {
1920
LETTERS_TABLE_NAME = aws_dynamodb_table.letters.name,
20-
LETTER_TTL_HOURS = 24,
21-
SUPPLIER_ID_HEADER = "nhsd-supplier-id"
22-
APIM_CORRELATION_HEADER = "nhsd-correlation-id"
21+
LETTER_TTL_HOURS = 12960, # 18 months * 30 days * 24 hours
22+
SUPPLIER_ID_HEADER = "nhsd-supplier-id",
23+
APIM_CORRELATION_HEADER = "nhsd-correlation-id",
24+
DOWNLOAD_URL_TTL_SECONDS = 60
2325
}
2426
}

infrastructure/terraform/components/api/module_authorizer_lambda.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
module "authorizer_lambda" {
2-
source = "https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.20/terraform-lambda.zip"
2+
source = "https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-lambda.zip"
33

44
aws_account_id = var.aws_account_id
55
component = var.component
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
module "get_letter_data" {
2+
source = "https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-lambda.zip"
3+
4+
function_name = "get_letter_data"
5+
description = "Get the letter data"
6+
7+
aws_account_id = var.aws_account_id
8+
component = var.component
9+
environment = var.environment
10+
project = var.project
11+
region = var.region
12+
group = var.group
13+
14+
log_retention_in_days = var.log_retention_in_days
15+
kms_key_arn = module.kms.key_arn
16+
17+
iam_policy_document = {
18+
body = data.aws_iam_policy_document.get_letter_data_lambda.json
19+
}
20+
21+
function_s3_bucket = local.acct.s3_buckets["lambda_function_artefacts"]["id"]
22+
function_code_base_path = local.aws_lambda_functions_dir_path
23+
function_code_dir = "api-handler/dist"
24+
function_include_common = true
25+
handler_function_name = "getLetterData"
26+
runtime = "nodejs22.x"
27+
memory = 128
28+
timeout = 5
29+
log_level = var.log_level
30+
31+
force_lambda_code_deploy = var.force_lambda_code_deploy
32+
enable_lambda_insights = false
33+
34+
send_to_firehose = true
35+
log_destination_arn = local.destination_arn
36+
log_subscription_role_arn = local.acct.log_subscription_role_arn
37+
38+
lambda_env_vars = merge(local.common_lambda_env_vars, {})
39+
}
40+
41+
data "aws_iam_policy_document" "get_letter_data_lambda" {
42+
statement {
43+
sid = "KMSPermissions"
44+
effect = "Allow"
45+
46+
actions = [
47+
"kms:Decrypt",
48+
"kms:GenerateDataKey",
49+
]
50+
51+
resources = [
52+
module.kms.key_arn, ## Requires shared kms module
53+
]
54+
}
55+
56+
statement {
57+
sid = "AllowDynamoDBAccess"
58+
effect = "Allow"
59+
60+
actions = [
61+
"dynamodb:GetItem",
62+
"dynamodb:Query"
63+
]
64+
65+
resources = [
66+
aws_dynamodb_table.letters.arn,
67+
"${aws_dynamodb_table.letters.arn}/index/supplierStatus-index"
68+
]
69+
}
70+
71+
statement {
72+
sid = "S3GetObjectForPresign"
73+
actions = [
74+
"s3:GetObject",
75+
"s3:ListBucket"] # allows 404 response instead of 403 if object missing
76+
resources = ["${module.s3bucket_test_letters.arn}/*"]
77+
}
78+
}

infrastructure/terraform/components/api/module_lambda_get_letters.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
module "get_letters" {
2-
source = "https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.20/terraform-lambda.zip"
2+
source = "https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-lambda.zip"
33

44
function_name = "get_letters"
55
description = "Get paginated letter ids"

infrastructure/terraform/components/api/module_lambda_patch_letter.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
module "patch_letter" {
2-
source = "https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.20/terraform-lambda.zip"
2+
source = "https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-lambda.zip"
33

44
function_name = "patch_letter"
55
description = "Update the status of a letter"

infrastructure/terraform/components/api/resources/spec.tmpl.json

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,66 @@
142142
"uri": "arn:aws:apigateway:${AWS_REGION}:lambda:path/2015-03-31/functions/${PATCH_LETTER_LAMBDA_ARN}/invocations"
143143
}
144144
}
145+
},
146+
"/letters/{id}/data": {
147+
"get": {
148+
"operationId": "getDataId",
149+
"responses": {
150+
"303": {
151+
"description": "See Other",
152+
"headers": {
153+
"Location": {
154+
"description": "The signed S3 URL of the data file to download",
155+
"example": "https://examples3bucket.com/filelocation",
156+
"schema": {
157+
"type": "string"
158+
}
159+
}
160+
}
161+
},
162+
"404": {
163+
"description": "Resource not found"
164+
},
165+
"429": {
166+
"description": "Too many requests"
167+
},
168+
"500": {
169+
"description": "Server error"
170+
}
171+
},
172+
"security": [
173+
{
174+
"LambdaAuthorizer": []
175+
}
176+
],
177+
"summary": "Fetch a data file",
178+
"x-amazon-apigateway-integration": {
179+
"contentHandling": "CONVERT_TO_TEXT",
180+
"credentials": "${APIG_EXECUTION_ROLE_ARN}",
181+
"httpMethod": "POST",
182+
"passthroughBehavior": "WHEN_NO_TEMPLATES",
183+
"responses": {
184+
".*": {
185+
"statusCode": "200"
186+
}
187+
},
188+
"timeoutInMillis": 29000,
189+
"type": "AWS_PROXY",
190+
"uri": "arn:aws:apigateway:${AWS_REGION}:lambda:path/2015-03-31/functions/${GET_LETTER_DATA_LAMBDA_ARN}/invocations"
191+
}
192+
},
193+
"parameters": [
194+
{
195+
"description": "Unique identifier of this resource",
196+
"in": "path",
197+
"name": "id",
198+
"required": true,
199+
"schema": {
200+
"example": "24L5eYSWGzCHlGmzNxuqVusPxDg",
201+
"type": "string"
202+
}
203+
}
204+
]
145205
}
146206
}
147207
}

lambdas/api-handler/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"esbuild": "^0.24.0"
44
},
55
"devDependencies": {
6+
"@aws-sdk/s3-request-presigner": "^3.901.0",
67
"@tsconfig/node22": "^22.0.2",
78
"@types/aws-lambda": "^8.10.148",
89
"@types/jest": "^29.5.14",
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
2+
import type { Deps } from '../deps';
3+
4+
describe('createDependenciesContainer', () => {
5+
beforeEach(() => {
6+
jest.clearAllMocks();
7+
jest.resetModules();
8+
9+
// pino
10+
jest.mock('pino', () => ({
11+
__esModule: true,
12+
default: jest.fn(() => ({
13+
info: jest.fn(),
14+
error: jest.fn(),
15+
warn: jest.fn(),
16+
debug: jest.fn(),
17+
})),
18+
}));
19+
20+
jest.mock('@aws-sdk/client-s3', () => ({
21+
S3Client: jest.fn(),
22+
}));
23+
24+
// Repo client
25+
jest.mock('../../../../../internal/datastore', () => ({
26+
LetterRepository: jest.fn(),
27+
}));
28+
29+
// Env
30+
jest.mock('../env', () => ({
31+
envVars: {
32+
LETTERS_TABLE_NAME: 'LettersTable',
33+
LETTER_TTL_HOURS: 12960,
34+
SUPPLIER_ID_HEADER: 'nhsd-supplier-id',
35+
APIM_CORRELATION_HEADER: 'nhsd-correlation-id',
36+
DOWNLOAD_URL_TTL_SECONDS: 60
37+
},
38+
}));
39+
});
40+
41+
test('constructs deps and wires repository config correctly', async () => {
42+
// get current mock instances
43+
const { S3Client } = jest.requireMock('@aws-sdk/client-s3') as { S3Client: jest.Mock };
44+
const pinoMock = jest.requireMock('pino') as { default: jest.Mock };
45+
const { LetterRepository } = jest.requireMock('../../../../../internal/datastore') as { LetterRepository: jest.Mock };
46+
47+
const { createDependenciesContainer } = require('../deps');
48+
const deps: Deps = createDependenciesContainer();
49+
50+
expect(S3Client).toHaveBeenCalledTimes(1);
51+
expect(pinoMock.default).toHaveBeenCalledTimes(1);
52+
53+
expect(LetterRepository).toHaveBeenCalledTimes(1);
54+
const repoCtorArgs = (LetterRepository as jest.Mock).mock.calls[0];
55+
expect(repoCtorArgs[2]).toEqual({
56+
lettersTableName: 'LettersTable',
57+
ttlHours: 12960
58+
});
59+
60+
expect(deps.env).toEqual({
61+
LETTERS_TABLE_NAME: 'LettersTable',
62+
LETTER_TTL_HOURS: 12960,
63+
SUPPLIER_ID_HEADER: 'nhsd-supplier-id',
64+
APIM_CORRELATION_HEADER: 'nhsd-correlation-id',
65+
DOWNLOAD_URL_TTL_SECONDS: 60
66+
});
67+
});
68+
});

0 commit comments

Comments
 (0)