@intentius/chant-lexicon-aws 0.1.0 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/integrity.json +25 -19
  2. package/dist/manifest.json +1 -1
  3. package/dist/meta.json +734 -435
  4. package/dist/rules/waw032.ts +52 -0
  5. package/dist/rules/waw033.ts +86 -0
  6. package/dist/rules/waw034.ts +63 -0
  7. package/dist/rules/waw035.ts +71 -0
  8. package/dist/rules/waw036.ts +88 -0
  9. package/dist/rules/waw037.ts +81 -0
  10. package/dist/types/index.d.ts +991 -59
  11. package/package.json +2 -2
  12. package/src/codegen/docs.ts +9 -1
  13. package/src/composites/composites.test.ts +65 -0
  14. package/src/composites/ec2-instance-role.ts +39 -0
  15. package/src/composites/efs-with-access-point.ts +90 -0
  16. package/src/composites/fargate-service.ts +102 -2
  17. package/src/composites/index.ts +8 -0
  18. package/src/composites/lambda-dynamodb.ts +66 -17
  19. package/src/composites/lambda-function.ts +2 -1
  20. package/src/composites/lambda-s3.ts +66 -20
  21. package/src/composites/minimal-vpc.ts +71 -0
  22. package/src/composites/solr-fargate-service.ts +42 -0
  23. package/src/generated/index.d.ts +991 -59
  24. package/src/generated/index.ts +34 -5
  25. package/src/generated/lexicon-aws.json +734 -435
  26. package/src/index.ts +4 -0
  27. package/src/lint/post-synth/waw032.test.ts +83 -0
  28. package/src/lint/post-synth/waw032.ts +52 -0
  29. package/src/lint/post-synth/waw033.test.ts +68 -0
  30. package/src/lint/post-synth/waw033.ts +86 -0
  31. package/src/lint/post-synth/waw034.test.ts +54 -0
  32. package/src/lint/post-synth/waw034.ts +63 -0
  33. package/src/lint/post-synth/waw035.test.ts +74 -0
  34. package/src/lint/post-synth/waw035.ts +71 -0
  35. package/src/lint/post-synth/waw036.test.ts +217 -0
  36. package/src/lint/post-synth/waw036.ts +88 -0
  37. package/src/lint/post-synth/waw037.test.ts +155 -0
  38. package/src/lint/post-synth/waw037.ts +81 -0
  39. package/src/serializer.ts +1 -3
@@ -5,33 +5,36 @@ import {
5
5
  Bucket_ServerSideEncryptionRule,
6
6
  Bucket_ServerSideEncryptionByDefault,
7
7
  Bucket_PublicAccessBlockConfiguration,
8
+ Bucket_NotificationConfiguration,
9
+ Bucket_LambdaConfiguration,
10
+ Permission,
8
11
  Role_Policy,
9
12
  } from "../generated";
10
- import { Sub } from "../intrinsics";
13
+ import { Sub, Join } from "../intrinsics";
11
14
  import { S3Actions } from "../actions/s3";
12
15
  import { LambdaFunction, type LambdaFunctionProps } from "./lambda-function";
13
16
 
14
17
  export interface LambdaS3Props extends LambdaFunctionProps {
15
18
  bucketName?: string;
16
19
  access?: "ReadOnly" | "ReadWrite" | "Full";
20
+ trigger?: {
21
+ events?: string[];
22
+ prefix?: string;
23
+ suffix?: string;
24
+ };
17
25
  defaults?: LambdaFunctionProps["defaults"] & {
18
26
  bucket?: Partial<ConstructorParameters<typeof Bucket>[0]>;
19
27
  };
20
28
  }
21
29
 
