Skip to content

Commit 0a379f4

Browse files
committed
CCM-11492 Merge in main
2 parents bd0a77c + c95e9c4 commit 0a379f4

File tree

23 files changed

+847
-35
lines changed

23 files changed

+847
-35
lines changed

infrastructure/terraform/modules/backend-api/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ No requirements.
4141
| <a name="module_count_routing_configs_lambda"></a> [count\_routing\_configs\_lambda](#module\_count\_routing\_configs\_lambda) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.22/terraform-lambda.zip | n/a |
4242
| <a name="module_create_routing_config_lambda"></a> [create\_routing\_config\_lambda](#module\_create\_routing\_config\_lambda) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.22/terraform-lambda.zip | n/a |
4343
| <a name="module_create_template_lambda"></a> [create\_template\_lambda](#module\_create\_template\_lambda) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.22/terraform-lambda.zip | n/a |
44+
| <a name="module_delete_routing_config_lambda"></a> [delete\_routing\_config\_lambda](#module\_delete\_routing\_config\_lambda) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.22/terraform-lambda.zip | n/a |
4445
| <a name="module_delete_template_lambda"></a> [delete\_template\_lambda](#module\_delete\_template\_lambda) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.22/terraform-lambda.zip | n/a |
4546
| <a name="module_get_client_lambda"></a> [get\_client\_lambda](#module\_get\_client\_lambda) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.22/terraform-lambda.zip | n/a |
4647
| <a name="module_get_routing_config_lambda"></a> [get\_routing\_config\_lambda](#module\_get\_routing\_config\_lambda) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.22/terraform-lambda.zip | n/a |

infrastructure/terraform/modules/backend-api/iam_role_api_gateway_execution_role.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ data "aws_iam_policy_document" "api_gateway_execution_policy" {
5353
module.count_routing_configs_lambda.function_arn,
5454
module.create_template_lambda.function_arn,
5555
module.create_routing_config_lambda.function_arn,
56+
module.delete_routing_config_lambda.function_arn,
5657
module.delete_template_lambda.function_arn,
5758
module.get_client_lambda.function_arn,
5859
module.get_routing_config_lambda.function_arn,

infrastructure/terraform/modules/backend-api/locals.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ locals {
1818
CREATE_LAMBDA_ARN = module.create_template_lambda.function_arn
1919
CREATE_ROUTING_CONFIG_LAMBDA_ARN = module.create_routing_config_lambda.function_arn
2020
DELETE_LAMBDA_ARN = module.delete_template_lambda.function_arn
21+
DELETE_ROUTING_CONFIG_LAMBDA_ARN = module.delete_routing_config_lambda.function_arn
2122
GET_CLIENT_LAMBDA_ARN = module.get_client_lambda.function_arn
2223
GET_LAMBDA_ARN = module.get_template_lambda.function_arn
2324
GET_ROUTING_CONFIG_LAMBDA_ARN = module.get_routing_config_lambda.function_arn
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
module "delete_routing_config_lambda" {
2+
source = "https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.22/terraform-lambda.zip"
3+
4+
project = var.project
5+
environment = var.environment
6+
component = var.component
7+
aws_account_id = var.aws_account_id
8+
region = var.region
9+
10+
kms_key_arn = var.kms_key_arn
11+
12+
function_name = "delete-routing-config"
13+
14+
function_module_name = "delete-routing-config"
15+
handler_function_name = "handler"
16+
description = "Delete Routing Config API endpoint"
17+
18+
memory = 512
19+
timeout = 3
20+
runtime = "nodejs20.x"
21+
22+
log_retention_in_days = var.log_retention_in_days
23+
24+
iam_policy_document = {
25+
body = data.aws_iam_policy_document.delete_routing_config_lambda_policy.json
26+
}
27+
28+
lambda_env_vars = local.backend_lambda_environment_variables
29+
function_s3_bucket = var.function_s3_bucket
30+
function_code_base_path = local.lambdas_dir
31+
function_code_dir = "backend-api/dist/delete-routing-config"
32+
33+
send_to_firehose = var.send_to_firehose
34+
log_destination_arn = var.log_destination_arn
35+
log_subscription_role_arn = var.log_subscription_role_arn
36+
}
37+
38+
data "aws_iam_policy_document" "delete_routing_config_lambda_policy" {
39+
statement {
40+
sid = "AllowDynamoAccess"
41+
effect = "Allow"
42+
43+
actions = [
44+
"dynamodb:UpdateItem",
45+
]
46+
47+
resources = [
48+
aws_dynamodb_table.routing_configuration.arn,
49+
]
50+
}
51+
52+
statement {
53+
sid = "AllowKMSAccess"
54+
effect = "Allow"
55+
56+
actions = [
57+
"kms:Decrypt",
58+
"kms:DescribeKey",
59+
"kms:Encrypt",
60+
"kms:GenerateDataKey*",
61+
"kms:ReEncrypt*",
62+
]
63+
64+
resources = [
65+
var.kms_key_arn
66+
]
67+
}
68+
}

infrastructure/terraform/modules/backend-api/spec.tmpl.json

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1093,6 +1093,55 @@
10931093
}
10941094
},
10951095
"/v1/routing-configuration/{routingConfigId}": {
1096+
"delete": {
1097+
"description": "Delete a routing configuration by Id",
1098+
"parameters": [
1099+
{
1100+
"description": "ID of routing configuration to delete",
1101+
"in": "path",
1102+
"name": "routingConfigId",
1103+
"required": true,
1104+
"schema": {
1105+
"type": "string"
1106+
}
1107+
}
1108+
],
1109+
"responses": {
1110+
"204": {
1111+
"description": "No content"
1112+
},
1113+
"default": {
1114+
"content": {
1115+
"application/json": {
1116+
"schema": {
1117+
"$ref": "#/components/schemas/Failure"
1118+
}
1119+
}
1120+
},
1121+
"description": "Error"
1122+
}
1123+
},
1124+
"security": [
1125+
{
1126+
"authorizer": []
1127+
}
1128+
],
1129+
"summary": "Delete a routing configuration",
1130+
"x-amazon-apigateway-integration": {
1131+
"contentHandling": "CONVERT_TO_TEXT",
1132+
"credentials": "${APIG_EXECUTION_ROLE_ARN}",
1133+
"httpMethod": "POST",
1134+
"passthroughBehavior": "WHEN_NO_TEMPLATES",
1135+
"responses": {
1136+
".*": {
1137+
"statusCode": "200"
1138+
}
1139+
},
1140+
"timeoutInMillis": 29000,
1141+
"type": "AWS_PROXY",
1142+
"uri": "arn:aws:apigateway:${AWS_REGION}:lambda:path/2015-03-31/functions/${DELETE_ROUTING_CONFIG_LAMBDA_ARN}/invocations"
1143+
}
1144+
},
10961145
"get": {
10971146
"description": "Get a routing configuration by ID",
10981147
"parameters": [
@@ -1504,22 +1553,8 @@
15041553
}
15051554
],
15061555
"responses": {
1507-
"200": {
1508-
"content": {
1509-
"application/json": {
1510-
"schema": {
1511-
"$ref": "#/components/schemas/TemplateSuccess"
1512-
}
1513-
}
1514-
},
1515-
"description": "200 response",
1516-
"headers": {
1517-
"Content-Type": {
1518-
"schema": {
1519-
"type": "string"
1520-
}
1521-
}
1522-
}
1556+
"204": {
1557+
"description": "No content"
15231558
},
15241559
"default": {
15251560
"content": {

lambdas/backend-api/README.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
<!-- vale off -->
12
# Backend-api
23

34
<!-- vale off -->
@@ -201,12 +202,20 @@ curl -X PUT --location "${APIG_STAGE}/v1/routing-configuration/${ROUTING_CONFIG_
201202
}'
202203
```
203204
204-
### PATCH - /v1/template/:templateId/submit - Submit a routing configuration
205+
### PATCH - /v1/routing-configuration/:routingConfigId/submit - Submit a routing configuration
205206
206207
```bash
207208
curl -X PATCH --location "${APIG_STAGE}/v1/routing-configuration/${ROUTING_CONFIG_ID}/submit" \
208209
--header 'Accept: application/json' \
209210
--header "Authorization: $SANDBOX_TOKEN"
210211
```
211212
213+
### DELETE - /v1/routing-configuration/:routingConfigId - Delete a routing configuration
214+
215+
```bash
216+
curl -X DELETE --location "${APIG_STAGE}/v1/routing-configuration/${ROUTING_CONFIG_ID}" \
217+
--header 'Accept: application/json' \
218+
--header "Authorization: $SANDBOX_TOKEN"
219+
```
220+
212221
<!-- vale on -->

lambdas/backend-api/build.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ npx esbuild \
2020
src/templates/create.ts \
2121
src/templates/delete-failed-scanned-object.ts \
2222
src/templates/delete.ts \
23+
src/templates/delete-routing-config.ts \
2324
src/templates/get-client.ts \
2425
src/templates/get-routing-config.ts \
2526
src/templates/get.ts \
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
import type { APIGatewayProxyEvent, Context } from 'aws-lambda';
2+
import { mock } from 'jest-mock-extended';
3+
import { createHandler } from '@backend-api/templates/api/delete-routing-config';
4+
import { RoutingConfigClient } from '@backend-api/templates/app/routing-config-client';
5+
6+
const setup = () => {
7+
const routingConfigClient = mock<RoutingConfigClient>();
8+
const mocks = { routingConfigClient };
9+
const handler = createHandler(mocks);
10+
11+
return { handler, mocks };
12+
};
13+
14+
describe('Delete Routing Config Handler', () => {
15+
beforeEach(jest.resetAllMocks);
16+
17+
test.each([
18+
['undefined', undefined],
19+
['missing user', { clientId: 'client-id', user: undefined }],
20+
['missing client', { clientId: undefined, user: 'user-id' }],
21+
])(
22+
'should return 400 - Invalid request when requestContext is %s',
23+
async (_, ctx) => {
24+
const { handler, mocks } = setup();
25+
26+
const event = mock<APIGatewayProxyEvent>({
27+
requestContext: { authorizer: ctx },
28+
pathParameters: { templateId: 'id' },
29+
});
30+
31+
const result = await handler(event, mock<Context>(), jest.fn());
32+
33+
expect(result).toEqual({
34+
statusCode: 400,
35+
body: JSON.stringify({
36+
statusCode: 400,
37+
technicalMessage: 'Invalid request',
38+
}),
39+
});
40+
41+
expect(
42+
mocks.routingConfigClient.deleteRoutingConfig
43+
).not.toHaveBeenCalled();
44+
}
45+
);
46+
47+
test('should return 400 - Invalid request when, no routingConfigId', async () => {
48+
const { handler, mocks } = setup();
49+
50+
const event = mock<APIGatewayProxyEvent>({
51+
requestContext: {
52+
authorizer: { user: 'sub', clientId: 'nhs-notify-client-id' },
53+
},
54+
body: JSON.stringify({ name: 'test' }),
55+
pathParameters: { routingConfigId: undefined },
56+
});
57+
58+
const result = await handler(event, mock<Context>(), jest.fn());
59+
60+
expect(result).toEqual({
61+
statusCode: 400,
62+
body: JSON.stringify({
63+
statusCode: 400,
64+
technicalMessage: 'Invalid request',
65+
}),
66+
});
67+
68+
expect(
69+
mocks.routingConfigClient.deleteRoutingConfig
70+
).not.toHaveBeenCalled();
71+
});
72+
73+
test('should return error when deleting routing config fails', async () => {
74+
const { handler, mocks } = setup();
75+
76+
mocks.routingConfigClient.deleteRoutingConfig.mockResolvedValueOnce({
77+
error: {
78+
errorMeta: {
79+
code: 500,
80+
description: 'Internal server error',
81+
},
82+
},
83+
});
84+
85+
const event = mock<APIGatewayProxyEvent>({
86+
requestContext: {
87+
authorizer: { user: 'sub', clientId: 'nhs-notify-client-id' },
88+
},
89+
pathParameters: { routingConfigId: '1-2-3' },
90+
});
91+
92+
const result = await handler(event, mock<Context>(), jest.fn());
93+
94+
expect(result).toEqual({
95+
statusCode: 500,
96+
body: JSON.stringify({
97+
statusCode: 500,
98+
technicalMessage: 'Internal server error',
99+
}),
100+
});
101+
102+
expect(mocks.routingConfigClient.deleteRoutingConfig).toHaveBeenCalledWith(
103+
'1-2-3',
104+
{
105+
userId: 'sub',
106+
clientId: 'nhs-notify-client-id',
107+
}
108+
);
109+
});
110+
111+
test('should return 204 no content response after deleting routing config', async () => {
112+
const { handler, mocks } = setup();
113+
114+
mocks.routingConfigClient.deleteRoutingConfig.mockResolvedValueOnce({
115+
data: undefined,
116+
});
117+
118+
const event = mock<APIGatewayProxyEvent>({
119+
requestContext: {
120+
authorizer: { user: 'sub', clientId: 'nhs-notify-client-id' },
121+
},
122+
pathParameters: { routingConfigId: '1-2-3' },
123+
});
124+
125+
const result = await handler(event, mock<Context>(), jest.fn());
126+
127+
expect(result).toEqual({
128+
statusCode: 204,
129+
body: JSON.stringify({ statusCode: 204, data: undefined }),
130+
});
131+
132+
expect(mocks.routingConfigClient.deleteRoutingConfig).toHaveBeenCalledWith(
133+
'1-2-3',
134+
{
135+
userId: 'sub',
136+
clientId: 'nhs-notify-client-id',
137+
}
138+
);
139+
});
140+
});

0 commit comments

Comments
 (0)