From c81b198194b6f382ba081fbed10f28d056e019ff Mon Sep 17 00:00:00 2001 From: Anthony Brown Date: Tue, 27 Jan 2026 17:51:31 +0000 Subject: [PATCH 1/4] add more standard tags --- packages/cdkConstructs/src/apps/createApp.ts | 25 ++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/packages/cdkConstructs/src/apps/createApp.ts b/packages/cdkConstructs/src/apps/createApp.ts index 39866e89..4d2aa794 100644 --- a/packages/cdkConstructs/src/apps/createApp.ts +++ b/packages/cdkConstructs/src/apps/createApp.ts @@ -12,19 +12,25 @@ export interface StandardStackProps extends StackProps { readonly version: string readonly commitId: string readonly isPullRequest: boolean + readonly environment: string } export function createApp( + productName: string, appName: string, repoName: string, driftDetectionGroup: string, isStateless: boolean = true, - region: string = "eu-west-2" -): {app: App, props: StandardStackProps} { + region: string = "eu-west-2", + projectType: string = "Production", + publicFacing: string = "Y", + serviceCategory: string = "Platinum" +): { app: App, props: StandardStackProps } { let stackName = getConfigFromEnvVar("stackName") const versionNumber = getConfigFromEnvVar("versionNumber") const commitId = getConfigFromEnvVar("commitId") const isPullRequest = getBooleanConfigFromEnvVar("isPullRequest") + const environment = getConfigFromEnvVar("environment") let cfnDriftDetectionGroup = driftDetectionGroup if (isPullRequest) { cfnDriftDetectionGroup += "-pull-request" @@ -34,6 +40,21 @@ export function createApp( Aspects.of(app).add(new AwsSolutionsChecks({verbose: true})) + Tags.of(app).add("TagVersion", "1") + Tags.of(app).add("Programme", "EPS") + Tags.of(app).add("Product", productName) + Tags.of(app).add("EPS", productName) + Tags.of(app).add("Owner", "england.epssupport@nhs.net") + Tags.of(app).add("CostCentre", "128997") + Tags.of(app).add("Customer", "NHS England") + Tags.of(app).add("data_classification", "5") + Tags.of(app).add("DataType", "PII") + Tags.of(app).add("Environment", environment) + Tags.of(app).add("ProjectType", projectType) + Tags.of(app).add("PublicFacing", publicFacing) + Tags.of(app).add("ServiceCategory", serviceCategory) + Tags.of(app).add("OnOffPattern", "AlwaysOn") + Tags.of(app).add("DeploymentTool", "CDK") Tags.of(app).add("version", versionNumber) Tags.of(app).add("commit", commitId) Tags.of(app).add("stackName", stackName) From 5cb58b3e274dca4ba47c589ad9a47cc82692dafc Mon Sep 17 00:00:00 2001 From: Anthony Brown Date: Tue, 27 Jan 2026 18:05:16 +0000 Subject: [PATCH 2/4] fix return --- packages/cdkConstructs/src/apps/createApp.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/cdkConstructs/src/apps/createApp.ts b/packages/cdkConstructs/src/apps/createApp.ts index 4d2aa794..38763204 100644 --- a/packages/cdkConstructs/src/apps/createApp.ts +++ b/packages/cdkConstructs/src/apps/createApp.ts @@ -75,7 +75,8 @@ export function createApp( stackName, version: versionNumber, commitId, - isPullRequest + isPullRequest, + environment } } } From e4110e7756230be31d54ea12b0d84d0d33d346c6 Mon Sep 17 00:00:00 2001 From: Anthony Brown Date: Tue, 27 Jan 2026 18:25:56 +0000 Subject: [PATCH 3/4] fix tests --- package-lock.json | 25 +++++-- packages/cdkConstructs/package.json | 5 +- packages/cdkConstructs/src/apps/createApp.ts | 35 +++++---- .../tests/apps/createApp.test.ts | 72 +++++++++++++++---- 4 files changed, 105 insertions(+), 32 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4f98b7b6..b1da05d3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1123,6 +1123,7 @@ "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -4174,11 +4175,12 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "25.0.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.9.tgz", - "integrity": "sha512-/rpCXHlCWeqClNBwUhDcusJxXYDjZTyE8v5oTO7WbL8eij2nKhUeU89/6xgjU7N4/Vh3He0BtyhJdQbDyhiXAw==", + "version": "25.0.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.10.tgz", + "integrity": "sha512-zWW5KPngR/yvakJgGOmZ5vTBemDoSqF3AcV/LrO5u5wTWyEAVVh+IT39G4gtyAkh3CtTZs8aX/yRM82OfzHJRg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~7.16.0" } @@ -4242,6 +4244,7 @@ "integrity": "sha512-npiaib8XzbjtzS2N4HlqPvlpxpmZ14FjSJrteZpPxGUaYPlvhzlzUZ4mZyABo0EFrOWnvyd0Xxroq//hKhtAWg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.53.0", "@typescript-eslint/types": "8.53.0", @@ -4871,6 +4874,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -5560,6 +5564,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", @@ -5842,7 +5847,8 @@ "version": "10.4.5", "resolved": "https://registry.npmjs.org/constructs/-/constructs-10.4.5.tgz", "integrity": "sha512-fOoP70YLevMZr5avJHx2DU3LNYmC6wM8OwdrNewMZou1kZnPGOeVzBrRjZNgFDHUlulYUjkpFRSpTE3D+n+ZSg==", - "license": "Apache-2.0" + "license": "Apache-2.0", + "peer": true }, "node_modules/convert-source-map": { "version": "2.0.0", @@ -6086,6 +6092,7 @@ "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -6995,6 +7002,7 @@ "integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jest/core": "30.2.0", "@jest/types": "30.2.0", @@ -9422,6 +9430,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -9560,6 +9569,7 @@ "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -9646,6 +9656,7 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -9807,6 +9818,7 @@ "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", @@ -9915,6 +9927,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -9928,6 +9941,7 @@ "integrity": "sha512-FQMeF0DJdWY0iOnbv466n/0BudNdKj1l5jYgl5JVTwjSsZSlqyXFt/9+1sEyhR6CLowbZpV7O1sCHrzBhucKKg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@vitest/expect": "4.0.17", "@vitest/mocker": "4.0.17", @@ -10321,6 +10335,9 @@ "aws-cdk-lib": "^2.235.0", "cdk-nag": "^2.37.52", "constructs": "^10.4.5" + }, + "devDependencies": { + "@types/node": "^25.0.10" } }, "packages/deploymentUtils": { diff --git a/packages/cdkConstructs/package.json b/packages/cdkConstructs/package.json index 7d28d57f..645abcf5 100644 --- a/packages/cdkConstructs/package.json +++ b/packages/cdkConstructs/package.json @@ -35,5 +35,8 @@ "lib" ], "main": "lib/src/index.js", - "types": "lib/src/index.d.ts" + "types": "lib/src/index.d.ts", + "devDependencies": { + "@types/node": "^25.0.10" + } } diff --git a/packages/cdkConstructs/src/apps/createApp.ts b/packages/cdkConstructs/src/apps/createApp.ts index 38763204..611686b4 100644 --- a/packages/cdkConstructs/src/apps/createApp.ts +++ b/packages/cdkConstructs/src/apps/createApp.ts @@ -15,17 +15,29 @@ export interface StandardStackProps extends StackProps { readonly environment: string } -export function createApp( - productName: string, - appName: string, - repoName: string, - driftDetectionGroup: string, - isStateless: boolean = true, - region: string = "eu-west-2", - projectType: string = "Production", - publicFacing: string = "Y", - serviceCategory: string = "Platinum" -): { app: App, props: StandardStackProps } { +export interface CreateAppParams { + readonly productName: string + readonly appName: string + readonly repoName: string + readonly driftDetectionGroup: string + readonly isStateless?: boolean + readonly region?: string + readonly projectType?: string + readonly publicFacing?: string + readonly serviceCategory?: string +} + +export function createApp({ + productName, + appName, + repoName, + driftDetectionGroup, + isStateless = true, + region = "eu-west-2", + projectType = "Production", + publicFacing = "Y", + serviceCategory = "Platinum" +}: CreateAppParams): { app: App, props: StandardStackProps } { let stackName = getConfigFromEnvVar("stackName") const versionNumber = getConfigFromEnvVar("versionNumber") const commitId = getConfigFromEnvVar("commitId") @@ -43,7 +55,6 @@ export function createApp( Tags.of(app).add("TagVersion", "1") Tags.of(app).add("Programme", "EPS") Tags.of(app).add("Product", productName) - Tags.of(app).add("EPS", productName) Tags.of(app).add("Owner", "england.epssupport@nhs.net") Tags.of(app).add("CostCentre", "128997") Tags.of(app).add("Customer", "NHS England") diff --git a/packages/cdkConstructs/tests/apps/createApp.test.ts b/packages/cdkConstructs/tests/apps/createApp.test.ts index e09dbf4f..9d45b3da 100644 --- a/packages/cdkConstructs/tests/apps/createApp.test.ts +++ b/packages/cdkConstructs/tests/apps/createApp.test.ts @@ -22,11 +22,21 @@ import { expect, vi } from "vitest" -import {createApp} from "../../src/apps/createApp" +import {createApp, type CreateAppParams} from "../../src/apps/createApp" import {AwsSolutionsChecks} from "cdk-nag" describe("createApp", () => { const originalEnv = process.env + const defaultParams: CreateAppParams = { + productName: "testProduct", + appName: "testApp", + repoName: "testRepo", + driftDetectionGroup: "test-drift-group" + } + const buildParams = (overrides: Partial = {}): CreateAppParams => ({ + ...defaultParams, + ...overrides + }) beforeEach(() => { // Reset environment before each test @@ -45,10 +55,11 @@ describe("createApp", () => { 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" }) test("creates an App with correct configuration", () => { - const {app, props} = createApp("testApp", "testRepo", "test-drift-group") + const {app, props} = createApp(buildParams()) expect(app).toBeInstanceOf(App) expect(props.stackName).toBe("test-stack-1-2-3") @@ -59,13 +70,13 @@ describe("createApp", () => { }) test("creates stateful App with correct stackName", () => { - const {props} = createApp("testApp", "testRepo", "test-drift-group", false) + const {props} = createApp(buildParams({isStateless: false})) expect(props.stackName).toBe("test-stack") }) test("uses custom region when provided", () => { - const {props} = createApp("testApp", "testRepo", "test-drift-group", true, "us-east-1") + const {props} = createApp(buildParams({region: "us-east-1"})) expect(props.env?.region).toBe("us-east-1") }) @@ -77,12 +88,27 @@ describe("createApp", () => { add: addTagSpy } as unknown as Tags) - const {app} = createApp("testApp", "testRepo", "test-drift-group") + const {app} = createApp(buildParams()) // Verify Tags.of was called with the app expect(tagsOfSpy).toHaveBeenCalledWith(app) // Verify all expected tags were added with correct values + expect(addTagSpy).toHaveBeenCalledWith("TagVersion", "1") + expect(addTagSpy).toHaveBeenCalledWith("Programme", "EPS") + expect(addTagSpy).toHaveBeenCalledWith("Product", "testProduct") + expect(addTagSpy).toHaveBeenCalledWith("Owner", "england.epssupport@nhs.net") + expect(addTagSpy).toHaveBeenCalledWith("Product", "testProduct") + expect(addTagSpy).toHaveBeenCalledWith("CostCentre", "128997") + expect(addTagSpy).toHaveBeenCalledWith("Customer", "NHS England") + expect(addTagSpy).toHaveBeenCalledWith("data_classification", "5") + expect(addTagSpy).toHaveBeenCalledWith("DataType", "PII") + expect(addTagSpy).toHaveBeenCalledWith("Environment", "test-environment") + expect(addTagSpy).toHaveBeenCalledWith("ProjectType", "Production") + expect(addTagSpy).toHaveBeenCalledWith("PublicFacing", "Y") + expect(addTagSpy).toHaveBeenCalledWith("ServiceCategory", "Platinum") + expect(addTagSpy).toHaveBeenCalledWith("OnOffPattern", "AlwaysOn") + expect(addTagSpy).toHaveBeenCalledWith("DeploymentTool", "CDK") expect(addTagSpy).toHaveBeenCalledWith("version", "1.2.3") expect(addTagSpy).toHaveBeenCalledWith("commit", "abc123def456") expect(addTagSpy).toHaveBeenCalledWith("stackName", "test-stack") @@ -91,14 +117,14 @@ describe("createApp", () => { expect(addTagSpy).toHaveBeenCalledWith("cfnDriftDetectionGroup", "test-drift-group") // Verify exactly 6 tags were added - expect(addTagSpy).toHaveBeenCalledTimes(6) + expect(addTagSpy).toHaveBeenCalledTimes(20) // Restore the spy tagsOfSpy.mockRestore() }) test("adds AwsSolutionsChecks aspect", () => { - const {app} = createApp("testApp", "testRepo", "test-drift-group") + const {app} = createApp(buildParams()) const aspects = Aspects.of(app).all expect(aspects).toContainEqual(new AwsSolutionsChecks({verbose: true})) @@ -111,19 +137,21 @@ describe("createApp", () => { 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" }) test("correctly modifies props", () => { - const {props} = createApp("testApp", "testRepo", "test-drift-group") + const {props} = createApp(buildParams()) expect(props.stackName).toBe("pr-stack") expect(props.version).toBe("0.0.1-pr") expect(props.commitId).toBe("pr123") expect(props.isPullRequest).toBe(true) + expect(props.environment).toBe("test-environment") }) test("creates stateful App with unmodified stackName", () => { - const {props} = createApp("testApp", "testRepo", "test-drift-group", false) + const {props} = createApp(buildParams({isStateless: false})) expect(props.stackName).toBe("pr-stack") }) @@ -135,7 +163,7 @@ describe("createApp", () => { add: addTagSpy } as unknown as Tags) - const {app} = createApp("testApp", "testRepo", "test-drift-group") + const {app} = createApp(buildParams()) // Verify Tags.of was called with the app expect(tagsOfSpy).toHaveBeenCalledWith(app) @@ -150,9 +178,10 @@ describe("createApp", () => { process.env.CDK_CONFIG_versionNumber = "1.0.0" process.env.CDK_CONFIG_commitId = "abc123" process.env.CDK_CONFIG_isPullRequest = "false" + process.env.CDK_CONFIG_environment = "test-environment" expect(() => { - createApp("testApp", "testRepo", "test-drift-group") + createApp(buildParams()) }).toThrow("Environment variable CDK_CONFIG_stackName is not set") }) @@ -160,9 +189,10 @@ describe("createApp", () => { process.env.CDK_CONFIG_stackName = "test-stack" process.env.CDK_CONFIG_commitId = "abc123" process.env.CDK_CONFIG_isPullRequest = "false" + process.env.CDK_CONFIG_environment = "test-environment" expect(() => { - createApp("testApp", "testRepo", "test-drift-group") + createApp(buildParams()) }).toThrow("Environment variable CDK_CONFIG_versionNumber is not set") }) @@ -170,9 +200,10 @@ describe("createApp", () => { process.env.CDK_CONFIG_stackName = "test-stack" process.env.CDK_CONFIG_versionNumber = "1.0.0" process.env.CDK_CONFIG_isPullRequest = "false" + process.env.CDK_CONFIG_environment = "test-environment" expect(() => { - createApp("testApp", "testRepo", "test-drift-group") + createApp(buildParams()) }).toThrow("Environment variable CDK_CONFIG_commitId is not set") }) @@ -180,10 +211,21 @@ describe("createApp", () => { process.env.CDK_CONFIG_stackName = "test-stack" process.env.CDK_CONFIG_versionNumber = "1.0.0" process.env.CDK_CONFIG_commitId = "abc123" - + process.env.CDK_CONFIG_environment = "test-environment" expect(() => { - createApp("testApp", "testRepo", "test-drift-group") + createApp(buildParams()) }).toThrow("Environment variable CDK_CONFIG_isPullRequest is not set") }) + + test("throws error when environment is not set", () => { + process.env.CDK_CONFIG_stackName = "test-stack" + process.env.CDK_CONFIG_versionNumber = "1.0.0" + process.env.CDK_CONFIG_commitId = "abc123" + process.env.CDK_CONFIG_isPullRequest = "false" + expect(() => { + createApp(buildParams()) + }).toThrow("Environment variable CDK_CONFIG_environment is not set") + }) + }) }) From f53622f55ea19a5e7656798cac85d6d11bc8eae9 Mon Sep 17 00:00:00 2001 From: Anthony Brown Date: Wed, 28 Jan 2026 10:29:41 +0000 Subject: [PATCH 4/4] correct comment --- packages/cdkConstructs/tests/apps/createApp.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cdkConstructs/tests/apps/createApp.test.ts b/packages/cdkConstructs/tests/apps/createApp.test.ts index 9d45b3da..78fd87f0 100644 --- a/packages/cdkConstructs/tests/apps/createApp.test.ts +++ b/packages/cdkConstructs/tests/apps/createApp.test.ts @@ -116,7 +116,7 @@ describe("createApp", () => { expect(addTagSpy).toHaveBeenCalledWith("repo", "testRepo") expect(addTagSpy).toHaveBeenCalledWith("cfnDriftDetectionGroup", "test-drift-group") - // Verify exactly 6 tags were added + // Verify exactly 20 tags were added expect(addTagSpy).toHaveBeenCalledTimes(20) // Restore the spy