Skip to content

Commit 281e2ad

Browse files
Merge branch 'main' into CCM-11345-Manual-Repo-Sync
2 parents cbab393 + 987e42a commit 281e2ad

File tree

20 files changed

+235
-156
lines changed

20 files changed

+235
-156
lines changed

.github/workflows/pr_create_dynamic_env.yaml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,20 @@ jobs:
2929
--arg targetComponent "api" \
3030
--arg terraformAction "apply" \
3131
--arg overrides "branch_name=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" \
32+
--arg overrideProjectName "nhs" \
33+
--arg overrideRoleName "nhs-main-acct-supplier-api-github-deploy" \
3234
'{ "ref": "main",
3335
"inputs": {
34-
"infraRepoName": $infraRepoName,
36+
"infraRepoName", $infraRepoName,
3537
"releaseVersion", $releaseVersion,
3638
"targetProject", $targetProject,
3739
"targetEnvironment", $targetEnvironment,
3840
"targetAccountGroup", $targetAccountGroup,
3941
"targetComponent", $targetComponent,
4042
"terraformAction", $terraformAction,
4143
"overrides", $overrides,
44+
"overrideProjectName", $overrideProjectName,
45+
"overrideRoleName", $overrideRoleName,
4246
}
4347
}')
4448

.github/workflows/pr_destroy_dynamic_env.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ jobs:
2828
--arg targetAccountGroup "nhs-notify-supplier-api-dev" \
2929
--arg targetComponent "api" \
3030
--arg terraformAction "destroy" \
31+
--arg overrideProjectName "nhs" \
32+
--arg overrideRoleName "nhs-main-acct-supplier-api-github-deploy" \
3133
'{ "ref": "main",
3234
"inputs": {
3335
"infraRepoName": $infraRepoName,
@@ -37,6 +39,8 @@ jobs:
3739
"targetAccountGroup", $targetAccountGroup,
3840
"targetComponent", $targetComponent,
3941
"terraformAction", $terraformAction,
42+
"overrideProjectName", $overrideProjectName,
43+
"overrideRoleName", $overrideRoleName,
4044
}
4145
}')
4246