22
30
  export const LambdaS3 = Composite<LambdaS3Props>((props) => {
23
- const encryptionDefault = new Bucket_ServerSideEncryptionByDefault({
24
- SSEAlgorithm: "AES256",
25
- });
26
-
31
+ const encryptionDefault = new Bucket_ServerSideEncryptionByDefault({ SSEAlgorithm: "AES256" });
27
32
  const encryptionRule = new Bucket_ServerSideEncryptionRule({
28
33
  ServerSideEncryptionByDefault: encryptionDefault,
29
34
  });
30
-
31
35
  const bucketEncryption = new Bucket_BucketEncryption({
32
36
  ServerSideEncryptionConfiguration: [encryptionRule],
33
37
  });
34
-
35
38
  const publicAccessBlock = new Bucket_PublicAccessBlockConfiguration({
36
39
  BlockPublicAcls: true,
37
40
  BlockPublicPolicy: true,
@@ -40,30 +43,73 @@ export const LambdaS3 = Composite<LambdaS3Props>((props) => {
40
43
  });
41
44
 
42
45
  const { defaults } = props;
46
+ const access = props.access ?? "ReadWrite";
47
+
48
+ if (props.trigger) {
49
+ // Create Lambda first to break the circular CFN dependency.
50
+ // Compute bucket ARN from name (no GetAtt on bucket → no resource dep).
51
+ const name = props.bucketName ?? Sub`\${AWS::StackName}-bucket`;
52
+ const bucketArnBase = Join("", ["arn:aws:s3:::", name]);
53
+ const bucketArnWildcard = Join("", ["arn:aws:s3:::", name, "/*"]);
54
+
55
+ const s3Policy = new Role_Policy({
56
+ PolicyName: `S3${access}`,
57
+ PolicyDocument: {
58
+ Version: "2012-10-17",
59
+ Statement: [{ Effect: "Allow", Action: S3Actions[access], Resource: [bucketArnBase, bucketArnWildcard] }],
60
+ },
61
+ });
62
+
63
+ const policies = props.Policies ? [s3Policy, ...props.Policies] : [s3Policy];
64
+ const env = props.Environment ?? { Variables: {} };
65
+ const variables = { ...((env as any).Variables ?? {}), BUCKET_NAME: name };
66
+ const { role, func } = LambdaFunction({ ...props, Policies: policies, Environment: { Variables: variables } });
43
67
 
68
+ const permission = new Permission({
69
+ FunctionName: func.Arn,
70
+ Action: "lambda:InvokeFunction",
71
+ Principal: "s3.amazonaws.com",
72
+ SourceArn: bucketArnBase,
73
+ });
74
+
75
+ const { events = ["s3:ObjectCreated:*"], prefix, suffix } = props.trigger;
76
+ const rules: Array<{ Name: string; Value: string }> = [];
77
+ if (prefix) rules.push({ Name: "prefix", Value: prefix });
78
+ if (suffix) rules.push({ Name: "suffix", Value: suffix });
79
+
80
+ const lambdaConfigs = events.map((event) => new Bucket_LambdaConfiguration({
81
+ Event: event,
82
+ Function: func.Arn,
83
+ ...(rules.length > 0 && { Filter: { S3Key: { Rules: rules } } }),
84
+ }));
85
+
86
+ const notificationConfig = new Bucket_NotificationConfiguration({
87
+ LambdaConfigurations: lambdaConfigs,
88
+ });
89
+
90
+ const bucket = new Bucket(mergeDefaults({
91
+ BucketName: props.bucketName,
92
+ BucketEncryption: bucketEncryption,
93
+ PublicAccessBlockConfiguration: publicAccessBlock,
94
+ NotificationConfiguration: notificationConfig,
95
+ }, defaults?.bucket), { DependsOn: [permission] });
96
+
97
+ return { bucket, role, func, permission };
98
+ }
99
+
100
+ // Non-trigger path: original flow
44
101
  const bucket = new Bucket(mergeDefaults({
45
102
  BucketName: props.bucketName,
46
103
  BucketEncryption: bucketEncryption,
47
104
  PublicAccessBlockConfiguration: publicAccessBlock,
48
105
  }, defaults?.bucket));
49
106
 
50
- const access = props.access ?? "ReadWrite";
51
107
  const s3PolicyDocument = {
52
108
  Version: "2012-10-17",
53
- Statement: [
54
- {
55
- Effect: "Allow",
56
- Action: S3Actions[access],
57
- Resource: [bucket.Arn, Sub`${bucket.Arn}/*`],
58
- },
59
- ],
109
+ Statement: [{ Effect: "Allow", Action: S3Actions[access], Resource: [bucket.Arn, Sub`${bucket.Arn}/*`] }],
60
110
  };
61
111
 
62
- const s3Policy = new Role_Policy({
63
- PolicyName: `S3${access}`,
64
- PolicyDocument: s3PolicyDocument,
65
- });
66
-
112
+ const s3Policy = new Role_Policy({ PolicyName: `S3${access}`, PolicyDocument: s3PolicyDocument });
67
113
  const policies = props.Policies ? [s3Policy, ...props.Policies] : [s3Policy];
68
114
  const env = props.Environment ?? { Variables: {} };
69
115
  const variables = { ...((env as any).Variables ?? {}), BUCKET_NAME: bucket.Ref };
@@ -0,0 +1,71 @@
1
+ import { Composite, mergeDefaults } from "@intentius/chant";
2
+ import {
3
+ Vpc,
4
+ Subnet,
5
+ InternetGateway,
6
+ VPCGatewayAttachment,
7
+ RouteTable,
8
+ EC2Route,
9
+ SubnetRouteTableAssociation,
10
+ SecurityGroup,
11
+ } from "../generated";
12
+ import { Select, GetAZs } from "../intrinsics";
13
+
14
+ export interface MinimalVpcProps {
15
+ cidr?: string;
16
+ subnetCidr?: string;
17
+ defaults?: {
18
+ vpc?: Partial<ConstructorParameters<typeof Vpc>[0]>;
19
+ subnet?: Partial<ConstructorParameters<typeof Subnet>[0]>;
20
+ securityGroup?: Partial<ConstructorParameters<typeof SecurityGroup>[0]>;
21
+ };
22
+ }
23
+
24
+ export const MinimalVpc = Composite<MinimalVpcProps>((props) => {
25
+ const { defaults } = props;
26
+ const cidr = props.cidr ?? "10.0.0.0/24";
27
+ const subnetCidr = props.subnetCidr ?? "10.0.0.0/25";
28
+
29
+ const vpc = new Vpc(mergeDefaults({
30
+ CidrBlock: cidr,
31
+ EnableDnsHostnames: true,
32
+ EnableDnsSupport: true,
33
+ }, defaults?.vpc));
34
+
35
+ const subnet = new Subnet(mergeDefaults({
36
+ VpcId: vpc.VpcId,
37
+ CidrBlock: subnetCidr,
38
+ AvailabilityZone: Select(0, GetAZs("")),
39
+ MapPublicIpOnLaunch: true,
40
+ }, defaults?.subnet));
41
+
42
+ const igw = new InternetGateway({});
43
+
44
+ const igwAttachment = new VPCGatewayAttachment({
45
+ VpcId: vpc.VpcId,
46
+ InternetGatewayId: igw.InternetGatewayId,
47
+ });
48
+
49
+ const routeTable = new RouteTable({ VpcId: vpc.VpcId });
50
+
51
+ const defaultRoute = new EC2Route(
52
+ {
53
+ RouteTableId: routeTable.RouteTableId,
54
+ DestinationCidrBlock: "0.0.0.0/0",
55
+ GatewayId: igw.InternetGatewayId,
56
+ },
57
+ { DependsOn: [igwAttachment] },
58
+ );
59
+
60
+ const subnetRta = new SubnetRouteTableAssociation({
61
+ SubnetId: subnet.SubnetId,
62
+ RouteTableId: routeTable.RouteTableId,
63
+ });
64
+
65
+ const securityGroup = new SecurityGroup(mergeDefaults({
66
+ GroupDescription: "MinimalVpc default security group",
67
+ VpcId: vpc.VpcId,
68
+ }, defaults?.securityGroup));
69
+
70
+ return { vpc, subnet, igw, igwAttachment, routeTable, defaultRoute, subnetRta, securityGroup };
71
+ }, "MinimalVpc");
@@ -0,0 +1,42 @@
1
+ import { Composite } from "@intentius/chant";
2
+ import { FargateService, FargateServiceProps } from "./fargate-service";
3
+
4
+ export interface SolrFargateServiceProps extends FargateServiceProps {
5
+ /**
6
+ * JVM heap size passed as SOLR_HEAP. Defaults to 45% of task memory.
7
+ * Examples: "1843m", "4g". Must not exceed 50% of task memory.
8
+ */
9
+ solrHeap?: string;
10
+ /**
11
+ * GC tuning string passed as GC_TUNE.
12
+ * Default: "-XX:+UseG1GC -XX:MaxGCPauseMillis=200"
13
+ */
14
+ gcOpts?: string;
15
+ }
16
+
17
+ export const SolrFargateService = Composite<SolrFargateServiceProps>((props) => {
18
+ const memoryMb = parseInt(props.memory ?? "4096");
19
+ const solrHeap = props.solrHeap ?? `${Math.floor(memoryMb * 0.45)}m`;
20
+ const gcOpts = props.gcOpts ?? "-XX:+UseG1GC -XX:MaxGCPauseMillis=200";
21
+
22
+ // Solr env defaults — user-supplied environment entries override these
23
+ const solrEnv: Record<string, string> = {
24
+ SOLR_HEAP: solrHeap,
25
+ GC_TUNE: gcOpts,
26
+ SOLR_OPTS: "-XX:-UseLargePages",
27
+ ...props.environment,
28
+ };
29
+
30
+ // Solr-specific ulimit default — user-supplied ulimits override
31
+ const solrUlimits = props.ulimits ?? [
32
+ { name: "nofile", softLimit: 65535, hardLimit: 65535 },
33
+ ];
34
+
35
+ return FargateService({
36
+ containerPort: 8983,
37
+ healthCheckPath: "/solr/admin/info/health",
38
+ ...props,
39
+ environment: solrEnv,
40
+ ulimits: solrUlimits,
41
+ });
42
+ }, "SolrFargateService");