Skip to content

Commit 6f26fbc

Browse files
authored
Merge branch 'main' into PRMP-579
2 parents d9a2565 + aa7b905 commit 6f26fbc

23 files changed

+651
-113
lines changed

.github/workflows/automated-deploy-dev.yml

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,3 +220,68 @@ jobs:
220220
uses: NHSDigital/national-document-repository/.github/workflows/ui-dev-to-main-ci.yml@main
221221
secrets:
222222
AWS_ASSUME_ROLE: ${{ secrets.AWS_ASSUME_ROLE }}
223+
224+
notify-slack:
225+
runs-on: ubuntu-latest
226+
needs: [terraform_plan_apply, deploy_lambdas, deploy_ui]
227+
if: failure() && github.event_name == 'push' && github.ref == 'refs/heads/main'
228+
steps:
229+
- name: Configure AWS Credentials
230+
uses: aws-actions/configure-aws-credentials@v5
231+
with:
232+
role-to-assume: ${{ secrets.AWS_ASSUME_ROLE }}
233+
aws-region: ${{ vars.AWS_REGION }}
234+
235+
- name: Get slack bot token from SSM parameter store
236+
run: |
237+
slack_bot_token=$(aws ssm get-parameter --name "/ndr/alerting/slack/bot_token" --with-decryption --query "Parameter.Value" --output text)
238+
echo "::add-mask::$slack_bot_token"
239+
echo "SLACK_BOT_TOKEN=$slack_bot_token" >> $GITHUB_ENV
240+
241+
- name: Send Slack Notification
242+
uses: slackapi/[email protected]
243+
with:
244+
method: chat.postMessage
245+
token: ${{ env.SLACK_BOT_TOKEN }}
246+
payload: |
247+
{
248+
"channel": "${{ vars.ALERTS_SLACK_CHANNEL_ID }}",
249+
"attachments": [
250+
{
251+
"color": "#ff0000",
252+
"blocks": [
253+
{
254+
"type": "header",
255+
"text": {
256+
"type": "plain_text",
257+
"text": "❌ Workflow `${{ github.workflow }}` failed"
258+
}
259+
},
260+
{
261+
"type": "section",
262+
"text": {
263+
"type": "mrkdwn",
264+
"text": "*Triggered by:* `${{ github.actor }}`\n*Branch:* `${{ github.ref_name }}`\n*Workflow:* <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|${{ github.workflow }}>"
265+
}
266+
},
267+
{
268+
"type": "divider"
269+
},
270+
{
271+
"type": "section",
272+
"fields": [
273+
{ "type": "mrkdwn", "text": "*terraform_plan_apply:* ${{ needs.terraform_plan_apply.result == 'success' && ':white_check_mark:' || ':x:' }}" },
274+
{ "type": "mrkdwn", "text": "*deploy_lambdas:* ${{ needs.deploy_lambdas.result == 'success' && ':white_check_mark:' || ':x:' }}" },
275+
{ "type": "mrkdwn", "text": "*deploy_ui:* ${{ needs.deploy_ui.result == 'success' && ':white_check_mark:' || ':x:' }}" }
276+
]
277+
},
278+
{
279+
"type": "context",
280+
"elements": [
281+
{ "type": "mrkdwn", "text": "Environment: `development` | Sandbox: `ndr-dev`" }
282+
]
283+
}
284+
]
285+
}
286+
]
287+
}

