mirror of
https://github.com/Sea-Haven-Industries/open-swe.git
synced 2026-10-05 20:02:11 +00:00
PR#1 of the AWS migration. CDK TypeScript app under /infra: stacks open-swe-iam (four per-env GitHub-OIDC deploy roles) + open-swe-dev/-prod (per-env EC2 instance role + AMI cache). aws-cdk-lib pinned exact 2.260.0; kebab naming Aspect + 15 tests. IAM is synth-only (NOT deployed). Cleared the Phase-1 security gates: - T4 GPT-4.1 IAM cross-review (StringEquals trust; cdk-hnb659fds-* wildcard kept as org convention; AWS-RunShellScript timeboxed to T19). - T5 /sh-security-review: deploy roles split PER-ENV with env-scoped OIDC trust (dev=branch ref+tag dev, prod=environment:prod+tag prod) so a dev token cannot reach prod; re-verified block:false.
84 lines
2.7 KiB
TypeScript
84 lines
2.7 KiB
TypeScript
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"),
|
|
);
|
|
});
|
|
});
|