Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/scripts/delete_proxygen_deployments.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ delete_apigee_deployments() {
APIGEE_API=$2
PROXYGEN_PRIVATE_KEY_NAME=$3
PROXYGEN_KID=$4
proxygen_private_key_arn=$(aws cloudformation list-exports --query "Exports[?Name=='account-resources:${PROXYGEN_PRIVATE_KEY_NAME}'].Value" --output text)

proxygen_private_key_arn=$(aws cloudformation list-exports --query "Exports[?Name=='secrets-cdk:Secrets:${PROXYGEN_PRIVATE_KEY_NAME}:Arn'].Value" --output text)
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the CloudFormation export isn’t present, this list-exports query will return an empty string and the subsequent Lambda payloads will be built with an invalid proxygenSecretName. Add a check after this assignment to ensure proxygen_private_key_arn is non-empty and exit with a clear error if it can’t be resolved.

Suggested change
if [ -z "${proxygen_private_key_arn}" ]; then
echo "Error: Unable to resolve CloudFormation export secrets-cdk:Secrets:${PROXYGEN_PRIVATE_KEY_NAME}:Arn for ${APIGEE_ENVIRONMENT}. Cannot continue without a valid proxygen private key ARN."
exit 1
fi

Copilot uses AI. Check for mistakes.
echo
echo "checking apigee deployments on ${APIGEE_ENVIRONMENT}"
echo
Expand Down
2 changes: 1 addition & 1 deletion .github/scripts/deploy_api.sh
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ echo
echo "Retrieving proxygen credentials"

# Retrieve the proxygen private key and client private key and cert from AWS Secrets Manager
proxygen_private_key_arn=$(aws cloudformation list-exports --query "Exports[?Name=='account-resources:${PROXYGEN_PRIVATE_KEY_NAME}'].Value" --output text)
proxygen_private_key_arn=$(aws cloudformation list-exports --query "Exports[?Name=='secrets-cdk:Secrets:${PROXYGEN_PRIVATE_KEY_NAME}:Arn'].Value" --output text)

Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the CloudFormation export isn’t present, this list-exports query will return an empty string and later payloads will use an invalid proxygenSecretName. Add a check after this assignment to ensure proxygen_private_key_arn is non-empty and exit with a clear error if it can’t be resolved.

Suggested change
if [[ -z "${proxygen_private_key_arn}" || "${proxygen_private_key_arn}" == "None" ]]; then
echo "Error: Could not resolve CloudFormation export 'secrets-cdk:Secrets:${PROXYGEN_PRIVATE_KEY_NAME}:Arn' for PROXYGEN_PRIVATE_KEY_NAME='${PROXYGEN_PRIVATE_KEY_NAME}'." >&2
exit 1
fi

Copilot uses AI. Check for mistakes.
if [[ "${ENABLE_MUTUAL_TLS}" == "true" ]]; then
echo
Expand Down
40 changes: 28 additions & 12 deletions .github/scripts/release_code.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,43 @@ export AWS_MAX_ATTEMPTS
echo "$COMMIT_ID"

CF_LONDON_EXPORTS=$(aws cloudformation list-exports --region eu-west-2 --output json)
artifact_bucket_arn=$(echo "$CF_LONDON_EXPORTS" | \

ARTIFACT_BUCKET_ARN=$(echo "$CF_LONDON_EXPORTS" | \
jq \
--arg EXPORT_NAME "account-resources:ArtifactsBucket" \
--arg EXPORT_NAME "account-resources-cdk-uk:Bucket:ArtifactsBucket:Arn" \
-r '.Exports[] | select(.Name == $EXPORT_NAME) | .Value')
artifact_bucket=$(echo "$artifact_bucket_arn" | cut -d: -f6 | cut -d/ -f1)
export artifact_bucket
ARTIFACT_BUCKET_NAME=$(echo "${ARTIFACT_BUCKET_ARN}" | cut -d ":" -f 6)

if [ -z "${ARTIFACT_BUCKET_NAME}" ]; then
echo "could not retrieve ARTIFACT_BUCKET_NAME from aws cloudformation list-exports"
exit 1
fi

cloud_formation_execution_role=$(echo "$CF_LONDON_EXPORTS" | \
CLOUD_FORMATION_EXECUTION_ROLE=$(echo "$CF_LONDON_EXPORTS" | \
jq \
--arg EXPORT_NAME "ci-resources:CloudFormationExecutionRole" \
--arg EXPORT_NAME "iam-cdk:IAM:CloudFormationExecutionRole:Arn" \
-r '.Exports[] | select(.Name == $EXPORT_NAME) | .Value')

if [ -z "${cloud_formation_execution_role}" ]; then
echo "could not retrieve ROLE from aws cloudformation list-exports"
if [ -z "${CLOUD_FORMATION_EXECUTION_ROLE}" ]; then
echo "could not retrieve CLOUD_FORMATION_EXECUTION_ROLE from aws cloudformation list-exports"
exit 1
fi
export cloud_formation_execution_role

TRUSTSTORE_BUCKET_ARN=$(aws cloudformation describe-stacks --stack-name account-resources --query "Stacks[0].Outputs[?OutputKey=='TrustStoreBucket'].OutputValue" --output text)
TRUSTSTORE_BUCKET_ARN=$(echo "$CF_LONDON_EXPORTS" | \
jq \
--arg EXPORT_NAME "account-resources-cdk-uk:Bucket:TrustStoreBucket:Arn" \
-r '.Exports[] | select(.Name == $EXPORT_NAME) | .Value')
TRUSTSTORE_BUCKET_NAME=$(echo "${TRUSTSTORE_BUCKET_ARN}" | cut -d ":" -f 6)

if [ -z "${TRUSTSTORE_BUCKET_NAME}" ]; then
echo "could not retrieve TRUSTSTORE_BUCKET_NAME from aws cloudformation list-exports"
exit 1
fi

LATEST_TRUSTSTORE_VERSION=$(aws s3api list-object-versions --bucket "${TRUSTSTORE_BUCKET_NAME}" --prefix "${TRUSTSTORE_FILE}" --query 'Versions[?IsLatest].[VersionId]' --output text)

export ARTIFACT_BUCKET_NAME
export CLOUD_FORMATION_EXECUTION_ROLE
export LATEST_TRUSTSTORE_VERSION

cd ../../.aws-sam/build || exit
Expand All @@ -42,11 +58,11 @@ sam deploy \
--stack-name "$STACK_NAME" \
--capabilities CAPABILITY_NAMED_IAM CAPABILITY_AUTO_EXPAND \
--region eu-west-2 \
--s3-bucket "$artifact_bucket" \
--s3-bucket "$ARTIFACT_BUCKET_NAME" \
--s3-prefix "$ARTIFACT_BUCKET_PREFIX" \
--config-file samconfig_package_and_deploy.toml \
--no-fail-on-empty-changeset \
--role-arn "$cloud_formation_execution_role" \
--role-arn "$CLOUD_FORMATION_EXECUTION_ROLE" \
--no-confirm-changeset \
--force-upload \
--tags "version=$VERSION_NUMBER stack=$STACK_NAME repo=$REPO cfnDriftDetectionGroup=$CFN_DRIFT_DETECTION_GROUP" \
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/run_regression_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,11 @@ jobs:
run: |
if [[ "$TARGET_ENVIRONMENT" != "prod" && "$TARGET_ENVIRONMENT" != "ref" ]]; then
# this should be the tag of the tests you want to run
REGRESSION_TEST_REPO_TAG=v3.10.9
REGRESSION_TEST_REPO_TAG=v3.12.36

# this should be the tag of the regression test workflow you want to run
# This will normally be the same as REGRESSION_TEST_REPO_TAG
REGRESSION_TEST_WORKFLOW_TAG=v3.10.9
REGRESSION_TEST_WORKFLOW_TAG=v3.12.36

curl https://raw.githubusercontent.com/NHSDigital/electronic-prescription-service-api-regression-tests/refs/tags/${REGRESSION_TEST_WORKFLOW_TAG}/scripts/run_regression_tests.py -o run_regression_tests.py
poetry install
Expand Down
11 changes: 9 additions & 2 deletions .github/workflows/run_release_code_and_api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,15 @@ jobs:
shell: bash
run: |
mkdir -p ~/.proxygen/tmp
client_private_key_arn=$(aws cloudformation list-exports --query "Exports[?Name=='account-resources:PsuClientKeySecret'].Value" --output text)
client_cert_arn=$(aws cloudformation list-exports --query "Exports[?Name=='account-resources:PsuClientCertSecret'].Value" --output text)
CF_LONDON_EXPORTS=$(aws cloudformation list-exports --region eu-west-2 --output json)
client_private_key_arn=$(echo "$CF_LONDON_EXPORTS" | \
jq \
--arg EXPORT_NAME "secrets-cdk:Secrets:PsuClientKeySecret:Arn" \
-r '.Exports[] | select(.Name == $EXPORT_NAME) | .Value')
client_cert_arn=$(echo "$CF_LONDON_EXPORTS" | \
jq \
--arg EXPORT_NAME "secrets-cdk:Secrets:PsuClientCertSecret:Arn" \
-r '.Exports[] | select(.Name == $EXPORT_NAME) | .Value')
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These jq selections will return an empty string if the export name isn’t found, and the subsequent aws secretsmanager get-secret-value will fail with a confusing error (invalid/empty secret id). Add explicit checks that client_private_key_arn and client_cert_arn are non-empty and fail early with a clear message if the exports are missing.

Suggested change
-r '.Exports[] | select(.Name == $EXPORT_NAME) | .Value')
-r '.Exports[] | select(.Name == $EXPORT_NAME) | .Value')
if [[ -z "${client_private_key_arn}" ]]; then
echo "Error: required CloudFormation export 'secrets-cdk:Secrets:PsuClientKeySecret:Arn' was not found in eu-west-2." >&2
exit 1
fi
if [[ -z "${client_cert_arn}" ]]; then
echo "Error: required CloudFormation export 'secrets-cdk:Secrets:PsuClientCertSecret:Arn' was not found in eu-west-2." >&2
exit 1
fi

Copilot uses AI. Check for mistakes.
aws secretsmanager get-secret-value --secret-id "${client_private_key_arn}" --query SecretString --output text > ~/.proxygen/tmp/client_private_key
aws secretsmanager get-secret-value --secret-id "${client_cert_arn}" --query SecretString --output text > ~/.proxygen/tmp/client_cert
env:
Expand Down
54 changes: 27 additions & 27 deletions SAMtemplates/alarms/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,11 @@ Resources:
TreatMissingData: notBreaching
ActionsEnabled: !Ref EnableAlerts
AlarmActions:
- !ImportValue lambda-resources:SlackAlertsSnsTopicArn
- !ImportValue account-resources-cdk-uk:SNS:SlackAlertsSnsTopicArn:Arn
InsufficientDataActions:
- !ImportValue lambda-resources:SlackAlertsSnsTopicArn
- !ImportValue account-resources-cdk-uk:SNS:SlackAlertsSnsTopicArn:Arn
OKActions:
- !ImportValue lambda-resources:SlackAlertsSnsTopicArn
- !ImportValue account-resources-cdk-uk:SNS:SlackAlertsSnsTopicArn:Arn

GetStatusUpdatesUnhandledErrorsAlarm:
Type: AWS::CloudWatch::Alarm
Expand All @@ -91,11 +91,11 @@ Resources:
TreatMissingData: notBreaching
ActionsEnabled: !Ref EnableAlerts
AlarmActions:
- !ImportValue lambda-resources:SlackAlertsSnsTopicArn
- !ImportValue account-resources-cdk-uk:SNS:SlackAlertsSnsTopicArn:Arn
InsufficientDataActions:
- !ImportValue lambda-resources:SlackAlertsSnsTopicArn
- !ImportValue account-resources-cdk-uk:SNS:SlackAlertsSnsTopicArn:Arn
OKActions:
- !ImportValue lambda-resources:SlackAlertsSnsTopicArn
- !ImportValue account-resources-cdk-uk:SNS:SlackAlertsSnsTopicArn:Arn

PrescriptionStatusUpdateErrorsLogsMetricFilter:
Type: AWS::Logs::MetricFilter
Expand Down Expand Up @@ -172,11 +172,11 @@ Resources:
TreatMissingData: notBreaching
ActionsEnabled: !Ref EnableAlerts
AlarmActions:
- !ImportValue lambda-resources:SlackAlertsSnsTopicArn
- !ImportValue account-resources-cdk-uk:SNS:SlackAlertsSnsTopicArn:Arn
InsufficientDataActions:
- !ImportValue lambda-resources:SlackAlertsSnsTopicArn
- !ImportValue account-resources-cdk-uk:SNS:SlackAlertsSnsTopicArn:Arn
OKActions:
- !ImportValue lambda-resources:SlackAlertsSnsTopicArn
- !ImportValue account-resources-cdk-uk:SNS:SlackAlertsSnsTopicArn:Arn

PrescriptionStatusUpdateUnhandledErrorsAlarm:
Type: AWS::CloudWatch::Alarm
Expand All @@ -197,11 +197,11 @@ Resources:
TreatMissingData: notBreaching
ActionsEnabled: !Ref EnableAlerts
AlarmActions:
- !ImportValue lambda-resources:SlackAlertsSnsTopicArn
- !ImportValue account-resources-cdk-uk:SNS:SlackAlertsSnsTopicArn:Arn
InsufficientDataActions:
- !ImportValue lambda-resources:SlackAlertsSnsTopicArn
- !ImportValue account-resources-cdk-uk:SNS:SlackAlertsSnsTopicArn:Arn
OKActions:
- !ImportValue lambda-resources:SlackAlertsSnsTopicArn
- !ImportValue account-resources-cdk-uk:SNS:SlackAlertsSnsTopicArn:Arn

DynamoDBSystemErrorsAlarm:
Type: AWS::CloudWatch::Alarm
Expand All @@ -222,11 +222,11 @@ Resources:
TreatMissingData: notBreaching
ActionsEnabled: !Ref EnableAlerts
AlarmActions:
- !ImportValue lambda-resources:SlackAlertsSnsTopicArn
- !ImportValue account-resources-cdk-uk:SNS:SlackAlertsSnsTopicArn:Arn
InsufficientDataActions:
- !ImportValue lambda-resources:SlackAlertsSnsTopicArn
- !ImportValue account-resources-cdk-uk:SNS:SlackAlertsSnsTopicArn:Arn
OKActions:
- !ImportValue lambda-resources:SlackAlertsSnsTopicArn
- !ImportValue account-resources-cdk-uk:SNS:SlackAlertsSnsTopicArn:Arn

DynamoDBWriteConsumptionAlarm:
Type: AWS::CloudWatch::Alarm
Expand All @@ -235,11 +235,11 @@ Resources:
AlarmName: !Sub "${AWS::StackName}_DynamoDB_ConsumedWriteCapacity"
ActionsEnabled: !Ref EnableAlerts
AlarmActions:
- !ImportValue lambda-resources:SlackAlertsSnsTopicArn
- !ImportValue account-resources-cdk-uk:SNS:SlackAlertsSnsTopicArn:Arn
InsufficientDataActions:
- !ImportValue lambda-resources:SlackAlertsSnsTopicArn
- !ImportValue account-resources-cdk-uk:SNS:SlackAlertsSnsTopicArn:Arn
OKActions:
- !ImportValue lambda-resources:SlackAlertsSnsTopicArn
- !ImportValue account-resources-cdk-uk:SNS:SlackAlertsSnsTopicArn:Arn
EvaluationPeriods: 1
Threshold: !Ref DynamoDBUtilizationPercentageThreshold
ComparisonOperator: GreaterThanOrEqualToThreshold
Expand Down Expand Up @@ -307,11 +307,11 @@ Resources:
TreatMissingData: notBreaching
ActionsEnabled: !Ref EnableAlerts
AlarmActions:
- !ImportValue lambda-resources:SlackAlertsSnsTopicArn
- !ImportValue account-resources-cdk-uk:SNS:SlackAlertsSnsTopicArn:Arn
InsufficientDataActions:
- !ImportValue lambda-resources:SlackAlertsSnsTopicArn
- !ImportValue account-resources-cdk-uk:SNS:SlackAlertsSnsTopicArn:Arn
OKActions:
- !ImportValue lambda-resources:SlackAlertsSnsTopicArn
- !ImportValue account-resources-cdk-uk:SNS:SlackAlertsSnsTopicArn:Arn

NotifyProcessorTimeoutsMetricFilter:
Type: AWS::Logs::MetricFilter
Expand Down Expand Up @@ -344,11 +344,11 @@ Resources:
TreatMissingData: notBreaching
ActionsEnabled: !Ref EnableAlerts
AlarmActions:
- !ImportValue lambda-resources:SlackAlertsSnsTopicArn
- !ImportValue account-resources-cdk-uk:SNS:SlackAlertsSnsTopicArn:Arn
InsufficientDataActions:
- !ImportValue lambda-resources:SlackAlertsSnsTopicArn
- !ImportValue account-resources-cdk-uk:SNS:SlackAlertsSnsTopicArn:Arn
OKActions:
- !ImportValue lambda-resources:SlackAlertsSnsTopicArn
- !ImportValue account-resources-cdk-uk:SNS:SlackAlertsSnsTopicArn:Arn

NHSNotifyPrescriptionsDeadLetterQueueMessagesAlarm:
Type: AWS::CloudWatch::Alarm
Expand All @@ -370,8 +370,8 @@ Resources:
TreatMissingData: notBreaching
ActionsEnabled: !Ref EnableAlerts
AlarmActions:
- !ImportValue lambda-resources:SlackAlertsSnsTopicArn
- !ImportValue account-resources-cdk-uk:SNS:SlackAlertsSnsTopicArn:Arn
InsufficientDataActions:
- !ImportValue lambda-resources:SlackAlertsSnsTopicArn
- !ImportValue account-resources-cdk-uk:SNS:SlackAlertsSnsTopicArn:Arn
OKActions:
- !ImportValue lambda-resources:SlackAlertsSnsTopicArn
- !ImportValue account-resources-cdk-uk:SNS:SlackAlertsSnsTopicArn:Arn
8 changes: 4 additions & 4 deletions SAMtemplates/apis/api_resources.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -68,22 +68,22 @@ Resources:
Properties:
LogGroupName: !Sub /aws/apigateway/${ApiName}
RetentionInDays: !Ref LogRetentionInDays
KmsKeyId: !ImportValue account-resources:CloudwatchLogsKmsKeyArn
KmsKeyId: !ImportValue account-resources-cdk-uk:KMS:CloudwatchLogsKmsKey:Arn

ApiGwAccessLogsSplunkSubscriptionFilter:
Condition: ShouldUseSplunk
Type: AWS::Logs::SubscriptionFilter
Properties:
RoleArn: !ImportValue lambda-resources:SplunkSubscriptionFilterRole
RoleArn: !ImportValue account-resources-cdk-uk:IAM:SplunkSubscriptionFilterRole:Arn
LogGroupName: !Ref ApiGwAccessLogs
FilterPattern: ""
DestinationArn: !ImportValue lambda-resources:SplunkDeliveryStream
DestinationArn: !ImportValue account-resources-cdk-uk:Firehose:SplunkDeliveryStream:Arn

ApiGwAccessLogsCsocSubscriptionFilter:
Condition: ShouldForwardCsocLogs
Type: AWS::Logs::SubscriptionFilter
Properties:
RoleArn: !ImportValue lambda-resources:SplunkSubscriptionFilterRole
RoleArn: !ImportValue account-resources-cdk-uk:IAM:SplunkSubscriptionFilterRole:Arn
LogGroupName: !Ref ApiGwAccessLogs
FilterPattern: ""
DestinationArn: "arn:aws:logs:eu-west-2:693466633220:destination:api_gateway_log_destination"
Expand Down
2 changes: 1 addition & 1 deletion SAMtemplates/apis/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ Resources:
- 5
- !Split
- ":"
- !ImportValue account-resources:TrustStoreBucket
- !ImportValue account-resources-cdk-uk:Bucket:TrustStoreBucket:Arn
- psu-truststore.pem
- !Ref AWS::NoValue
TruststoreVersion: !If
Expand Down
6 changes: 3 additions & 3 deletions SAMtemplates/functions/lambda_resources.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@ Resources:
- !Join
- ","
- - !Ref LambdaManagedPolicy
- !ImportValue lambda-resources:LambdaInsightsLogGroupPolicy
- !ImportValue account-resources:CloudwatchEncryptionKMSPolicyArn
- !ImportValue account-resources:LambdaDecryptSecretsKMSPolicy
- !ImportValue account-resources-cdk-uk:IAM:LambdaInsightsLogGroupPolicy:Arn
- !ImportValue account-resources-cdk-uk:IAM:CloudwatchEncryptionKMSPolicy:Arn
- !ImportValue secrets-cdk:IAM:LambdaDecryptSecretsKMSPolicy:Arn
- !If
- ShouldIncludeAdditionalPolicies
- !Join
Expand Down
Loading
Loading