.github/workflows/automated-sonarqube-cloud-analysis.yml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,60 @@ jobs:
2626
env:
2727
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
2828
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
29+
30+
notify-slack:
31+
runs-on: ubuntu-latest
32+
needs: [sonarqube_cloud]
33+
if: failure() && github.event_name == 'push' && github.ref == 'refs/heads/main'
34+
steps:
35+
- name: Configure AWS Credentials
36+
uses: aws-actions/configure-aws-credentials@v5
37+
with:
38+
role-to-assume: ${{ secrets.AWS_ASSUME_ROLE }}
39+
aws-region: ${{ vars.AWS_REGION }}
40+
41+
- name: Get slack bot token from SSM parameter store
42+
run: |
43+
slack_bot_token=$(aws ssm get-parameter --name "/ndr/alerting/slack/bot_token" --with-decryption --query "Parameter.Value" --output text)
44+
echo "::add-mask::$slack_bot_token"
45+
echo "SLACK_BOT_TOKEN=$slack_bot_token" >> $GITHUB_ENV
46+
47+
- name: Send Slack Notification
48+
uses: slackapi/[email protected]
49+
with:
50+
method: chat.postMessage
51+
token: ${{ env.SLACK_BOT_TOKEN }}
52+
payload: |
53+
{
54+
"channel": "${{ vars.ALERTS_SLACK_CHANNEL_ID }}",
55+
"attachments": [
56+
{
57+
"color": "#ff0000",
58+
"blocks": [
59+
{
60+
"type": "header",
61+
"text": {
62+
"type": "plain_text",
63+
"text": "❌ Workflow `${{ github.workflow }}` failed"
64+
}
65+
},
66+
{
67+
"type": "section",
68+
"text": {
69+
"type": "mrkdwn",
70+
"text": "*Triggered by:* `${{ github.actor }}`\n*Branch:* `${{ github.ref_name }}`\n*Workflow:* <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|${{ github.workflow }}>"
71+
}
72+
},
73+
{
74+
"type": "divider"
75+
},
76+
{
77+
"type": "section",
78+
"fields": [
79+
{ "type": "mrkdwn", "text": "*sonarqube_cloud:* ${{ needs.sonarqube_cloud.result == 'success' && ':white_check_mark:' || ':x:' }}" }
80+
]
81+
}
82+
]
83+
}
84+
]
85+
}

.github/workflows/cron-daily-health-check.yml

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ jobs:
160160
environment: development
161161
python_version: "3.11"
162162
secrets:
163-
AWS_ASSUME_ROLE: ${{ secrets.AWS_ASSUME_ROLE }}
163+
AWS_ASSUME_ROLE: ${{ secrets.AWS_ASSUME_ROLE }}
164164

165165
deploy_lambdas:
166166
name: Deploy Lambdas
@@ -196,3 +196,72 @@ jobs:
196196
sandbox_name: ${{ needs.set_workspace.outputs.workspace }}
197197
environment: development
198198
secrets: inherit
199+
200+
notify-slack:
201+
runs-on: ubuntu-latest
202+
needs: [terraform_plan_apply, run_lambda_unit_tests, run_ui_unit_tests, run_cypress_tests, publish_lambda_layers, deploy_lambdas, deploy_ui]
203+
if: failure()
204+
steps:
205+
- name: Configure AWS Credentials
206+
uses: aws-actions/configure-aws-credentials@v5
207+
with:
208+
role-to-assume: ${{ secrets.AWS_ASSUME_ROLE }}
209+
aws-region: ${{ vars.AWS_REGION }}
210+
211+
- name: Get slack bot token from SSM parameter store
212+
run: |
213+
slack_bot_token=$(aws ssm get-parameter --name "/ndr/alerting/slack/bot_token" --with-decryption --query "Parameter.Value" --output text)
214+
echo "::add-mask::$slack_bot_token"
215+
echo "SLACK_BOT_TOKEN=$slack_bot_token" >> $GITHUB_ENV
216+
217+
- name: Send Slack Notification
218+
uses: slackapi/[email protected]
219+
with:
220+
method: chat.postMessage
221+
token: ${{ env.SLACK_BOT_TOKEN }}
222+
payload: |
223+
{
224+
"channel": "${{ vars.ALERTS_SLACK_CHANNEL_ID }}",
225+
"attachments": [
226+
{
227+
"color": "#ff0000",
228+
"blocks": [
229+
{
230+
"type": "header",
231+
"text": {
232+
"type": "plain_text",
233+
"text": "❌ Workflow `${{ github.workflow }}` failed"
234+
}
235+
},
236+
{
237+
"type": "section",
238+
"text": {
239+
"type": "mrkdwn",
240+
"text": "*Triggered by:* `Scheduled Job`\n*Workflow:* <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|${{ github.workflow }}>"
241+
}
242+
},
243+
{
244+
"type": "divider"
245+
},
246+
{
247+
"type": "section",
248+
"fields": [
249+
{ "type": "mrkdwn", "text": "*terraform_plan_apply:* ${{ needs.terraform_plan_apply.result == 'success' && ':white_check_mark:' || ':x:' }}" },
250+
{ "type": "mrkdwn", "text": "*run_lambda_unit_tests:* ${{ needs.run_lambda_unit_tests.result == 'success' && ':white_check_mark:' || ':x:' }}" },
251+
{ "type": "mrkdwn", "text": "*run_ui_unit_tests:* ${{ needs.run_ui_unit_tests.result == 'success' && ':white_check_mark:' || ':x:' }}" },
252+
{ "type": "mrkdwn", "text": "*run_cypress_tests:* ${{ needs.run_cypress_tests.result == 'success' && ':white_check_mark:' || ':x:' }}" },
253+
{ "type": "mrkdwn", "text": "*publish_lambda_layers:* ${{ needs.publish_lambda_layers.result == 'success' && ':white_check_mark:' || ':x:' }}" },
254+
{ "type": "mrkdwn", "text": "*deploy_lambdas:* ${{ needs.deploy_lambdas.result == 'success' && ':white_check_mark:' || ':x:' }}" },
255+
{ "type": "mrkdwn", "text": "*deploy_ui:* ${{ needs.deploy_ui.result == 'success' && ':white_check_mark:' || ':x:' }}" }
256+
]
257+
},
258+
{
259+
"type": "context",
260+
"elements": [
261+
{ "type": "mrkdwn", "text": "Environment: `development` | Sandbox: `${{ needs.set_workspace.outputs.workspace }}`" }
262+
]
263+
}
264+
]
265+
}
266+
]
267+
}

