From ced56bea4bb400a13498e11a2b3b6c7bdacafd23 Mon Sep 17 00:00:00 2001 From: tstephen-nhs <231503406+tstephen-nhs@users.noreply.github.com> Date: Mon, 30 Mar 2026 10:33:34 +0000 Subject: [PATCH 01/12] fix: support IP6 AAAA record --- .../cdkConstructs/src/constructs/RestApiGateway.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/cdkConstructs/src/constructs/RestApiGateway.ts b/packages/cdkConstructs/src/constructs/RestApiGateway.ts index fe532fd4..b3747829 100644 --- a/packages/cdkConstructs/src/constructs/RestApiGateway.ts +++ b/packages/cdkConstructs/src/constructs/RestApiGateway.ts @@ -24,7 +24,12 @@ import {accessLogFormat} from "./RestApiGateway/accessLogFormat.js" import {Certificate, CertificateValidation} from "aws-cdk-lib/aws-certificatemanager" import {Bucket} from "aws-cdk-lib/aws-s3" import {BucketDeployment, Source} from "aws-cdk-lib/aws-s3-deployment" -import {ARecord, HostedZone, RecordTarget} from "aws-cdk-lib/aws-route53" +import { + ARecord, + AaaaRecord, + HostedZone, + RecordTarget +} from "aws-cdk-lib/aws-route53" import {ApiGateway as ApiGatewayTarget} from "aws-cdk-lib/aws-route53-targets" import {NagSuppressions} from "cdk-nag" import {ACCOUNT_RESOURCES, LAMBDA_RESOURCES} from "../constants" @@ -245,6 +250,12 @@ export class RestApiGateway extends Construct { zone: hostedZone }) + new AaaaRecord(this, "AaaaRecord", { + recordName: props.stackName, + target: RecordTarget.fromAlias(new ApiGatewayTarget(apiGateway)), + zone: hostedZone + }) + const cfnStage = apiGateway.deploymentStage.node.defaultChild as CfnStage cfnStage.cfnOptions.metadata = { guard: { From 0956257e3ef2640e3c3398d1ec41ef09048997fd Mon Sep 17 00:00:00 2001 From: tstephen-nhs <231503406+tstephen-nhs@users.noreply.github.com> Date: Mon, 30 Mar 2026 10:42:19 +0000 Subject: [PATCH 02/12] fix: merge suppressions instead of re-writing --- packages/cdkConstructs/src/constants.ts | 5 +++++ .../cdkConstructs/src/constructs/RestApiGateway.ts | 9 ++------- packages/cdkConstructs/src/constructs/StateMachine.ts | 11 +++-------- .../src/constructs/lambdaSharedResources.ts | 4 ++-- 4 files changed, 12 insertions(+), 17 deletions(-) diff --git a/packages/cdkConstructs/src/constants.ts b/packages/cdkConstructs/src/constants.ts index 7f6ca498..5cfef0a4 100644 --- a/packages/cdkConstructs/src/constants.ts +++ b/packages/cdkConstructs/src/constants.ts @@ -17,3 +17,8 @@ export const LAMBDA_RESOURCES = { SplunkDeliveryStream: Fn.importValue("lambda-resources:SplunkDeliveryStream"), SplunkSubscriptionFilterRole: Fn.importValue("lambda-resources:SplunkSubscriptionFilterRole") } + +/** Shared cfn-guard rule identifiers used for metadata suppressions. */ +export const CFN_GUARD_RULES = { + LogGroupRetentionPeriodCheck: "CW_LOGGROUP_RETENTION_PERIOD_CHECK" +} as const diff --git a/packages/cdkConstructs/src/constructs/RestApiGateway.ts b/packages/cdkConstructs/src/constructs/RestApiGateway.ts index b3747829..ac74b4e7 100644 --- a/packages/cdkConstructs/src/constructs/RestApiGateway.ts +++ b/packages/cdkConstructs/src/constructs/RestApiGateway.ts @@ -33,6 +33,7 @@ import { import {ApiGateway as ApiGatewayTarget} from "aws-cdk-lib/aws-route53-targets" import {NagSuppressions} from "cdk-nag" import {ACCOUNT_RESOURCES, LAMBDA_RESOURCES} from "../constants" +import {addSuppressions} from "../utils/helpers" /** Configuration for creating a REST API with optional mTLS and log forwarding integrations. */ export interface RestApiGatewayProps { @@ -257,13 +258,7 @@ export class RestApiGateway extends Construct { }) const cfnStage = apiGateway.deploymentStage.node.defaultChild as CfnStage - cfnStage.cfnOptions.metadata = { - guard: { - SuppressedRules: [ - "API_GW_CACHE_ENABLED_AND_ENCRYPTED" - ] - } - } + addSuppressions([cfnStage], ["API_GW_CACHE_ENABLED_AND_ENCRYPTED"]) // Outputs this.api = apiGateway diff --git a/packages/cdkConstructs/src/constructs/StateMachine.ts b/packages/cdkConstructs/src/constructs/StateMachine.ts index 821c4813..bbcdeea6 100644 --- a/packages/cdkConstructs/src/constructs/StateMachine.ts +++ b/packages/cdkConstructs/src/constructs/StateMachine.ts @@ -20,7 +20,8 @@ import { } from "aws-cdk-lib/aws-stepfunctions" import {Construct} from "constructs" import {CfnDeliveryStream} from "aws-cdk-lib/aws-kinesisfirehose" -import {ACCOUNT_RESOURCES, LAMBDA_RESOURCES} from "../constants" +import {ACCOUNT_RESOURCES, CFN_GUARD_RULES, LAMBDA_RESOURCES} from "../constants" +import {addSuppressions} from "../utils/helpers" /** * Configuration for provisioning an Express Step Functions state machine @@ -109,13 +110,7 @@ export class ExpressStateMachine extends Construct { }) const cfnLogGroup = logGroup.node.defaultChild as CfnLogGroup - cfnLogGroup.cfnOptions.metadata = { - guard: { - SuppressedRules: [ - "CW_LOGGROUP_RETENTION_PERIOD_CHECK" - ] - } - } + addSuppressions([cfnLogGroup], [CFN_GUARD_RULES.LogGroupRetentionPeriodCheck]) if (addSplunkSubscriptionFilter) { if (splunkDeliveryStream) { diff --git a/packages/cdkConstructs/src/constructs/lambdaSharedResources.ts b/packages/cdkConstructs/src/constructs/lambdaSharedResources.ts index 7f89899e..72177781 100644 --- a/packages/cdkConstructs/src/constructs/lambdaSharedResources.ts +++ b/packages/cdkConstructs/src/constructs/lambdaSharedResources.ts @@ -13,7 +13,7 @@ import { } from "aws-cdk-lib/aws-iam" import {NagSuppressions} from "cdk-nag" import {LAMBDA_INSIGHTS_LAYER_ARNS} from "../config" -import {ACCOUNT_RESOURCES, LAMBDA_RESOURCES} from "../constants" +import {ACCOUNT_RESOURCES, CFN_GUARD_RULES, LAMBDA_RESOURCES} from "../constants" import {addSuppressions} from "../utils/helpers" import {CfnDeliveryStream} from "aws-cdk-lib/aws-kinesisfirehose" import {Stream} from "aws-cdk-lib/aws-kinesis" @@ -74,7 +74,7 @@ export const createSharedLambdaResources = ( }) const cfnlogGroup = logGroup.node.defaultChild as CfnLogGroup - addSuppressions([cfnlogGroup], ["CW_LOGGROUP_RETENTION_PERIOD_CHECK"]) + addSuppressions([cfnlogGroup], [CFN_GUARD_RULES.LogGroupRetentionPeriodCheck]) if (addSplunkSubscriptionFilter) { // This is in an if statement to ensure correct value is used From 14204bc2995f5d4f03617755d9a3a8df33613fdf Mon Sep 17 00:00:00 2001 From: tstephen-nhs <231503406+tstephen-nhs@users.noreply.github.com> Date: Mon, 30 Mar 2026 11:09:19 +0000 Subject: [PATCH 03/12] feat: permit ApiGateway to skip domain record --- .../src/constructs/RestApiGateway.ts | 76 ++++++++++++------- .../tests/constructs/RestApiGateway.test.ts | 41 +++++++++- 2 files changed, 86 insertions(+), 31 deletions(-) diff --git a/packages/cdkConstructs/src/constructs/RestApiGateway.ts b/packages/cdkConstructs/src/constructs/RestApiGateway.ts index ac74b4e7..5a1020ea 100644 --- a/packages/cdkConstructs/src/constructs/RestApiGateway.ts +++ b/packages/cdkConstructs/src/constructs/RestApiGateway.ts @@ -28,6 +28,7 @@ import { ARecord, AaaaRecord, HostedZone, + IHostedZone, RecordTarget } from "aws-cdk-lib/aws-route53" import {ApiGateway as ApiGatewayTarget} from "aws-cdk-lib/aws-route53-targets" @@ -49,6 +50,10 @@ export interface RestApiGatewayProps { readonly csocApiGatewayDestination: string /** Managed policies attached to the API Gateway execution role. */ readonly executionPolicies: Array + /** + * When true (default), creates the custom service domain, ACM certificate, and Route53 records. + */ + readonly enableServiceDomain?: boolean } /** Creates a regional REST API with standard logging, DNS, and optional mTLS/CSOC integration. */ @@ -70,6 +75,7 @@ export class RestApiGateway extends Construct { * forwardCsocLogs: true, * csocApiGatewayDestination: "arn:aws:logs:eu-west-2:123456789012:destination:csoc", * executionPolicies: [myLambdaInvokePolicy] + * enableServiceDomain: true * }) * api.api.root.addResource("patients") * ``` @@ -77,6 +83,8 @@ export class RestApiGateway extends Construct { public constructor(scope: Construct, id: string, props: RestApiGatewayProps) { super(scope, id) + const enableServiceDomain = (props.enableServiceDomain ?? true) + if (props.forwardCsocLogs && props.csocApiGatewayDestination === "") { throw new Error("csocApiGatewayDestination must be provided when forwardCsocLogs is true") } @@ -100,12 +108,17 @@ export class RestApiGateway extends Construct { const trustStoreBucketKmsKey = Key.fromKeyArn( this, "TrustStoreBucketKmsKey", ACCOUNT_RESOURCES.TrustStoreBucketKMSKey) - const epsDomainName: string = ACCOUNT_RESOURCES.EpsDomainName - const hostedZone = HostedZone.fromHostedZoneAttributes(this, "HostedZone", { - hostedZoneId: ACCOUNT_RESOURCES.EpsZoneId, - zoneName: epsDomainName - }) - const serviceDomainName = `${props.stackName}.${epsDomainName}` + let hostedZone: IHostedZone | undefined + let serviceDomainName: string | undefined + + if (enableServiceDomain) { + const epsDomainName: string = ACCOUNT_RESOURCES.EpsDomainName + hostedZone = HostedZone.fromHostedZoneAttributes(this, "HostedZone", { + hostedZoneId: ACCOUNT_RESOURCES.EpsZoneId, + zoneName: epsDomainName + }) + serviceDomainName = `${props.stackName}.${epsDomainName}` + } // Resources const logGroup = new LogGroup(this, "ApiGatewayAccessLogGroup", { @@ -131,14 +144,16 @@ export class RestApiGateway extends Construct { }) } - const certificate = new Certificate(this, "Certificate", { - domainName: serviceDomainName, - validation: CertificateValidation.fromDns(hostedZone) - }) + const certificate = enableServiceDomain && hostedZone && serviceDomainName + ? new Certificate(this, "Certificate", { + domainName: serviceDomainName, + validation: CertificateValidation.fromDns(hostedZone) + }) + : undefined let mtlsConfig: MTLSConfig | undefined - if (props.mutualTlsTrustStoreKey) { + if (enableServiceDomain && props.mutualTlsTrustStoreKey) { const trustStoreKeyPrefix = `cpt-api/${props.stackName}-truststore` const logGroup = new LogGroup(this, "LambdaLogGroup", { encryptionKey: cloudWatchLogsKmsKey, @@ -220,13 +235,16 @@ export class RestApiGateway extends Construct { const apiGateway = new RestApi(this, "ApiGateway", { restApiName: `${props.stackName}-apigw`, - domainName: { - domainName: serviceDomainName, - certificate: certificate, - securityPolicy: SecurityPolicy.TLS_1_2, - endpointType: EndpointType.REGIONAL, - mtls: mtlsConfig - }, + ...(enableServiceDomain + ? { + domainName: { + domainName: serviceDomainName!, + certificate: certificate!, + securityPolicy: SecurityPolicy.TLS_1_2, + endpointType: EndpointType.REGIONAL, + mtls: mtlsConfig + } + } : {}), disableExecuteApiEndpoint: mtlsConfig ? true : false, // NOSONAR endpointConfiguration: { types: [EndpointType.REGIONAL] @@ -245,17 +263,19 @@ export class RestApiGateway extends Construct { managedPolicies: props.executionPolicies }).withoutPolicyUpdates() - new ARecord(this, "ARecord", { - recordName: props.stackName, - target: RecordTarget.fromAlias(new ApiGatewayTarget(apiGateway)), - zone: hostedZone - }) + if (enableServiceDomain && hostedZone) { + new ARecord(this, "ARecord", { + recordName: props.stackName, + target: RecordTarget.fromAlias(new ApiGatewayTarget(apiGateway)), + zone: hostedZone + }) - new AaaaRecord(this, "AaaaRecord", { - recordName: props.stackName, - target: RecordTarget.fromAlias(new ApiGatewayTarget(apiGateway)), - zone: hostedZone - }) + new AaaaRecord(this, "AaaaRecord", { + recordName: props.stackName, + target: RecordTarget.fromAlias(new ApiGatewayTarget(apiGateway)), + zone: hostedZone + }) + } const cfnStage = apiGateway.deploymentStage.node.defaultChild as CfnStage addSuppressions([cfnStage], ["API_GW_CACHE_ENABLED_AND_ENCRYPTED"]) diff --git a/packages/cdkConstructs/tests/constructs/RestApiGateway.test.ts b/packages/cdkConstructs/tests/constructs/RestApiGateway.test.ts index 0853fddd..9cf6034d 100644 --- a/packages/cdkConstructs/tests/constructs/RestApiGateway.test.ts +++ b/packages/cdkConstructs/tests/constructs/RestApiGateway.test.ts @@ -35,7 +35,8 @@ describe("RestApiGateway without mTLS", () => { mutualTlsTrustStoreKey: undefined, forwardCsocLogs: false, csocApiGatewayDestination: "", - executionPolicies: [testPolicy] + executionPolicies: [testPolicy], + enableServiceDomain: true }) // Add a dummy method to satisfy API Gateway validation @@ -192,7 +193,8 @@ describe("RestApiGateway with CSOC logs", () => { mutualTlsTrustStoreKey: undefined, forwardCsocLogs: true, csocApiGatewayDestination: "arn:aws:logs:eu-west-2:123456789012:destination:csoc-destination", - executionPolicies: [testPolicy] + executionPolicies: [testPolicy], + enableServiceDomain: true }) // Add a dummy method to satisfy API Gateway validation @@ -240,7 +242,8 @@ describe("RestApiGateway with mTLS", () => { mutualTlsTrustStoreKey: "truststore.pem", forwardCsocLogs: false, csocApiGatewayDestination: "", - executionPolicies: [testPolicy] + executionPolicies: [testPolicy], + enableServiceDomain: true }) // Add a dummy method to satisfy API Gateway validation @@ -352,3 +355,35 @@ describe("RestApiGateway validation errors", () => { })).toThrow("csocApiGatewayDestination must be provided when forwardCsocLogs is true") }) }) + +describe("RestApiGateway enableServiceDomain default behaviour", () => { + test("creates custom domain resources when enableServiceDomain is omitted", () => { + const app = new App() + const stack = new Stack(app, "EnableServiceDomainDefaultStack") + const testPolicy = new ManagedPolicy(stack, "TestPolicy", { + description: "test execution policy", + statements: [ + new PolicyStatement({ + actions: ["lambda:InvokeFunction"], + resources: ["arn:aws:lambda:eu-west-2:123456789012:function:test-function"] + }) + ] + }) + + const apiGateway = new RestApiGateway(stack, "TestApiGateway", { + stackName: "test-stack", + logRetentionInDays: 30, + mutualTlsTrustStoreKey: undefined, + forwardCsocLogs: false, + csocApiGatewayDestination: "", + executionPolicies: [testPolicy] + }) + + apiGateway.api.root.addMethod("GET") + + const template = Template.fromStack(stack) + template.resourceCountIs("AWS::CertificateManager::Certificate", 1) + template.resourceCountIs("AWS::ApiGateway::DomainName", 1) + template.resourceCountIs("AWS::Route53::RecordSet", 2) + }) +}) From dcc316971d8d64d3c07f44921d64495e1fe9e855 Mon Sep 17 00:00:00 2001 From: tstephen-nhs <231503406+tstephen-nhs@users.noreply.github.com> Date: Mon, 30 Mar 2026 12:01:39 +0000 Subject: [PATCH 04/12] fix: include 408 (timeout) in statemachine responses --- .../src/constructs/RestApiGateway/StateMachineEndpoint.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/cdkConstructs/src/constructs/RestApiGateway/StateMachineEndpoint.ts b/packages/cdkConstructs/src/constructs/RestApiGateway/StateMachineEndpoint.ts index 7adf3c57..daa4e908 100644 --- a/packages/cdkConstructs/src/constructs/RestApiGateway/StateMachineEndpoint.ts +++ b/packages/cdkConstructs/src/constructs/RestApiGateway/StateMachineEndpoint.ts @@ -65,6 +65,7 @@ export class StateMachineEndpoint extends Construct { methodResponses: [ {statusCode: "200"}, {statusCode: "400"}, + {statusCode: "408"}, {statusCode: "500"} ] }) From 79eccacf3f7556f00d6a82eeb5ed22439791cfb4 Mon Sep 17 00:00:00 2001 From: tstephen-nhs <231503406+tstephen-nhs@users.noreply.github.com> Date: Mon, 30 Mar 2026 15:06:32 +0100 Subject: [PATCH 05/12] docs: fix example Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- packages/cdkConstructs/src/constructs/RestApiGateway.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cdkConstructs/src/constructs/RestApiGateway.ts b/packages/cdkConstructs/src/constructs/RestApiGateway.ts index 5a1020ea..6dff6e0e 100644 --- a/packages/cdkConstructs/src/constructs/RestApiGateway.ts +++ b/packages/cdkConstructs/src/constructs/RestApiGateway.ts @@ -74,7 +74,7 @@ export class RestApiGateway extends Construct { * mutualTlsTrustStoreKey: "truststore.pem", * forwardCsocLogs: true, * csocApiGatewayDestination: "arn:aws:logs:eu-west-2:123456789012:destination:csoc", - * executionPolicies: [myLambdaInvokePolicy] + * executionPolicies: [myLambdaInvokePolicy], * enableServiceDomain: true * }) * api.api.root.addResource("patients") From a21bdb78aa1ade23b482fe22607503f83bbc890e Mon Sep 17 00:00:00 2001 From: tstephen-nhs <231503406+tstephen-nhs@users.noreply.github.com> Date: Mon, 30 Mar 2026 14:14:38 +0000 Subject: [PATCH 06/12] chore: flag if mtls set but domain record not enabled --- .../src/constructs/RestApiGateway.ts | 6 +- .../tests/constructs/RestApiGateway.test.ts | 57 +++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/packages/cdkConstructs/src/constructs/RestApiGateway.ts b/packages/cdkConstructs/src/constructs/RestApiGateway.ts index 6dff6e0e..16918400 100644 --- a/packages/cdkConstructs/src/constructs/RestApiGateway.ts +++ b/packages/cdkConstructs/src/constructs/RestApiGateway.ts @@ -42,7 +42,7 @@ export interface RestApiGatewayProps { readonly stackName: string /** Shared retention period for API and deployment-related log groups. */ readonly logRetentionInDays: number - /** Truststore object key to enable mTLS; leave undefined to disable mTLS. */ + /** Truststore object key to enable mTLS; leave undefined to disable mTLS or when enableServiceDomain is false. */ readonly mutualTlsTrustStoreKey: string | undefined /** Enables creation of a second subscription filter to forward logs to CSOC. */ readonly forwardCsocLogs: boolean @@ -89,6 +89,10 @@ export class RestApiGateway extends Construct { throw new Error("csocApiGatewayDestination must be provided when forwardCsocLogs is true") } + if (!enableServiceDomain && props.mutualTlsTrustStoreKey) { + throw new Error("mutualTlsTrustStoreKey should not be provided when enableServiceDomain is false") + } + // Imports const cloudWatchLogsKmsKey = Key.fromKeyArn( this, "cloudWatchLogsKmsKey", ACCOUNT_RESOURCES.CloudwatchLogsKmsKeyArn) diff --git a/packages/cdkConstructs/tests/constructs/RestApiGateway.test.ts b/packages/cdkConstructs/tests/constructs/RestApiGateway.test.ts index 9cf6034d..3f4155c0 100644 --- a/packages/cdkConstructs/tests/constructs/RestApiGateway.test.ts +++ b/packages/cdkConstructs/tests/constructs/RestApiGateway.test.ts @@ -354,6 +354,30 @@ describe("RestApiGateway validation errors", () => { executionPolicies: [testPolicy] })).toThrow("csocApiGatewayDestination must be provided when forwardCsocLogs is true") }) + + test("throws when enableServiceDomain is false and mutualTlsTrustStoreKey is provided", () => { + const app = new App() + const stack = new Stack(app, "ValidationStack2") + const testPolicy = new ManagedPolicy(stack, "TestPolicy", { + description: "test execution policy", + statements: [ + new PolicyStatement({ + actions: ["lambda:InvokeFunction"], + resources: ["arn:aws:lambda:eu-west-2:123456789012:function:test-function"] + }) + ] + }) + + expect(() => new RestApiGateway(stack, "TestApiGateway", { + stackName: "test-stack", + logRetentionInDays: 30, + mutualTlsTrustStoreKey: "truststore.pem", + forwardCsocLogs: false, + csocApiGatewayDestination: "", + executionPolicies: [testPolicy], + enableServiceDomain: false + })).toThrow("mutualTlsTrustStoreKey should not be provided when enableServiceDomain is false") + }) }) describe("RestApiGateway enableServiceDomain default behaviour", () => { @@ -387,3 +411,36 @@ describe("RestApiGateway enableServiceDomain default behaviour", () => { template.resourceCountIs("AWS::Route53::RecordSet", 2) }) }) + +describe("RestApiGateway with enableServiceDomain false", () => { + test("does not create custom domain resources when enableServiceDomain is false", () => { + const app = new App() + const stack = new Stack(app, "DisableServiceDomainStack") + const testPolicy = new ManagedPolicy(stack, "TestPolicy", { + description: "test execution policy", + statements: [ + new PolicyStatement({ + actions: ["lambda:InvokeFunction"], + resources: ["arn:aws:lambda:eu-west-2:123456789012:function:test-function"] + }) + ] + }) + + const apiGateway = new RestApiGateway(stack, "TestApiGateway", { + stackName: "test-stack", + logRetentionInDays: 30, + mutualTlsTrustStoreKey: undefined, + forwardCsocLogs: false, + csocApiGatewayDestination: "", + executionPolicies: [testPolicy], + enableServiceDomain: false + }) + + apiGateway.api.root.addMethod("GET") + + const template = Template.fromStack(stack) + template.resourceCountIs("AWS::CertificateManager::Certificate", 0) + template.resourceCountIs("AWS::ApiGateway::DomainName", 0) + template.resourceCountIs("AWS::Route53::RecordSet", 0) + }) +}) From e44b5bb2307a70630be2bb06a20c1e7f6245db60 Mon Sep 17 00:00:00 2001 From: tstephen-nhs <231503406+tstephen-nhs@users.noreply.github.com> Date: Mon, 30 Mar 2026 14:27:23 +0000 Subject: [PATCH 07/12] test: AAAA domain record creation --- .../tests/constructs/RestApiGateway.test.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/cdkConstructs/tests/constructs/RestApiGateway.test.ts b/packages/cdkConstructs/tests/constructs/RestApiGateway.test.ts index 3f4155c0..02b1538a 100644 --- a/packages/cdkConstructs/tests/constructs/RestApiGateway.test.ts +++ b/packages/cdkConstructs/tests/constructs/RestApiGateway.test.ts @@ -156,6 +156,19 @@ describe("RestApiGateway without mTLS", () => { }) }) + test("creates Route53 AAAA record", () => { + template.hasResourceProperties("AWS::Route53::RecordSet", { + Name: { + "Fn::Join": ["", [ + "test-stack.", + {"Fn::ImportValue": "eps-route53-resources:EPS-domain"}, + "." + ]] + }, + Type: "AAAA" + }) + }) + test("sets guard metadata on stage", () => { const stages = template.findResources("AWS::ApiGateway::Stage") const stageKeys = Object.keys(stages) From ba1e7d49af37624d0b44b79d01b3bd45e214ca1a Mon Sep 17 00:00:00 2001 From: tstephen-nhs <231503406+tstephen-nhs@users.noreply.github.com> Date: Mon, 30 Mar 2026 14:39:10 +0000 Subject: [PATCH 08/12] fix: 408 should not be returned --- .../src/constructs/RestApiGateway/StateMachineEndpoint.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/cdkConstructs/src/constructs/RestApiGateway/StateMachineEndpoint.ts b/packages/cdkConstructs/src/constructs/RestApiGateway/StateMachineEndpoint.ts index daa4e908..7adf3c57 100644 --- a/packages/cdkConstructs/src/constructs/RestApiGateway/StateMachineEndpoint.ts +++ b/packages/cdkConstructs/src/constructs/RestApiGateway/StateMachineEndpoint.ts @@ -65,7 +65,6 @@ export class StateMachineEndpoint extends Construct { methodResponses: [ {statusCode: "200"}, {statusCode: "400"}, - {statusCode: "408"}, {statusCode: "500"} ] }) From f1ad1f6ba19c17651f5b0de70d84085eda909e3d Mon Sep 17 00:00:00 2001 From: tstephen-nhs <231503406+tstephen-nhs@users.noreply.github.com> Date: Mon, 30 Mar 2026 16:10:37 +0000 Subject: [PATCH 09/12] chore: export further account resources --- packages/cdkConstructs/src/constants.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/cdkConstructs/src/constants.ts b/packages/cdkConstructs/src/constants.ts index 5cfef0a4..43ffa2e4 100644 --- a/packages/cdkConstructs/src/constants.ts +++ b/packages/cdkConstructs/src/constants.ts @@ -6,6 +6,13 @@ export const ACCOUNT_RESOURCES = { CloudwatchLogsKmsKeyArn: Fn.importValue("account-resources:CloudwatchLogsKmsKeyArn"), EpsDomainName: Fn.importValue("eps-route53-resources:EPS-domain"), EpsZoneId: Fn.importValue("eps-route53-resources:EPS-ZoneID"), + LambdaAccessSecretsPolicy: Fn.importValue("account-resources:LambdaAccessSecretsPolicy"), + LambdaDecryptSecretsKMSPolicy: Fn.importValue("account-resources:LambdaDecryptSecretsKMSPolicy"), + SpinePrivateKeyARN: Fn.importValue("account-resources:SpinePrivateKey"), + SpinePublicCertificateARN: Fn.importValue("account-resources:SpinePublicCertificate"), + SpineASIDARN: Fn.importValue("account-resources:SpineASID"), + SpinePartyKeyARN: Fn.importValue("account-resources:SpinePartyKey"), + SpineCAChainARN: Fn.importValue("account-resources:SpineCAChain"), TrustStoreBucket: Fn.importValue("account-resources:TrustStoreBucket"), TrustStoreBucketKMSKey: Fn.importValue("account-resources:TrustStoreBucketKMSKey"), TrustStoreDeploymentBucket: Fn.importValue("account-resources:TrustStoreDeploymentBucket") From 50be43a64b3044578074a7b752b910cb15b96c6d Mon Sep 17 00:00:00 2001 From: tstephen-nhs <231503406+tstephen-nhs@users.noreply.github.com> Date: Mon, 30 Mar 2026 16:29:12 +0000 Subject: [PATCH 10/12] chore: optimise params of getConfigFromEnvVar --- packages/cdkConstructs/src/config/index.ts | 16 ++++++++-------- .../cdkConstructs/tests/config/index.test.ts | 12 ++++++------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/cdkConstructs/src/config/index.ts b/packages/cdkConstructs/src/config/index.ts index 483f4403..3ead3e0d 100644 --- a/packages/cdkConstructs/src/config/index.ts +++ b/packages/cdkConstructs/src/config/index.ts @@ -4,8 +4,8 @@ import {StandardStackProps} from "../apps/createApp" export function getConfigFromEnvVar( varName: string, - prefix: string = "CDK_CONFIG_", - defaultValue: string | undefined = undefined + defaultValue?: string, + prefix: string = "CDK_CONFIG_" ): string { const value = process.env[prefix + varName] if (!value) { @@ -19,19 +19,19 @@ export function getConfigFromEnvVar( export function getBooleanConfigFromEnvVar( varName: string, - prefix: string = "CDK_CONFIG_", - defaultValue: string | undefined = undefined + defaultValue?: string, + prefix: string = "CDK_CONFIG_" ): boolean { - const value = getConfigFromEnvVar(varName, prefix, defaultValue) + const value = getConfigFromEnvVar(varName, defaultValue, prefix) return value.toLowerCase().trim() === "true" } export function getNumberConfigFromEnvVar( varName: string, - prefix: string = "CDK_CONFIG_", - defaultValue: string | undefined = undefined + defaultValue?: string, + prefix: string = "CDK_CONFIG_" ): number { - const value = getConfigFromEnvVar(varName, prefix, defaultValue) + const value = getConfigFromEnvVar(varName, defaultValue, prefix) return Number(value) } diff --git a/packages/cdkConstructs/tests/config/index.test.ts b/packages/cdkConstructs/tests/config/index.test.ts index d2bbbdb2..223cf935 100644 --- a/packages/cdkConstructs/tests/config/index.test.ts +++ b/packages/cdkConstructs/tests/config/index.test.ts @@ -96,7 +96,7 @@ describe("config helpers", () => { test("getConfigFromEnvVar returns the default value when env var is not set", () => { delete process.env.CDK_CONFIG_MISSING - expect(getConfigFromEnvVar("MISSING", "CDK_CONFIG_", "fallback")).toBe("fallback") + expect(getConfigFromEnvVar("MISSING", "fallback")).toBe("fallback") }) test("getConfigFromEnvVar throws when value is missing", () => { @@ -109,7 +109,7 @@ describe("config helpers", () => { test("getConfigFromEnvVar supports alternate prefixes", () => { process.env.APP_CUSTOM_VALUE = "alt" - expect(getConfigFromEnvVar("CUSTOM_VALUE", "APP_")).toBe("alt") + expect(getConfigFromEnvVar("CUSTOM_VALUE", undefined, "APP_")).toBe("alt") }) test("getBooleanConfigFromEnvVar maps string booleans", () => { @@ -123,8 +123,8 @@ describe("config helpers", () => { test("getBooleanConfigFromEnvVar uses default value when env var is not set", () => { delete process.env.CDK_CONFIG_BOOL_MISSING - expect(getBooleanConfigFromEnvVar("BOOL_MISSING", "CDK_CONFIG_", "true")).toBe(true) - expect(getBooleanConfigFromEnvVar("BOOL_MISSING", "CDK_CONFIG_", "false")).toBe(false) + expect(getBooleanConfigFromEnvVar("BOOL_MISSING", "true")).toBe(true) + expect(getBooleanConfigFromEnvVar("BOOL_MISSING", "false")).toBe(false) }) test("getNumberConfigFromEnvVar parses numeric strings", () => { @@ -136,13 +136,13 @@ describe("config helpers", () => { test("getNumberConfigFromEnvVar uses default value when env var is not set", () => { delete process.env.CDK_CONFIG_NUM_MISSING - expect(getNumberConfigFromEnvVar("NUM_MISSING", "CDK_CONFIG_", "99")).toBe(99) + expect(getNumberConfigFromEnvVar("NUM_MISSING", "99")).toBe(99) }) test("getConfigFromEnvVar ignores default value when env var is set", () => { process.env.CDK_CONFIG_STACK_NAME = "primary" - expect(getConfigFromEnvVar("STACK_NAME", "CDK_CONFIG_", "ignored")).toBe("primary") + expect(getConfigFromEnvVar("STACK_NAME", "ignored")).toBe("primary") }) test("getTrustStoreVersion returns the version ID from S3", async () => { From 07bf22ea039537cef8af325a102033b3b8cd248d Mon Sep 17 00:00:00 2001 From: tstephen-nhs <231503406+tstephen-nhs@users.noreply.github.com> Date: Wed, 1 Apr 2026 10:46:22 +0000 Subject: [PATCH 11/12] Revert "chore: optimise params of getConfigFromEnvVar" This reverts commit 50be43a64b3044578074a7b752b910cb15b96c6d. --- packages/cdkConstructs/src/config/index.ts | 16 ++++++++-------- .../cdkConstructs/tests/config/index.test.ts | 12 ++++++------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/cdkConstructs/src/config/index.ts b/packages/cdkConstructs/src/config/index.ts index 3ead3e0d..483f4403 100644 --- a/packages/cdkConstructs/src/config/index.ts +++ b/packages/cdkConstructs/src/config/index.ts @@ -4,8 +4,8 @@ import {StandardStackProps} from "../apps/createApp" export function getConfigFromEnvVar( varName: string, - defaultValue?: string, - prefix: string = "CDK_CONFIG_" + prefix: string = "CDK_CONFIG_", + defaultValue: string | undefined = undefined ): string { const value = process.env[prefix + varName] if (!value) { @@ -19,19 +19,19 @@ export function getConfigFromEnvVar( export function getBooleanConfigFromEnvVar( varName: string, - defaultValue?: string, - prefix: string = "CDK_CONFIG_" + prefix: string = "CDK_CONFIG_", + defaultValue: string | undefined = undefined ): boolean { - const value = getConfigFromEnvVar(varName, defaultValue, prefix) + const value = getConfigFromEnvVar(varName, prefix, defaultValue) return value.toLowerCase().trim() === "true" } export function getNumberConfigFromEnvVar( varName: string, - defaultValue?: string, - prefix: string = "CDK_CONFIG_" + prefix: string = "CDK_CONFIG_", + defaultValue: string | undefined = undefined ): number { - const value = getConfigFromEnvVar(varName, defaultValue, prefix) + const value = getConfigFromEnvVar(varName, prefix, defaultValue) return Number(value) } diff --git a/packages/cdkConstructs/tests/config/index.test.ts b/packages/cdkConstructs/tests/config/index.test.ts index 223cf935..d2bbbdb2 100644 --- a/packages/cdkConstructs/tests/config/index.test.ts +++ b/packages/cdkConstructs/tests/config/index.test.ts @@ -96,7 +96,7 @@ describe("config helpers", () => { test("getConfigFromEnvVar returns the default value when env var is not set", () => { delete process.env.CDK_CONFIG_MISSING - expect(getConfigFromEnvVar("MISSING", "fallback")).toBe("fallback") + expect(getConfigFromEnvVar("MISSING", "CDK_CONFIG_", "fallback")).toBe("fallback") }) test("getConfigFromEnvVar throws when value is missing", () => { @@ -109,7 +109,7 @@ describe("config helpers", () => { test("getConfigFromEnvVar supports alternate prefixes", () => { process.env.APP_CUSTOM_VALUE = "alt" - expect(getConfigFromEnvVar("CUSTOM_VALUE", undefined, "APP_")).toBe("alt") + expect(getConfigFromEnvVar("CUSTOM_VALUE", "APP_")).toBe("alt") }) test("getBooleanConfigFromEnvVar maps string booleans", () => { @@ -123,8 +123,8 @@ describe("config helpers", () => { test("getBooleanConfigFromEnvVar uses default value when env var is not set", () => { delete process.env.CDK_CONFIG_BOOL_MISSING - expect(getBooleanConfigFromEnvVar("BOOL_MISSING", "true")).toBe(true) - expect(getBooleanConfigFromEnvVar("BOOL_MISSING", "false")).toBe(false) + expect(getBooleanConfigFromEnvVar("BOOL_MISSING", "CDK_CONFIG_", "true")).toBe(true) + expect(getBooleanConfigFromEnvVar("BOOL_MISSING", "CDK_CONFIG_", "false")).toBe(false) }) test("getNumberConfigFromEnvVar parses numeric strings", () => { @@ -136,13 +136,13 @@ describe("config helpers", () => { test("getNumberConfigFromEnvVar uses default value when env var is not set", () => { delete process.env.CDK_CONFIG_NUM_MISSING - expect(getNumberConfigFromEnvVar("NUM_MISSING", "99")).toBe(99) + expect(getNumberConfigFromEnvVar("NUM_MISSING", "CDK_CONFIG_", "99")).toBe(99) }) test("getConfigFromEnvVar ignores default value when env var is set", () => { process.env.CDK_CONFIG_STACK_NAME = "primary" - expect(getConfigFromEnvVar("STACK_NAME", "ignored")).toBe("primary") + expect(getConfigFromEnvVar("STACK_NAME", "CDK_CONFIG_", "ignored")).toBe("primary") }) test("getTrustStoreVersion returns the version ID from S3", async () => { From bdf808f96964718c34c700ed711ef5f4e5b7e806 Mon Sep 17 00:00:00 2001 From: tstephen-nhs <231503406+tstephen-nhs@users.noreply.github.com> Date: Wed, 1 Apr 2026 11:08:32 +0000 Subject: [PATCH 12/12] refactor: extract env var prefix constant; export constants --- packages/cdkConstructs/src/config/index.ts | 7 +-- packages/cdkConstructs/src/constants.ts | 3 ++ packages/cdkConstructs/src/index.ts | 3 +- .../tests/apps/createApp.test.ts | 49 ++++++++++--------- .../cdkConstructs/tests/config/index.test.ts | 31 ++++++------ 5 files changed, 50 insertions(+), 43 deletions(-) diff --git a/packages/cdkConstructs/src/config/index.ts b/packages/cdkConstructs/src/config/index.ts index 483f4403..8a367af9 100644 --- a/packages/cdkConstructs/src/config/index.ts +++ b/packages/cdkConstructs/src/config/index.ts @@ -1,10 +1,11 @@ import {CloudFormationClient, DescribeStacksCommand} from "@aws-sdk/client-cloudformation" import {S3Client, HeadObjectCommand} from "@aws-sdk/client-s3" import {StandardStackProps} from "../apps/createApp" +import {CDK_ENV_PREFIX} from "../constants" export function getConfigFromEnvVar( varName: string, - prefix: string = "CDK_CONFIG_", + prefix: string = CDK_ENV_PREFIX, defaultValue: string | undefined = undefined ): string { const value = process.env[prefix + varName] @@ -19,7 +20,7 @@ export function getConfigFromEnvVar( export function getBooleanConfigFromEnvVar( varName: string, - prefix: string = "CDK_CONFIG_", + prefix: string = CDK_ENV_PREFIX, defaultValue: string | undefined = undefined ): boolean { const value = getConfigFromEnvVar(varName, prefix, defaultValue) @@ -28,7 +29,7 @@ export function getBooleanConfigFromEnvVar( export function getNumberConfigFromEnvVar( varName: string, - prefix: string = "CDK_CONFIG_", + prefix: string = CDK_ENV_PREFIX, defaultValue: string | undefined = undefined ): number { const value = getConfigFromEnvVar(varName, prefix, defaultValue) diff --git a/packages/cdkConstructs/src/constants.ts b/packages/cdkConstructs/src/constants.ts index 43ffa2e4..03edbd6c 100644 --- a/packages/cdkConstructs/src/constants.ts +++ b/packages/cdkConstructs/src/constants.ts @@ -1,5 +1,8 @@ import {Fn} from "aws-cdk-lib" +/** Default prefix used for CDK config environment variables. */ +export const CDK_ENV_PREFIX = "CDK_CONFIG_" + /** Imported cross-stack account resource values used by constructs in this package. */ export const ACCOUNT_RESOURCES = { CloudwatchEncryptionKMSPolicyArn: Fn.importValue("account-resources:CloudwatchEncryptionKMSPolicyArn"), diff --git a/packages/cdkConstructs/src/index.ts b/packages/cdkConstructs/src/index.ts index c684622b..39dc8095 100644 --- a/packages/cdkConstructs/src/index.ts +++ b/packages/cdkConstructs/src/index.ts @@ -13,4 +13,5 @@ export * from "./config/index.js" export * from "./utils/helpers.js" export * from "./stacks/deleteUnusedStacks.js" export * from "./nag/pack/epsNagPack.js" -export * from "./changesets/checkDestructiveChanges" +export * from "./changesets/checkDestructiveChanges.js" +export * from "./constants.js" diff --git a/packages/cdkConstructs/tests/apps/createApp.test.ts b/packages/cdkConstructs/tests/apps/createApp.test.ts index 2237b772..49641396 100644 --- a/packages/cdkConstructs/tests/apps/createApp.test.ts +++ b/packages/cdkConstructs/tests/apps/createApp.test.ts @@ -24,6 +24,7 @@ import { } from "vitest" import {createApp, type CreateAppParams} from "../../src/apps/createApp" import {AwsSolutionsChecks} from "cdk-nag" +import {CDK_ENV_PREFIX} from "../../src/constants" describe("createApp", () => { const originalEnv = process.env @@ -51,10 +52,10 @@ describe("createApp", () => { describe("when all environment variables are set", () => { beforeEach(() => { - process.env.CDK_CONFIG_versionNumber = "1.2.3" - process.env.CDK_CONFIG_commitId = "abc123def456" - process.env.CDK_CONFIG_isPullRequest = "false" - process.env.CDK_CONFIG_environment = "test-environment" + process.env[`${CDK_ENV_PREFIX}versionNumber`] = "1.2.3" + process.env[`${CDK_ENV_PREFIX}commitId`] = "abc123def456" + process.env[`${CDK_ENV_PREFIX}isPullRequest`] = "false" + process.env[`${CDK_ENV_PREFIX}environment`] = "test-environment" }) test("creates an App with correct configuration", () => { @@ -124,10 +125,10 @@ describe("createApp", () => { describe("when isPullRequest is true", () => { beforeEach(() => { - process.env.CDK_CONFIG_versionNumber = "0.0.1-pr" - process.env.CDK_CONFIG_commitId = "pr123" - process.env.CDK_CONFIG_isPullRequest = "true" - process.env.CDK_CONFIG_environment = "test-environment" + process.env[`${CDK_ENV_PREFIX}versionNumber`] = "0.0.1-pr" + process.env[`${CDK_ENV_PREFIX}commitId`] = "pr123" + process.env[`${CDK_ENV_PREFIX}isPullRequest`] = "true" + process.env[`${CDK_ENV_PREFIX}environment`] = "test-environment" }) test("correctly modifies props", () => { @@ -159,41 +160,41 @@ describe("createApp", () => { describe("when environment variables are missing", () => { test("throws error when versionNumber is not set", () => { - process.env.CDK_CONFIG_commitId = "abc123" - process.env.CDK_CONFIG_isPullRequest = "false" - process.env.CDK_CONFIG_environment = "test-environment" + process.env[`${CDK_ENV_PREFIX}commitId`] = "abc123" + process.env[`${CDK_ENV_PREFIX}isPullRequest`] = "false" + process.env[`${CDK_ENV_PREFIX}environment`] = "test-environment" expect(() => { createApp(buildParams()) - }).toThrow("Environment variable CDK_CONFIG_versionNumber is not set") + }).toThrow(`Environment variable ${CDK_ENV_PREFIX}versionNumber is not set`) }) test("throws error when commitId is not set", () => { - process.env.CDK_CONFIG_versionNumber = "1.0.0" - process.env.CDK_CONFIG_isPullRequest = "false" - process.env.CDK_CONFIG_environment = "test-environment" + process.env[`${CDK_ENV_PREFIX}versionNumber`] = "1.0.0" + process.env[`${CDK_ENV_PREFIX}isPullRequest`] = "false" + process.env[`${CDK_ENV_PREFIX}environment`] = "test-environment" expect(() => { createApp(buildParams()) - }).toThrow("Environment variable CDK_CONFIG_commitId is not set") + }).toThrow(`Environment variable ${CDK_ENV_PREFIX}commitId is not set`) }) test("throws error when isPullRequest is not set", () => { - process.env.CDK_CONFIG_versionNumber = "1.0.0" - process.env.CDK_CONFIG_commitId = "abc123" - process.env.CDK_CONFIG_environment = "test-environment" + process.env[`${CDK_ENV_PREFIX}versionNumber`] = "1.0.0" + process.env[`${CDK_ENV_PREFIX}commitId`] = "abc123" + process.env[`${CDK_ENV_PREFIX}environment`] = "test-environment" expect(() => { createApp(buildParams()) - }).toThrow("Environment variable CDK_CONFIG_isPullRequest is not set") + }).toThrow(`Environment variable ${CDK_ENV_PREFIX}isPullRequest is not set`) }) test("throws error when environment is not set", () => { - process.env.CDK_CONFIG_versionNumber = "1.0.0" - process.env.CDK_CONFIG_commitId = "abc123" - process.env.CDK_CONFIG_isPullRequest = "false" + process.env[`${CDK_ENV_PREFIX}versionNumber`] = "1.0.0" + process.env[`${CDK_ENV_PREFIX}commitId`] = "abc123" + process.env[`${CDK_ENV_PREFIX}isPullRequest`] = "false" expect(() => { createApp(buildParams()) - }).toThrow("Environment variable CDK_CONFIG_environment is not set") + }).toThrow(`Environment variable ${CDK_ENV_PREFIX}environment is not set`) }) }) diff --git a/packages/cdkConstructs/tests/config/index.test.ts b/packages/cdkConstructs/tests/config/index.test.ts index d2bbbdb2..6c1f690d 100644 --- a/packages/cdkConstructs/tests/config/index.test.ts +++ b/packages/cdkConstructs/tests/config/index.test.ts @@ -12,6 +12,7 @@ import { getNumberConfigFromEnvVar, getTrustStoreVersion } from "../../src/config/index" +import {CDK_ENV_PREFIX} from "../../src/constants" const mockCloudFormationSend = vi.fn() const mockS3Send = vi.fn() @@ -88,22 +89,22 @@ describe("config helpers", () => { }) test("getConfigFromEnvVar returns the configured value", () => { - process.env.CDK_CONFIG_STACK_NAME = "primary" + process.env[`${CDK_ENV_PREFIX}STACK_NAME`] = "primary" expect(getConfigFromEnvVar("STACK_NAME")).toBe("primary") }) test("getConfigFromEnvVar returns the default value when env var is not set", () => { - delete process.env.CDK_CONFIG_MISSING + delete process.env[`${CDK_ENV_PREFIX}MISSING`] - expect(getConfigFromEnvVar("MISSING", "CDK_CONFIG_", "fallback")).toBe("fallback") + expect(getConfigFromEnvVar("MISSING", CDK_ENV_PREFIX, "fallback")).toBe("fallback") }) test("getConfigFromEnvVar throws when value is missing", () => { - delete process.env.CDK_CONFIG_MISSING + delete process.env[`${CDK_ENV_PREFIX}MISSING`] expect(() => getConfigFromEnvVar("MISSING")) - .toThrow("Environment variable CDK_CONFIG_MISSING is not set") + .toThrow(`Environment variable ${CDK_ENV_PREFIX}MISSING is not set`) }) test("getConfigFromEnvVar supports alternate prefixes", () => { @@ -113,36 +114,36 @@ describe("config helpers", () => { }) test("getBooleanConfigFromEnvVar maps string booleans", () => { - process.env.CDK_CONFIG_FEATURE_FLAG = "true " - process.env.CDK_CONFIG_OTHER_FLAG = " false" + process.env[`${CDK_ENV_PREFIX}FEATURE_FLAG`] = "true " + process.env[`${CDK_ENV_PREFIX}OTHER_FLAG`] = " false" expect(getBooleanConfigFromEnvVar("FEATURE_FLAG")).toBe(true) expect(getBooleanConfigFromEnvVar("OTHER_FLAG")).toBe(false) }) test("getBooleanConfigFromEnvVar uses default value when env var is not set", () => { - delete process.env.CDK_CONFIG_BOOL_MISSING + delete process.env[`${CDK_ENV_PREFIX}BOOL_MISSING`] - expect(getBooleanConfigFromEnvVar("BOOL_MISSING", "CDK_CONFIG_", "true")).toBe(true) - expect(getBooleanConfigFromEnvVar("BOOL_MISSING", "CDK_CONFIG_", "false")).toBe(false) + expect(getBooleanConfigFromEnvVar("BOOL_MISSING", CDK_ENV_PREFIX, "true")).toBe(true) + expect(getBooleanConfigFromEnvVar("BOOL_MISSING", CDK_ENV_PREFIX, "false")).toBe(false) }) test("getNumberConfigFromEnvVar parses numeric strings", () => { - process.env.CDK_CONFIG_TIMEOUT = "45" + process.env[`${CDK_ENV_PREFIX}TIMEOUT`] = "45" expect(getNumberConfigFromEnvVar("TIMEOUT")).toBe(45) }) test("getNumberConfigFromEnvVar uses default value when env var is not set", () => { - delete process.env.CDK_CONFIG_NUM_MISSING + delete process.env[`${CDK_ENV_PREFIX}NUM_MISSING`] - expect(getNumberConfigFromEnvVar("NUM_MISSING", "CDK_CONFIG_", "99")).toBe(99) + expect(getNumberConfigFromEnvVar("NUM_MISSING", CDK_ENV_PREFIX, "99")).toBe(99) }) test("getConfigFromEnvVar ignores default value when env var is set", () => { - process.env.CDK_CONFIG_STACK_NAME = "primary" + process.env[`${CDK_ENV_PREFIX}STACK_NAME`] = "primary" - expect(getConfigFromEnvVar("STACK_NAME", "CDK_CONFIG_", "ignored")).toBe("primary") + expect(getConfigFromEnvVar("STACK_NAME", CDK_ENV_PREFIX, "ignored")).toBe("primary") }) test("getTrustStoreVersion returns the version ID from S3", async () => {