import * as cdk from "aws-cdk-lib"; import { Annotations, Match } from "aws-cdk-lib/assertions"; import * as iam from "aws-cdk-lib/aws-iam"; import { KebabNamingAspect, isKebabCase } from "../lib/aspects/kebab-naming-aspect"; import { OpenSweIamStack } from "../lib/open-swe-iam-stack"; import { OpenSweStack } from "../lib/open-swe-stack"; const ENV = { account: "328440206208", region: "us-east-1" }; describe("isKebabCase", () => { it.each([ "open-swe-dev", "open-swe-prod-instance-role", "githubdeploy-open-swe-infra", "open-swe-dev/slack-signing", // Secrets Manager path "/open-swe-dev/feature-flag", // SSM param path "/open-swe/dev/agent", // log group path "abc123", ])("accepts conforming name %s", (name) => { expect(isKebabCase(name)).toBe(true); }); it.each([ "OpenSweDev", "open_swe_dev", "openSweDev", "Open-Swe-Dev", "open-swe-dev/SlackSigning", ])("rejects non-conforming name %s", (name) => { expect(isKebabCase(name)).toBe(false); }); }); describe("KebabNamingAspect", () => { it("passes the real app stacks (no errors)", () => { const app = new cdk.App(); cdk.Aspects.of(app).add(new KebabNamingAspect()); new OpenSweIamStack(app, "OpenSweIamStack", { stackName: "open-swe-iam", env: ENV }); const dev = new OpenSweStack(app, "OpenSweDevStack", { stackName: "open-swe-dev", env: ENV, envName: "dev", }); const prod = new OpenSweStack(app, "OpenSweProdStack", { stackName: "open-swe-prod", env: ENV, envName: "prod", }); for (const s of [dev, prod]) { Annotations.fromStack(s).hasNoError("*", Match.anyValue()); } }); it("flags a deliberately non-kebab-case resource name", () => { const app = new cdk.App(); const stack = new cdk.Stack(app, "ConformingStackId", { stackName: "open-swe-test", env: ENV }); cdk.Aspects.of(stack).add(new KebabNamingAspect()); // Deliberately bad physical name — must be flagged. new iam.Role(stack, "BadlyNamedRole", { roleName: "OpenSweBadRole", assumedBy: new iam.ServicePrincipal("ec2.amazonaws.com"), }); Annotations.fromStack(stack).hasError( "*", Match.stringLikeRegexp("not kebab-case"), ); }); it("flags a deliberately non-kebab-case stack name", () => { const app = new cdk.App(); // PascalCase stackName — the convention CDK defaults to and that we forbid. const stack = new cdk.Stack(app, "BadStack", { stackName: "OpenSweBadStack", env: ENV }); cdk.Aspects.of(stack).add(new KebabNamingAspect()); Annotations.fromStack(stack).hasError( "*", Match.stringLikeRegexp("Stack name .* is not kebab-case"), ); }); });