infrastructure/api.tf

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ resource "aws_api_gateway_deployment" "ndr_api_deploy" {
6060
module.feature-flags-lambda,
6161
module.fhir_document_reference_gateway,
6262
module.get-doc-fhir-lambda,
63+
module.get_document_review_lambda,
64+
module.get-doc-ref-lambda,
6365
module.get-report-by-ods-gateway,
6466
module.get-report-by-ods-lambda,
6567
module.lloyd-george-stitch-gateway,
@@ -68,16 +70,19 @@ resource "aws_api_gateway_deployment" "ndr_api_deploy" {
6870
module.logout_lambda,
6971
module.search-document-references-gateway,
7072
module.search-document-references-lambda,
73+
module.search_document_review_lambda,
7174
module.search-patient-details-gateway,
7275
module.search-patient-details-lambda,
7376
module.send-feedback-gateway,
7477
module.send-feedback-lambda,
75-
module.update_doc_ref_lambda,
78+
module.review_document_version_gateway,
79+
module.update-doc-ref-lambda,
7680
module.update-upload-state-gateway,
7781
module.update-upload-state-lambda,
7882
module.document-status-check-gateway,
7983
module.document-status-check-lambda,
8084
module.post-document-references-fhir-lambda,
85+
module.patch_document_review_lambda,
8186
module.virus_scan_result_gateway,
8287
module.virus_scan_result_lambda
8388
]

infrastructure/buckets.tf

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,6 @@ resource "aws_s3_bucket_lifecycle_configuration" "ndr_document_pending_review_st
283283
}
284284
}
285285

