Skip to content

Commit 7442128

Browse files
nsindhu26mabe13dependabot[bot]TomdangoSindhu
authored
Release/27.0 (#1036)
# Release Branch Pull Request ## Description of Changes Release includes changes to accept Distance Selling Pharmacies and some PEN test fixes --------- Co-authored-by: Matthew Begley <60427904+mabe13@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Thomas Judd-Cooper <me@tomjuddcooper.co.uk> Co-authored-by: Sindhu <nsindhu26@gmail.com> Co-authored-by: ThomasC-Kainos <106971950+ThomasC-Kainos@users.noreply.github.com> Co-authored-by: ManithaSrinivasa <manitha.srinivasa@accenture.com>
1 parent a34a326 commit 7442128

15 files changed

Lines changed: 284 additions & 16 deletions

application/common/constants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
CLOSED_AND_HIDDEN_STATUSES = ["HIDDEN", "CLOSED"]
44

55
PHARMACY_SERVICE_TYPE_IDS = [13, 131, 132, 134, 137, 148, 149]
6-
PHARMACY_ORGANISATION_SUB_TYPES = ["Community"]
6+
PHARMACY_ORGANISATION_SUB_TYPES = ["Community", "DistanceSelling"]
77
PHARMACY_ODSCODE_LENGTH = 5
88
PHARMACY_SERVICE_TYPE_ID = 13
99

infrastructure/stacks/application/data.tf

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,22 @@ data "aws_iam_policy_document" "sns_topic_app_alerts_for_slack_access_default_re
5151
}
5252
resources = [aws_sns_topic.sns_topic_app_alerts_for_slack_default_region.arn]
5353
}
54+
55+
statement {
56+
sid = "DenyNonSecureTransport"
57+
effect = "Deny"
58+
actions = ["sns:Publish"]
59+
principals {
60+
type = "*"
61+
identifiers = ["*"]
62+
}
63+
resources = [aws_sns_topic.sns_topic_app_alerts_for_slack_default_region.arn]
64+
condition {
65+
test = "Bool"
66+
variable = "aws:SecureTransport"
67+
values = ["false"]
68+
}
69+
}
5470
}
5571

5672
data "aws_iam_policy_document" "sns_topic_app_alerts_for_slack_access_alarm_region" {
@@ -63,6 +79,22 @@ data "aws_iam_policy_document" "sns_topic_app_alerts_for_slack_access_alarm_regi
6379
}
6480
resources = [aws_sns_topic.sns_topic_app_alerts_for_slack_route53_health_check_alarm_region.arn]
6581
}
82+
83+
statement {
84+
sid = "DenyNonSecureTransport"
85+
effect = "Deny"
86+
actions = ["sns:Publish"]
87+
principals {
88+
type = "*"
89+
identifiers = ["*"]
90+
}
91+
resources = [aws_sns_topic.sns_topic_app_alerts_for_slack_route53_health_check_alarm_region.arn]
92+
condition {
93+
test = "Bool"
94+
variable = "aws:SecureTransport"
95+
values = ["false"]
96+
}
97+
}
6698
}
6799

68100
# ##############