infrastructure/terraform/components/api/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ No requirements.
2727
| Name | Source | Version |
2828
|------|--------|---------|
2929
| <a name="module_authorizer_lambda"></a> [authorizer\_lambda](#module\_authorizer\_lambda) | git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/lambda | v2.0.4 |
30+
| <a name="module_get_letters"></a> [get\_letters](#module\_get\_letters) | git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/lambda | v2.0.10 |
3031
| <a name="module_hello_world"></a> [hello\_world](#module\_hello\_world) | git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/lambda | v2.0.10 |
3132
| <a name="module_kms"></a> [kms](#module\_kms) | git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/kms | v2.0.10 |
3233
## Outputs

infrastructure/terraform/components/api/iam_role_api_gateway_execution_role.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ data "aws_iam_policy_document" "api_gateway_execution_policy" {
5050
resources = [
5151
module.authorizer_lambda.function_arn,
5252
module.hello_world.function_arn,
53+
module.get_letters.function_arn,
5354
]
5455
}
5556
}

infrastructure/terraform/components/api/locals.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ locals {
99
AWS_REGION = var.region
1010
AUTHORIZER_LAMBDA_ARN = module.authorizer_lambda.function_arn
1111
HELLO_WORLD_LAMBDA_ARN = module.hello_world.function_arn
12+
GET_LETTERS_LAMBDA_ARN = module.get_letters.function_arn
1213
})
1314

1415
destination_arn = "arn:aws:logs:${var.region}:${var.shared_infra_account_id}:destination:nhs-main-obs-firehose-logs"
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
module "get_letters" {
2+
source = "git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/lambda?ref=v2.0.10"
3+
4+
function_name = "get_letters"
5+
description = "Get paginated letter ids"
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_letters_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 = "getLetters"
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 = {
39+
}
40+
}
41+
42+
data "aws_iam_policy_document" "get_letters_lambda" {
43+
statement {
44+
sid = "KMSPermissions"
45+
effect = "Allow"
46+
47+
actions = [
48+
"kms:Decrypt",
49+
"kms:GenerateDataKey",
50+
]
51+
52+
resources = [
53+
module.kms.key_arn, ## Requires shared kms module
54+
]
55+
}
56+
}

infrastructure/terraform/components/api/module_lambda_hello_world.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ module "hello_world" {
2222
function_code_base_path = local.aws_lambda_functions_dir_path
2323
function_code_dir = "api-handler/dist"
2424
function_include_common = true
25-
handler_function_name = "handler"
25+
handler_function_name = "helloWorld"
2626
runtime = "nodejs22.x"
2727
memory = 128
2828
timeout = 5

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

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@
22
"components": {
33
"securitySchemes": {
44
"LambdaAuthorizer": {
5-
"type": "apiKey",
6-
"name": "Authorization",
75
"in": "header",
8-
"x-amazon-apigateway-authtype": "custom",
6+
"name": "Authorization",
7+
"type": "apiKey",
98
"x-amazon-apigateway-authorizer": {
10-
"type": "request",
11-
"authorizerUri": "arn:aws:apigateway:${AWS_REGION}:lambda:path/2015-03-31/functions/${AUTHORIZER_LAMBDA_ARN}/invocations",
129
"authorizerCredentials": "${APIG_EXECUTION_ROLE_ARN}",
10+
"authorizerResultTtlInSeconds": 0,
11+
"authorizerUri": "arn:aws:apigateway:${AWS_REGION}:lambda:path/2015-03-31/functions/${AUTHORIZER_LAMBDA_ARN}/invocations",
1312
"identitySource": "method.request.header.Authorization",
14-
"authorizerResultTtlInSeconds": 0
15-
}
13+
"type": "request"
14+
},
15+
"x-amazon-apigateway-authtype": "custom"
1616
}
1717
}
1818
},
@@ -25,13 +25,18 @@
2525
"paths": {
2626
"/": {
2727
"get": {
28-
"summary": "Health check",
2928
"description": "Returns 200 OK if the API is up.",
3029
"responses": {
3130
"200": {
3231
"description": "OK"
3332
}
3433
},
34+
"security": [
35+
{
36+
"LambdaAuthorizer": []
37+
}
38+
],
39+
"summary": "Health check",
3540
"x-amazon-apigateway-integration": {
3641
"contentHandling": "CONVERT_TO_TEXT",
3742
"credentials": "${APIG_EXECUTION_ROLE_ARN}",
@@ -45,12 +50,37 @@
4550
"timeoutInMillis": 29000,
4651
"type": "AWS_PROXY",
4752
"uri": "arn:aws:apigateway:${AWS_REGION}:lambda:path/2015-03-31/functions/${HELLO_WORLD_LAMBDA_ARN}/invocations"
53+
}
54+
}
55+
},
56+
"/letters": {
57+
"get": {
58+
"description": "Returns 200 OK with paginated letter ids.",
59+
"responses": {
60+
"200": {
61+
"description": "OK"
62+
}
4863
},
4964
"security": [
5065
{
5166
"LambdaAuthorizer": []
5267
}
53-
]
68+
],
69+
"summary": "Get letters",
70+
"x-amazon-apigateway-integration": {
71+
"contentHandling": "CONVERT_TO_TEXT",
72+
"credentials": "${APIG_EXECUTION_ROLE_ARN}",
73+
"httpMethod": "POST",
74+
"passthroughBehavior": "WHEN_NO_TEMPLATES",
75+
"responses": {
76+
".*": {
77+
"statusCode": "200"
78+
}
79+
},
80+
"timeoutInMillis": 29000,
81+
"type": "AWS_PROXY",
82+
"uri": "arn:aws:apigateway:${AWS_REGION}:lambda:path/2015-03-31/functions/${GET_LETTERS_LAMBDA_ARN}/invocations"
83+
}
5484
}
5585
}
5686
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { getLetters } from '../../index';
2+
import type { Context } from 'aws-lambda';
3+
import { mockDeep } from 'jest-mock-extended';
4+
5+
describe('API Lambda handler', () => {
6+
it('returns 200 OK with basic paginated resources', async () => {
7+
const event = { path: '/letters' };
8+
const context = mockDeep<Context>();
9+
const callback = jest.fn();
10+
const result = await getLetters(event, context, callback);
11+
12+
const expected = {
13+
"links": {
14+
"self": "/letters?page=1",
15+
"first": "/letters?page=1",
16+
"last": "/letters?page=1",
17+
"next": "/letters?page=1",
18+
"prev": "/letters?page=1"
19+
},
20+
"data": [
21+
{ "type": "letter", "id": "l1" },
22+
{ "type": "letter", "id": "l2" },
23+
{ "type": "letter", "id": "l3" }
24+
]
25+
}
26+
27+
expect(result).toEqual({
28+
statusCode: 200,
29+
body: JSON.stringify(expected, null, 2),
30+
});
31+
});
32+
33+
it('returns 404 Not Found for an unknown path', async () => {
34+
const event = { path: '/unknown' };
35+
const context = mockDeep<Context>();
36+
const callback = jest.fn();
37+
const result = await getLetters(event, context, callback);
38+
39+
expect(result).toEqual({
40+
statusCode: 404,
41+
body: 'Not Found',
42+
});
43+
});
44+
});

lambdas/api-handler/src/__tests__/index.test.ts renamed to lambdas/api-handler/src/handlers/__tests__/hello-world.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { handler } from '../index';
1+
import { helloWorld } from '../../index';
22
import type { Context } from 'aws-lambda';
33
import { mockDeep } from 'jest-mock-extended';
44

@@ -7,7 +7,7 @@ describe('API Lambda handler', () => {
77
const event = { path: '/' };
88
const context = mockDeep<Context>();
99
const callback = jest.fn();
10-
const result = await handler(event, context, callback);
10+
const result = await helloWorld(event, context, callback);
1111

1212
expect(result).toEqual({
1313
statusCode: 200,
@@ -19,7 +19,7 @@ describe('API Lambda handler', () => {
1919
const event = {}; // No path provided
2020
const context = mockDeep<Context>();
2121
const callback = jest.fn();
22-
const result = await handler(event as any, context, callback);
22+
const result = await helloWorld(event as any, context, callback);
2323

2424
expect(result).toEqual({
2525
statusCode: 200,
@@ -31,7 +31,7 @@ describe('API Lambda handler', () => {
3131
const event = { path: '/unknown' };
3232
const context = mockDeep<Context>();
3333
const callback = jest.fn();
34-
const result = await handler(event, context, callback);
34+
const result = await helloWorld(event, context, callback);
3535

3636
expect(result).toEqual({
3737
statusCode: 404,

0 commit comments

Comments
 (0)