286-
287286
# Logging Buckets
288287
resource "aws_s3_bucket" "access_logs" {
289288
count = local.access_logs_count

infrastructure/gateway-document-reference.tf

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ module "document_reference_id_gateway" {
2626
source = "./modules/gateway"
2727
api_gateway_id = aws_api_gateway_rest_api.ndr_doc_store_api.id
2828
parent_id = module.document_reference_gateway.gateway_resource_id
29-
http_methods = ["PUT"]
29+
http_methods = ["PUT", "GET"]
3030
authorization = "CUSTOM"
3131
gateway_path = "{id}"
3232
authorizer_id = aws_api_gateway_authorizer.repo_authoriser.id
@@ -36,4 +36,6 @@ module "document_reference_id_gateway" {
3636
request_parameters = {
3737
"method.request.path.id" = true
3838
}
39+
40+
depends_on = [module.document_reference_gateway]
3941
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
module "review_document_gateway" {
2+
source = "./modules/gateway"
3+
api_gateway_id = aws_api_gateway_rest_api.ndr_doc_store_api.id
4+
parent_id = aws_api_gateway_rest_api.ndr_doc_store_api.root_resource_id
5+
http_methods = ["GET"]
6+
authorization = "CUSTOM"
7+
gateway_path = "DocumentReview"
8+
authorizer_id = aws_api_gateway_authorizer.repo_authoriser.id
9+
require_credentials = true
10+
origin = contains(["prod"], terraform.workspace) ? "'https://${var.domain}'" : "'https://${terraform.workspace}.${var.domain}'"
11+
}
12+
13+
resource "aws_api_gateway_resource" "review_document_id" {
14+
rest_api_id = aws_api_gateway_rest_api.ndr_doc_store_api.id
15+
parent_id = module.review_document_gateway.gateway_resource_id
16+
path_part = "{id}"
17+
}
18+
19+
module "review_document_version_gateway" {
20+
source = "./modules/gateway"
21+
api_gateway_id = aws_api_gateway_rest_api.ndr_doc_store_api.id
22+
parent_id = aws_api_gateway_resource.review_document_id.id
23+
http_methods = ["GET", "PATCH"]
24+
authorization = "CUSTOM"
25+
gateway_path = "{version}"
26+
authorizer_id = aws_api_gateway_authorizer.repo_authoriser.id
27+
require_credentials = true
28+
origin = contains(["prod"], terraform.workspace) ? "'https://${var.domain}'" : "'https://${terraform.workspace}.${var.domain}'"
29+
30+
request_parameters = {
31+
"method.request.path.id" = true
32+
"method.request.path.version" = true
33+
}
34+
}

infrastructure/iam.tf

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,11 @@ data "aws_iam_policy_document" "assume_role_policy_for_get_doc_ref_lambda" {
139139
actions = ["sts:AssumeRole"]
140140

141141
principals {
142-
type = "AWS"
143-
identifiers = [module.get-doc-fhir-lambda.lambda_execution_role_arn]
142+
type = "AWS"
143+
identifiers = [
144+
module.get-doc-fhir-lambda.lambda_execution_role_arn,
145+
module.get-doc-ref-lambda.lambda_execution_role_arn
146+
]
144147
}
145148
}
146149
}
@@ -251,7 +254,7 @@ data "aws_iam_policy_document" "assume_role_policy_for_update_lambda" {
251254
principals {
252255
type = "AWS"
253256
identifiers = compact([
254-
module.update_doc_ref_lambda.lambda_execution_role_arn
257+
module.update-doc-ref-lambda.lambda_execution_role_arn
255258
])
256259
}
257260
}
@@ -266,3 +269,51 @@ resource "aws_iam_role_policy_attachment" "update_put_presign_url" {
266269
role = aws_iam_role.update_put_presign_url_role.name
267270
policy_arn = aws_iam_policy.s3_document_data_policy_put_only.arn
268271
}
272+
273+
data "aws_iam_policy_document" "assume_role_policy_get_document_review_lambda" {
274+
statement {
275+
actions = ["sts:AssumeRole"]
276+
277+
principals {
278+
type = "AWS"
279+
identifiers = [module.get_document_review_lambda.lambda_execution_role_arn]
280+
}
281+
}
282+
}
283+
284+
resource "aws_iam_role" "get_document_review_presign" {
285+
name = "${terraform.workspace}_get_review_presign_url_role"
286+
assume_role_policy = data.aws_iam_policy_document.assume_role_policy_get_document_review_lambda.json
287+
}
288+
289+
resource "aws_iam_role_policy_attachment" "get_document_review" {
290+
role = aws_iam_role.get_document_review_presign.name
291+
policy_arn = aws_iam_policy.s3_document_data_policy_get_document_review_lambda.arn
292+
}
293+
294+
resource "aws_iam_policy" "s3_document_data_policy_get_document_review_lambda" {
295+
name = "${terraform.workspace}_get_document_only_policy_for_get_document_review_lambda"
296+
297+
policy = jsonencode({
298+
"Version" : "2012-10-17",
299+
"Statement" : [
300+
{
301+
"Effect" : "Allow",
302+
"Action" : [
303+
"s3:GetObject",
304+
],
305+
"Resource" : ["${module.ndr-document-pending-review-store.bucket_arn}/*"]
306+
}
307+
]
308+
})
309+
}
310+
311+
resource "aws_iam_role" "get_doc_ref_presign_url_role" {
312+
name = "${terraform.workspace}_get_doc_ref_presign_url_role"
313+
assume_role_policy = data.aws_iam_policy_document.assume_role_policy_for_get_doc_ref_lambda.json
314+
}
315+
316+
resource "aws_iam_role_policy_attachment" "get_doc_ref_presign_url" {
317+
role = aws_iam_role.get_doc_ref_presign_url_role.name
318+
policy_arn = aws_iam_policy.s3_document_data_policy_for_get_doc_ref_lambda.arn
319+
}

0 commit comments

Comments
 (0)