infrastructure/stacks/application/security_groups.tf

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ resource "aws_security_group_rule" "allow_https_out" {
2222

2323
#tfsec:ignore:aws-vpc-no-public-egress-sgr
2424
resource "aws_security_group_rule" "allow_postgres_out" {
25-
type = "egress"
26-
from_port = 5432
27-
to_port = 5432
28-
protocol = "tcp"
29-
cidr_blocks = ["0.0.0.0/0"]
30-
security_group_id = aws_security_group.lambda_sg.id
31-
description = "Allow all Postgres outbound traffic"
25+
type = "egress"
26+
from_port = 5432
27+
to_port = 5432
28+
protocol = "tcp"
29+
source_security_group_id = data.aws_security_group.db_sg.id
30+
security_group_id = aws_security_group.lambda_sg.id
31+
description = "Allow all Postgres outbound traffic"
3232
}
3333

3434
resource "aws_security_group_rule" "database_allow_in_from_lambda" {

infrastructure/stacks/shared-resources/api-gateway-responses.tf

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ resource "aws_api_gateway_method_response" "response_200" {
77
"method.response.header.Cache-control" = true
88
"method.response.header.Pragma" = true
99
"method.response.header.Strict-Transport-Security" = true
10+
"method.response.header.X-Frame-Options" = true
11+
"method.response.header.X-Content-Type-Options" = true
12+
"method.response.header.Content-Security-Policy" = true
1013
}
1114
response_models = {
1215
"application/json" = aws_api_gateway_model.default_model.name
@@ -22,6 +25,9 @@ resource "aws_api_gateway_method_response" "response_400" {
2225
"method.response.header.Cache-control" = true
2326
"method.response.header.Pragma" = true
2427
"method.response.header.Strict-Transport-Security" = true
28+
"method.response.header.X-Frame-Options" = true
29+
"method.response.header.X-Content-Type-Options" = true
30+
"method.response.header.Content-Security-Policy" = true
2531
}
2632
response_models = {
2733
"application/json" = aws_api_gateway_model.default_model.name
@@ -37,6 +43,9 @@ resource "aws_api_gateway_method_response" "response_500" {
3743
"method.response.header.Cache-control" = true
3844
"method.response.header.Pragma" = true
3945
"method.response.header.Strict-Transport-Security" = true
46+
"method.response.header.X-Frame-Options" = true
47+
"method.response.header.X-Content-Type-Options" = true
48+
"method.response.header.Content-Security-Policy" = true
4049
}
4150
response_models = {
4251
"application/json" = aws_api_gateway_model.default_model.name
@@ -54,6 +63,9 @@ resource "aws_api_gateway_integration_response" "di_endpoint_integration_success
5463
"method.response.header.Cache-control" = "'no-cache'"
5564
"method.response.header.Pragma" = "'no-store'"
5665
"method.response.header.Strict-Transport-Security" = "'max-age=31536000; includeSubDomains'"
66+
"method.response.header.X-Frame-Options" = "'DENY'"
67+
"method.response.header.X-Content-Type-Options" = "'nosniff'"
68+
"method.response.header.Content-Security-Policy" = "'default-src 'self''"
5769
}
5870

5971
depends_on = [
@@ -75,6 +87,9 @@ resource "aws_api_gateway_integration_response" "response_400" {
7587
"method.response.header.Cache-control" = "'no-cache'"
7688
"method.response.header.Pragma" = "'no-store'"
7789
"method.response.header.Strict-Transport-Security" = "'max-age=31536000; includeSubDomains'"
90+
"method.response.header.X-Frame-Options" = "'DENY'"
91+
"method.response.header.X-Content-Type-Options" = "'nosniff'"
92+
"method.response.header.Content-Security-Policy" = "'default-src 'self''"
7893
}
7994

8095
depends_on = [
@@ -96,6 +111,9 @@ resource "aws_api_gateway_integration_response" "response_500" {
96111
"method.response.header.Cache-control" = "'no-cache'"
97112
"method.response.header.Pragma" = "'no-store'"
98113
"method.response.header.Strict-Transport-Security" = "'max-age=31536000; includeSubDomains'"
114+
"method.response.header.X-Frame-Options" = "'DENY'"
115+
"method.response.header.X-Content-Type-Options" = "'nosniff'"
116+
"method.response.header.Content-Security-Policy" = "'default-src 'self''"
99117
}
100118

101119
depends_on = [
@@ -112,9 +130,41 @@ resource "aws_api_gateway_gateway_response" "access_denied_403_gateway_response"
112130
response_type = "ACCESS_DENIED"
113131
response_templates = ({ "application/json" : jsonencode({ "Message" : "Access Denied, please contact the development team for assistance" }) })
114132

133+
response_parameters = {
134+
"gatewayresponse.header.Cache-control" = "'no-cache'"
135+
"gatewayresponse.header.Pragma" = "'no-store'"
136+
"gatewayresponse.header.Strict-Transport-Security" = "'max-age=31536000; includeSubDomains'"
137+
"gatewayresponse.header.X-Frame-Options" = "'DENY'"
138+
"gatewayresponse.header.X-Content-Type-Options" = "'nosniff'"
139+
"gatewayresponse.header.Content-Security-Policy" = "'default-src 'self''"
140+
}
141+
115142
depends_on = [
116143
aws_api_gateway_integration.di_endpoint_integration,
117144
aws_api_gateway_resource.di_endpoint_change_event_path,
118145
aws_api_gateway_method.di_endpoint_method,
119146
]
120147
}
148+
149+
resource "aws_api_gateway_gateway_response" "invalid_api_key_403_response" {
150+
rest_api_id = aws_api_gateway_rest_api.di_endpoint.id
151+
status_code = "403"
152+
response_type = "INVALID_API_KEY"
153+
response_templates = ({ "application/json" : jsonencode({ "message" : "Forbidden" }) })
154+
155+
response_parameters = {
156+
"gatewayresponse.header.Cache-Control" = "'no-cache'"
157+
"gatewayresponse.header.Pragma" = "'no-store'"
158+
"gatewayresponse.header.Strict-Transport-Security" = "'max-age=31536000; includeSubDomains'"
159+
"gatewayresponse.header.X-Frame-Options" = "'DENY'"
160+
"gatewayresponse.header.X-Content-Type-Options" = "'nosniff'"
161+
"gatewayresponse.header.Content-Security-Policy" = "'default-src 'self''"
162+
}
163+
164+
depends_on = [
165+
aws_api_gateway_integration.di_endpoint_integration,
166+
aws_api_gateway_resource.di_endpoint_change_event_path,
167+
aws_api_gateway_method.di_endpoint_method,
168+
]
169+
}
170+

infrastructure/stacks/shared-resources/api-gateway.tf

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ EOF
9595
resource "aws_api_gateway_deployment" "di_endpoint_deployment" {
9696
rest_api_id = aws_api_gateway_rest_api.di_endpoint.id
9797
depends_on = [
98-
aws_api_gateway_rest_api_policy.di_endpoint_policy
98+
aws_api_gateway_rest_api_policy.di_endpoint_policy,
99+
aws_api_gateway_gateway_response.invalid_api_key_403_response
99100
]
100101
triggers = {
101102
redeployment = join("", [md5(jsonencode([

infrastructure/stacks/shared-resources/data.tf

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,22 @@ data "aws_iam_policy_document" "shared_resources_sns_topic_app_alerts_for_slack_
6868
}
6969
resources = [aws_sns_topic.shared_resources_sns_topic_app_alerts_for_slack_default_region.arn]
7070
}
71+
72+
statement {
73+
sid = "DenyNonSecureTransport"
74+
effect = "Deny"
75+
actions = ["sns:Publish"]
76+
principals {
77+
type = "*"
78+
identifiers = ["*"]
79+
}
80+
resources = [aws_sns_topic.shared_resources_sns_topic_app_alerts_for_slack_default_region.arn]
81+
condition {
82+
test = "Bool"
83+
variable = "aws:SecureTransport"
84+
values = ["false"]
85+
}
86+
}
7187
}
7288

7389
data "aws_iam_policy_document" "shared_resources_sns_topic_app_alerts_for_slack_access_alarm_region" {
@@ -80,6 +96,22 @@ data "aws_iam_policy_document" "shared_resources_sns_topic_app_alerts_for_slack_
8096
}
8197
resources = [aws_sns_topic.shared_resources_sns_topic_app_alerts_for_slack_route53_health_check_alarm_region.arn]
8298
}
99+
100+
statement {
101+
sid = "DenyNonSecureTransport"
102+
effect = "Deny"
103+
actions = ["sns:Publish"]
104+
principals {
105+
type = "*"
106+
identifiers = ["*"]
107+
}
108+
resources = [aws_sns_topic.shared_resources_sns_topic_app_alerts_for_slack_route53_health_check_alarm_region.arn]
109+
condition {
110+
test = "Bool"
111+
variable = "aws:SecureTransport"
112+
values = ["false"]
113+
}
114+
}
83115
}
84116

85117
data "aws_iam_role" "di_firehose_role" {

test/integration/features/F001_Valid_Change_Events.feature

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,9 @@ Feature: F001. Ensure valid change events are converted and sent to DoS
5959
Scenario: F001SXX3. A Changed event with aligned data does not save an update to DoS
6060
Given a basic service is created
6161
When the Changed Event is sent for processing with "valid" api key
62-
Then the "service-sync" lambda shows field "message" with value "No changes to save"
62+
Then the change event response has status code "200"
63+
And the response has security headers
64+
And the "service-sync" lambda shows field "message" with value "No changes to save"
6365
And the service history is not updated
6466

6567
@complete @general
@@ -511,3 +513,51 @@ Feature: F001. Ensure valid change events are converted and sent to DoS
511513
| " 0123456789" | 0123456789 |
512514
| "0123456789 " | 0123456789 |
513515
| "012 34567 89" | 0123456789 |
516+
517+
518+
@complete @general
519+
Scenario Outline: F001SX40. Changes are processed successfully for service_type = "134" with OrganisationSubType = "DistanceSelling"
520+
Given an entry is created in the services table
521+
And the service "service_type" is set to "134"
522+
And the service "service_status" is set to "1"
523+
And the entry is committed to the services table
524+
And the change event "OrganisationSubType" is set to "DistanceSelling"
525+
When the Changed Event is sent for processing with "valid" api key
526+
Then the "service-sync" lambda shows field "message" with value "Update Request Success"
527+
Then the Changed Event is stored in dynamo db
528+
And the service history is not updated
529+
When the change event "<field>" is set to "<value>"
530+
When the Changed Event is sent for processing with "valid" api key
531+
Then the Changed Event is stored in dynamo db
532+
Then the "<DOS_field>" is updated within the DoS DB
533+
And the service history shows "<service_hist_field>" change type is "modify"
534+
535+
Examples:
536+
| field | value | DOS_field |service_hist_field |
537+
| website | www.testonetwo.com | website | cmsurl |
538+
| phone | 22459436909 | phone | cmstelephoneno |
539+
| Address1 | 5 Tester Way | address | postaladdress |
540+
541+
@complete @general
542+
Scenario: F001SX41. Changed Event with updated postcode to verify location changes with service_type = "134" and OrganisationSubType = "DistanceSelling"
543+
Given an entry is created in the services table
544+
And the service "service_type" is set to "134"
545+
And the service "service_status" is set to "1"
546+
And the entry is committed to the services table
547+
And the change event "OrganisationSubType" is set to "DistanceSelling"
548+
When the Changed Event is sent for processing with "valid" api key
549+
Then the "service-sync" lambda shows field "message" with value "Update Request Success"
550+
Then the Changed Event is stored in dynamo db
551+
And the service history is not updated
552+
When the change event "Postcode" is set to "PR4 2BE"
553+
When the Changed Event is sent for processing with "valid" api key
554+
Then the Changed Event is stored in dynamo db
555+
Then DoS has "PR4 2BE" in the "Postcode" field
556+
Then DoS has "KIRKHAM" in the "town" field
557+
And DoS has "341832" in the "easting" field
558+
And DoS has "432011" in the "northing" field
559+
And DoS has "53.781108" in the "latitude" field
560+
And DoS has "-2.886537" in the "longitude" field
561+
And the service history is updated with the "Postcode"
562+
And the service history shows "postalcode" change type is "modify"
563+

test/integration/features/F002_Invalid_Change_Events.feature

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,11 @@ Feature: F002. Invalid change event Exception handling
6262
And the change event has an additional date with no specified date
6363
When the Changed Event is sent for processing with "valid" api key
6464
Then the "service-sync" lambda shows field "message" with value "Opening times are not valid"
65+
66+
@complete @validation
67+
Scenario: F002SXX9. A Changed Event where OrganisationSubType is NOT DistanceSelling is reported and ignored
68+
Given a basic service is created with type "134"
69+
And the change event "OrganisationSubType" is set to "Distance Selling"
70+
When the Changed Event is sent for processing with "valid" api key
71+
Then the "ingest-change-event" lambda shows field "message" with value "Validation Error - Unexpected Org Sub Type ID: 'Distance Selling'"
72+
And the service history is not updated

test/integration/features/F003_DoS_Security.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ Feature: F003. Endpoint security and reporting
55
Given a basic service is created
66
When the Changed Event is sent for processing with "invalid" api key
77
Then the change event response has status code "403"
8+
And the response has security headers
89
And the Slack channel shows an alert saying "DI 4XX Endpoint Errors" from "SHARED_ENVIRONMENT"

test/integration/features/F004_Error_Handling.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Feature: F004. Error Handling
55
Given a basic service is created
66
When the Changed Event is sent for processing with no sequence id
77
Then the change event response has status code "400"
8+
And the response has security headers
89

910
@complete @slack_and_infrastructure
1011
Scenario: F004SXX6. An Alphanumeric Sequence number raises a 400 Bad Request exception

0 commit comments

Comments
 (0)