@intentius/chant-lexicon-aws 0.0.6 → 0.0.9
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.
- package/dist/integrity.json +25 -10
- package/dist/manifest.json +1 -1
- package/dist/meta.json +9444 -4597
- package/dist/rules/cf-refs.ts +99 -0
- package/dist/rules/ext001.ts +32 -25
- package/dist/rules/hardcoded-region.ts +1 -0
- package/dist/rules/iam-wildcard.ts +1 -0
- package/dist/rules/s3-encryption.ts +3 -3
- package/dist/rules/waw016.ts +86 -0
- package/dist/rules/waw017.ts +53 -0
- package/dist/rules/waw018.ts +71 -0
- package/dist/rules/waw019.ts +82 -0
- package/dist/rules/waw020.ts +64 -0
- package/dist/rules/waw021.ts +53 -0
- package/dist/rules/waw022.ts +43 -0
- package/dist/rules/waw023.ts +47 -0
- package/dist/rules/waw024.ts +54 -0
- package/dist/rules/waw025.ts +43 -0
- package/dist/rules/waw026.ts +46 -0
- package/dist/rules/waw027.ts +50 -0
- package/dist/rules/waw028.ts +47 -0
- package/dist/rules/waw029.ts +62 -0
- package/dist/rules/waw030.ts +246 -0
- package/dist/skills/chant-aws.md +430 -0
- package/dist/types/index.d.ts +58525 -58501
- package/package.json +2 -2
- package/src/actions/actions.test.ts +75 -0
- package/src/actions/dynamodb.ts +36 -0
- package/src/actions/ecr.ts +9 -0
- package/src/actions/ecs.ts +5 -0
- package/src/actions/iam.ts +3 -0
- package/src/actions/index.ts +9 -0
- package/src/actions/lambda.ts +11 -0
- package/src/actions/logs.ts +4 -0
- package/src/actions/s3.ts +34 -0
- package/src/actions/sns.ts +5 -0
- package/src/actions/sqs.ts +15 -0
- package/src/codegen/__snapshots__/snapshot.test.ts.snap +20 -20
- package/src/codegen/docs-links.test.ts +143 -0
- package/src/codegen/docs.ts +294 -124
- package/src/codegen/generate-lexicon.ts +8 -0
- package/src/codegen/generate-typescript.ts +25 -1
- package/src/codegen/generate.ts +1 -13
- package/src/codegen/package.ts +2 -0
- package/src/codegen/typecheck.test.ts +1 -1
- package/src/composites/composites.test.ts +442 -0
- package/src/composites/fargate-alb.ts +253 -0
- package/src/composites/index.ts +20 -0
- package/src/composites/lambda-api.ts +20 -0
- package/src/composites/lambda-dynamodb.ts +64 -0
- package/src/composites/lambda-eventbridge.ts +36 -0
- package/src/composites/lambda-function.ts +76 -0
- package/src/composites/lambda-s3.ts +72 -0
- package/src/composites/lambda-sns.ts +30 -0
- package/src/composites/lambda-sqs.ts +44 -0
- package/src/composites/scheduled-lambda.ts +37 -0
- package/src/composites/vpc-default.ts +148 -0
- package/src/default-tags.test.ts +38 -0
- package/src/default-tags.ts +77 -0
- package/src/generated/index.d.ts +58525 -58501
- package/src/generated/index.ts +1351 -1351
- package/src/generated/lexicon-aws.json +9444 -4597
- package/src/import/generator.test.ts +5 -5
- package/src/import/generator.ts +4 -4
- package/src/import/roundtrip-fixtures.test.ts +2 -1
- package/src/import/roundtrip.test.ts +5 -5
- package/src/index.ts +21 -0
- package/src/integration.test.ts +92 -21
- package/src/intrinsics.ts +24 -13
- package/src/lint/post-synth/cf-refs.ts +99 -0
- package/src/lint/post-synth/ext001.test.ts +214 -31
- package/src/lint/post-synth/ext001.ts +32 -25
- package/src/lint/post-synth/waw013.test.ts +120 -0
- package/src/lint/post-synth/waw014.test.ts +121 -0
- package/src/lint/post-synth/waw015.test.ts +147 -0
- package/src/lint/post-synth/waw016.test.ts +141 -0
- package/src/lint/post-synth/waw016.ts +86 -0
- package/src/lint/post-synth/waw017.test.ts +130 -0
- package/src/lint/post-synth/waw017.ts +53 -0
- package/src/lint/post-synth/waw018.test.ts +109 -0
- package/src/lint/post-synth/waw018.ts +71 -0
- package/src/lint/post-synth/waw019.test.ts +138 -0
- package/src/lint/post-synth/waw019.ts +82 -0
- package/src/lint/post-synth/waw020.test.ts +125 -0
- package/src/lint/post-synth/waw020.ts +64 -0
- package/src/lint/post-synth/waw021.test.ts +81 -0
- package/src/lint/post-synth/waw021.ts +53 -0
- package/src/lint/post-synth/waw022.test.ts +54 -0
- package/src/lint/post-synth/waw022.ts +43 -0
- package/src/lint/post-synth/waw023.test.ts +53 -0
- package/src/lint/post-synth/waw023.ts +47 -0
- package/src/lint/post-synth/waw024.test.ts +64 -0
- package/src/lint/post-synth/waw024.ts +54 -0
- package/src/lint/post-synth/waw025.test.ts +42 -0
- package/src/lint/post-synth/waw025.ts +43 -0
- package/src/lint/post-synth/waw026.test.ts +54 -0
- package/src/lint/post-synth/waw026.ts +46 -0
- package/src/lint/post-synth/waw027.test.ts +63 -0
- package/src/lint/post-synth/waw027.ts +50 -0
- package/src/lint/post-synth/waw028.test.ts +68 -0
- package/src/lint/post-synth/waw028.ts +47 -0
- package/src/lint/post-synth/waw029.test.ts +179 -0
- package/src/lint/post-synth/waw029.ts +62 -0
- package/src/lint/post-synth/waw030.test.ts +800 -0
- package/src/lint/post-synth/waw030.ts +246 -0
- package/src/lint/rules/hardcoded-region.ts +1 -0
- package/src/lint/rules/iam-wildcard.ts +1 -0
- package/src/lint/rules/rules.test.ts +8 -8
- package/src/lint/rules/s3-encryption.ts +3 -3
- package/src/lsp/completions.ts +2 -0
- package/src/lsp/hover.ts +17 -0
- package/src/nested-stack-integration.test.ts +100 -0
- package/src/nested-stack.ts +2 -2
- package/src/plugin.test.ts +13 -15
- package/src/plugin.ts +552 -114
- package/src/serializer.test.ts +370 -43
- package/src/serializer.ts +69 -17
- package/src/spec/fetch.ts +10 -0
- package/src/spec/parse.test.ts +141 -0
- package/src/spec/parse.ts +40 -0
- package/src/taggable.ts +44 -0
- package/src/testdata/nested-stacks/app.ts +26 -0
- package/src/testdata/nested-stacks/network/outputs.ts +17 -0
- package/src/testdata/nested-stacks/network/security.ts +17 -0
- package/src/testdata/nested-stacks/network/vpc.ts +54 -0
- package/dist/skills/aws-cloudformation.md +0 -41
- package/src/codegen/rollback.test.ts +0 -80
- package/src/codegen/rollback.ts +0 -20
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import { Composite } from "@intentius/chant";
|
|
2
|
+
import {
|
|
3
|
+
EcsCluster,
|
|
4
|
+
EcsService,
|
|
5
|
+
EcsService_LoadBalancer,
|
|
6
|
+
EcsService_NetworkConfiguration,
|
|
7
|
+
EcsService_AwsVpcConfiguration,
|
|
8
|
+
TaskDefinition,
|
|
9
|
+
TaskDefinition_ContainerDefinition,
|
|
10
|
+
TaskDefinition_PortMapping,
|
|
11
|
+
TaskDefinition_LogConfiguration,
|
|
12
|
+
TaskDefinition_KeyValuePair,
|
|
13
|
+
LoadBalancer,
|
|
14
|
+
TargetGroup,
|
|
15
|
+
Listener,
|
|
16
|
+
Listener_Action,
|
|
17
|
+
SecurityGroup,
|
|
18
|
+
SecurityGroup_Ingress,
|
|
19
|
+
LogGroup,
|
|
20
|
+
Role,
|
|
21
|
+
Role_Policy,
|
|
22
|
+
} from "../generated";
|
|
23
|
+
import { Sub } from "../intrinsics";
|
|
24
|
+
import { ECRActions } from "../actions/ecr";
|
|
25
|
+
import { LogsActions } from "../actions/logs";
|
|
26
|
+
|
|
27
|
+
export interface FargateAlbProps {
|
|
28
|
+
image: string;
|
|
29
|
+
containerPort?: number;
|
|
30
|
+
cpu?: string;
|
|
31
|
+
memory?: string;
|
|
32
|
+
desiredCount?: number;
|
|
33
|
+
vpcId: string;
|
|
34
|
+
publicSubnetIds: string[];
|
|
35
|
+
privateSubnetIds: string[];
|
|
36
|
+
healthCheckPath?: string;
|
|
37
|
+
listenerPort?: number;
|
|
38
|
+
environment?: Record<string, string>;
|
|
39
|
+
command?: string[];
|
|
40
|
+
ManagedPolicyArns?: string[];
|
|
41
|
+
Policies?: InstanceType<typeof Role_Policy>[];
|
|
42
|
+
logRetentionDays?: number;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const ecsTrustPolicy = {
|
|
46
|
+
Version: "2012-10-17" as const,
|
|
47
|
+
Statement: [
|
|
48
|
+
{
|
|
49
|
+
Effect: "Allow" as const,
|
|
50
|
+
Principal: { Service: "ecs-tasks.amazonaws.com" },
|
|
51
|
+
Action: "sts:AssumeRole",
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const FargateAlb = Composite<FargateAlbProps>((props) => {
|
|
57
|
+
const containerPort = props.containerPort ?? 80;
|
|
58
|
+
const cpu = props.cpu ?? "256";
|
|
59
|
+
const memory = props.memory ?? "512";
|
|
60
|
+
const desiredCount = props.desiredCount ?? 2;
|
|
61
|
+
const healthCheckPath = props.healthCheckPath ?? "/";
|
|
62
|
+
const listenerPort = props.listenerPort ?? 80;
|
|
63
|
+
const logRetentionDays = props.logRetentionDays ?? 30;
|
|
64
|
+
|
|
65
|
+
// ECS Cluster
|
|
66
|
+
const cluster = new EcsCluster({});
|
|
67
|
+
|
|
68
|
+
// Execution role — ECR pull + CloudWatch Logs write
|
|
69
|
+
const executionPolicyDocument = {
|
|
70
|
+
Version: "2012-10-17",
|
|
71
|
+
Statement: [
|
|
72
|
+
{
|
|
73
|
+
Effect: "Allow",
|
|
74
|
+
Action: ECRActions.Pull,
|
|
75
|
+
Resource: "*",
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
Effect: "Allow",
|
|
79
|
+
Action: LogsActions.Write,
|
|
80
|
+
Resource: "*",
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const executionPolicy = new Role_Policy({
|
|
86
|
+
PolicyName: "ExecutionPolicy",
|
|
87
|
+
PolicyDocument: executionPolicyDocument,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const executionRole = new Role({
|
|
91
|
+
AssumeRolePolicyDocument: ecsTrustPolicy,
|
|
92
|
+
Policies: [executionPolicy],
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Task role — app permissions
|
|
96
|
+
const taskRole = new Role({
|
|
97
|
+
AssumeRolePolicyDocument: ecsTrustPolicy,
|
|
98
|
+
ManagedPolicyArns: props.ManagedPolicyArns,
|
|
99
|
+
Policies: props.Policies,
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// Log group
|
|
103
|
+
const logGroup = new LogGroup({
|
|
104
|
+
RetentionInDays: logRetentionDays,
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// Container definition
|
|
108
|
+
const portMapping = new TaskDefinition_PortMapping({
|
|
109
|
+
ContainerPort: containerPort,
|
|
110
|
+
Protocol: "tcp",
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
const logConfiguration = new TaskDefinition_LogConfiguration({
|
|
114
|
+
LogDriver: "awslogs",
|
|
115
|
+
Options: {
|
|
116
|
+
"awslogs-group": logGroup as any,
|
|
117
|
+
"awslogs-region": Sub`\${AWS::Region}`,
|
|
118
|
+
"awslogs-stream-prefix": "ecs",
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const environmentVars: InstanceType<typeof TaskDefinition_KeyValuePair>[] = [];
|
|
123
|
+
if (props.environment) {
|
|
124
|
+
for (const [name, value] of Object.entries(props.environment)) {
|
|
125
|
+
environmentVars.push(
|
|
126
|
+
new TaskDefinition_KeyValuePair({ Name: name, Value: value }),
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const container = new TaskDefinition_ContainerDefinition({
|
|
132
|
+
Name: "app",
|
|
133
|
+
Image: props.image,
|
|
134
|
+
Essential: true,
|
|
135
|
+
PortMappings: [portMapping],
|
|
136
|
+
LogConfiguration: logConfiguration,
|
|
137
|
+
Environment: environmentVars.length > 0 ? environmentVars : undefined,
|
|
138
|
+
Command: props.command,
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// Task definition
|
|
142
|
+
const taskDef = new TaskDefinition({
|
|
143
|
+
NetworkMode: "awsvpc",
|
|
144
|
+
RequiresCompatibilities: ["FARGATE"],
|
|
145
|
+
Cpu: cpu,
|
|
146
|
+
Memory: memory,
|
|
147
|
+
ExecutionRoleArn: executionRole.Arn,
|
|
148
|
+
TaskRoleArn: taskRole.Arn,
|
|
149
|
+
ContainerDefinitions: [container],
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// ALB security group — ingress on listener port from anywhere
|
|
153
|
+
const albIngress = new SecurityGroup_Ingress({
|
|
154
|
+
IpProtocol: "tcp",
|
|
155
|
+
FromPort: listenerPort,
|
|
156
|
+
ToPort: listenerPort,
|
|
157
|
+
CidrIp: "0.0.0.0/0",
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
const albSg = new SecurityGroup({
|
|
161
|
+
GroupDescription: "ALB security group",
|
|
162
|
+
VpcId: props.vpcId,
|
|
163
|
+
SecurityGroupIngress: [albIngress],
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
// Task security group — ingress on container port from ALB SG
|
|
167
|
+
const taskIngress = new SecurityGroup_Ingress({
|
|
168
|
+
IpProtocol: "tcp",
|
|
169
|
+
FromPort: containerPort,
|
|
170
|
+
ToPort: containerPort,
|
|
171
|
+
SourceSecurityGroupId: albSg.GroupId,
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
const taskSg = new SecurityGroup({
|
|
175
|
+
GroupDescription: "Fargate task security group",
|
|
176
|
+
VpcId: props.vpcId,
|
|
177
|
+
SecurityGroupIngress: [taskIngress],
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
// Application Load Balancer
|
|
181
|
+
const alb = new LoadBalancer({
|
|
182
|
+
Type: "application",
|
|
183
|
+
Scheme: "internet-facing",
|
|
184
|
+
Subnets: props.publicSubnetIds,
|
|
185
|
+
SecurityGroups: [albSg.GroupId],
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// Target group
|
|
189
|
+
const targetGroup = new TargetGroup({
|
|
190
|
+
TargetType: "ip",
|
|
191
|
+
Protocol: "HTTP",
|
|
192
|
+
Port: containerPort,
|
|
193
|
+
VpcId: props.vpcId,
|
|
194
|
+
HealthCheckPath: healthCheckPath,
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
// Listener
|
|
198
|
+
const defaultAction = new Listener_Action({
|
|
199
|
+
Type: "forward",
|
|
200
|
+
TargetGroupArn: targetGroup.TargetGroupArn,
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
const listener = new Listener({
|
|
204
|
+
LoadBalancerArn: alb.LoadBalancerArn,
|
|
205
|
+
Port: listenerPort,
|
|
206
|
+
Protocol: "HTTP",
|
|
207
|
+
DefaultActions: [defaultAction],
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// ECS Service
|
|
211
|
+
const serviceLoadBalancer = new EcsService_LoadBalancer({
|
|
212
|
+
ContainerName: "app",
|
|
213
|
+
ContainerPort: containerPort,
|
|
214
|
+
TargetGroupArn: targetGroup.TargetGroupArn,
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
const awsVpcConfig = new EcsService_AwsVpcConfiguration({
|
|
218
|
+
Subnets: props.privateSubnetIds,
|
|
219
|
+
SecurityGroups: [taskSg.GroupId],
|
|
220
|
+
AssignPublicIp: "DISABLED",
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
const networkConfig = new EcsService_NetworkConfiguration({
|
|
224
|
+
AwsvpcConfiguration: awsVpcConfig,
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
const service = new EcsService(
|
|
228
|
+
{
|
|
229
|
+
Cluster: cluster.Arn,
|
|
230
|
+
TaskDefinition: taskDef.TaskDefinitionArn,
|
|
231
|
+
LaunchType: "FARGATE",
|
|
232
|
+
DesiredCount: desiredCount,
|
|
233
|
+
HealthCheckGracePeriodSeconds: 60,
|
|
234
|
+
LoadBalancers: [serviceLoadBalancer],
|
|
235
|
+
NetworkConfiguration: networkConfig,
|
|
236
|
+
},
|
|
237
|
+
{ DependsOn: [listener] },
|
|
238
|
+
);
|
|
239
|
+
|
|
240
|
+
return {
|
|
241
|
+
cluster,
|
|
242
|
+
executionRole,
|
|
243
|
+
taskRole,
|
|
244
|
+
logGroup,
|
|
245
|
+
taskDef,
|
|
246
|
+
albSg,
|
|
247
|
+
taskSg,
|
|
248
|
+
alb,
|
|
249
|
+
targetGroup,
|
|
250
|
+
listener,
|
|
251
|
+
service,
|
|
252
|
+
};
|
|
253
|
+
}, "FargateAlb");
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export { LambdaFunction, LambdaNode, LambdaPython, NodeLambda, PythonLambda } from "./lambda-function";
|
|
2
|
+
export type { LambdaFunctionProps } from "./lambda-function";
|
|
3
|
+
export { LambdaApi } from "./lambda-api";
|
|
4
|
+
export type { LambdaApiProps } from "./lambda-api";
|
|
5
|
+
export { LambdaScheduled, ScheduledLambda } from "./scheduled-lambda";
|
|
6
|
+
export type { ScheduledLambdaProps } from "./scheduled-lambda";
|
|
7
|
+
export { LambdaSqs } from "./lambda-sqs";
|
|
8
|
+
export type { LambdaSqsProps } from "./lambda-sqs";
|
|
9
|
+
export { LambdaEventBridge } from "./lambda-eventbridge";
|
|
10
|
+
export type { LambdaEventBridgeProps } from "./lambda-eventbridge";
|
|
11
|
+
export { LambdaDynamoDB } from "./lambda-dynamodb";
|
|
12
|
+
export type { LambdaDynamoDBProps } from "./lambda-dynamodb";
|
|
13
|
+
export { LambdaS3 } from "./lambda-s3";
|
|
14
|
+
export type { LambdaS3Props } from "./lambda-s3";
|
|
15
|
+
export { LambdaSns } from "./lambda-sns";
|
|
16
|
+
export type { LambdaSnsProps } from "./lambda-sns";
|
|
17
|
+
export { VpcDefault } from "./vpc-default";
|
|
18
|
+
export type { VpcDefaultProps } from "./vpc-default";
|
|
19
|
+
export { FargateAlb } from "./fargate-alb";
|
|
20
|
+
export type { FargateAlbProps } from "./fargate-alb";
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Composite } from "@intentius/chant";
|
|
2
|
+
import { Permission } from "../generated";
|
|
3
|
+
import { LambdaFunction, type LambdaFunctionProps } from "./lambda-function";
|
|
4
|
+
|
|
5
|
+
export interface LambdaApiProps extends LambdaFunctionProps {
|
|
6
|
+
sourceArn?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const LambdaApi = Composite<LambdaApiProps>((props) => {
|
|
10
|
+
const { role, func } = LambdaFunction(props);
|
|
11
|
+
|
|
12
|
+
const permission = new Permission({
|
|
13
|
+
FunctionName: func.Arn,
|
|
14
|
+
Action: "lambda:InvokeFunction",
|
|
15
|
+
Principal: "apigateway.amazonaws.com",
|
|
16
|
+
SourceArn: props.sourceArn,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
return { role, func, permission };
|
|
20
|
+
}, "LambdaApi");
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Composite } from "@intentius/chant";
|
|
2
|
+
import { Table, Table_AttributeDefinition, Table_KeySchema, Role_Policy } from "../generated";
|
|
3
|
+
import { DynamoDBActions } from "../actions/dynamodb";
|
|
4
|
+
import { LambdaFunction, type LambdaFunctionProps } from "./lambda-function";
|
|
5
|
+
|
|
6
|
+
export interface LambdaDynamoDBProps extends LambdaFunctionProps {
|
|
7
|
+
tableName?: string;
|
|
8
|
+
partitionKey: string;
|
|
9
|
+
sortKey?: string;
|
|
10
|
+
access?: "ReadOnly" | "ReadWrite" | "Full";
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const LambdaDynamoDB = Composite<LambdaDynamoDBProps>((props) => {
|
|
14
|
+
const attributeDefinitions = [
|
|
15
|
+
new Table_AttributeDefinition({ AttributeName: props.partitionKey, AttributeType: "S" }),
|
|
16
|
+
];
|
|
17
|
+
const keySchema: InstanceType<typeof Table_KeySchema>[] = [
|
|
18
|
+
new Table_KeySchema({ AttributeName: props.partitionKey, KeyType: "HASH" }),
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
if (props.sortKey) {
|
|
22
|
+
attributeDefinitions.push(
|
|
23
|
+
new Table_AttributeDefinition({ AttributeName: props.sortKey, AttributeType: "S" }),
|
|
24
|
+
);
|
|
25
|
+
keySchema.push(
|
|
26
|
+
new Table_KeySchema({ AttributeName: props.sortKey, KeyType: "RANGE" }),
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const table = new Table({
|
|
31
|
+
TableName: props.tableName,
|
|
32
|
+
BillingMode: "PAY_PER_REQUEST",
|
|
33
|
+
AttributeDefinitions: attributeDefinitions,
|
|
34
|
+
KeySchema: keySchema,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const access = props.access ?? "ReadWrite";
|
|
38
|
+
const dynamoPolicyDocument = {
|
|
39
|
+
Version: "2012-10-17",
|
|
40
|
+
Statement: [
|
|
41
|
+
{
|
|
42
|
+
Effect: "Allow",
|
|
43
|
+
Action: DynamoDBActions[access],
|
|
44
|
+
Resource: table.Arn,
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const dynamoPolicy = new Role_Policy({
|
|
50
|
+
PolicyName: `DynamoDB${access}`,
|
|
51
|
+
PolicyDocument: dynamoPolicyDocument,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const policies = props.Policies ? [dynamoPolicy, ...props.Policies] : [dynamoPolicy];
|
|
55
|
+
const env = props.Environment ?? { Variables: {} };
|
|
56
|
+
const variables = { ...((env as any).Variables ?? {}), TABLE_NAME: table.Ref };
|
|
57
|
+
const { role, func } = LambdaFunction({
|
|
58
|
+
...props,
|
|
59
|
+
Policies: policies,
|
|
60
|
+
Environment: { Variables: variables },
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
return { table, role, func };
|
|
64
|
+
}, "LambdaDynamoDB");
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Composite } from "@intentius/chant";
|
|
2
|
+
import { EventRule, EventRule_Target, Permission } from "../generated";
|
|
3
|
+
import { LambdaFunction, type LambdaFunctionProps } from "./lambda-function";
|
|
4
|
+
|
|
5
|
+
export interface LambdaEventBridgeProps extends LambdaFunctionProps {
|
|
6
|
+
ruleName?: string;
|
|
7
|
+
schedule?: string;
|
|
8
|
+
eventPattern?: Record<string, unknown>;
|
|
9
|
+
enabled?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const LambdaEventBridge = Composite<LambdaEventBridgeProps>((props) => {
|
|
13
|
+
const { role, func } = LambdaFunction(props);
|
|
14
|
+
|
|
15
|
+
const rule = new EventRule({
|
|
16
|
+
Name: props.ruleName,
|
|
17
|
+
ScheduleExpression: props.schedule,
|
|
18
|
+
EventPattern: props.eventPattern,
|
|
19
|
+
State: (props.enabled ?? true) ? "ENABLED" : "DISABLED",
|
|
20
|
+
Targets: [
|
|
21
|
+
new EventRule_Target({
|
|
22
|
+
Arn: func.Arn,
|
|
23
|
+
Id: "Target0",
|
|
24
|
+
}),
|
|
25
|
+
],
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const permission = new Permission({
|
|
29
|
+
FunctionName: func.Arn,
|
|
30
|
+
Action: "lambda:InvokeFunction",
|
|
31
|
+
Principal: "events.amazonaws.com",
|
|
32
|
+
SourceArn: rule.Arn,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
return { rule, role, func, permission };
|
|
36
|
+
}, "LambdaEventBridge");
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Composite, withDefaults } from "@intentius/chant";
|
|
2
|
+
import { Role, Function, Function_VpcConfig, Role_Policy } from "../generated";
|
|
3
|
+
|
|
4
|
+
const lambdaTrustPolicy = {
|
|
5
|
+
Version: "2012-10-17" as const,
|
|
6
|
+
Statement: [
|
|
7
|
+
{
|
|
8
|
+
Effect: "Allow" as const,
|
|
9
|
+
Principal: { Service: "lambda.amazonaws.com" },
|
|
10
|
+
Action: "sts:AssumeRole",
|
|
11
|
+
},
|
|
12
|
+
],
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const BASIC_EXECUTION_ARN =
|
|
16
|
+
"arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole";
|
|
17
|
+
const VPC_ACCESS_ARN =
|
|
18
|
+
"arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole";
|
|
19
|
+
|
|
20
|
+
export interface LambdaFunctionProps {
|
|
21
|
+
name: string;
|
|
22
|
+
Runtime: string;
|
|
23
|
+
Handler: string;
|
|
24
|
+
Code: ConstructorParameters<typeof Function>[0]["Code"];
|
|
25
|
+
Timeout?: number;
|
|
26
|
+
MemorySize?: number;
|
|
27
|
+
Environment?: ConstructorParameters<typeof Function>[0]["Environment"];
|
|
28
|
+
ManagedPolicyArns?: string[];
|
|
29
|
+
Policies?: InstanceType<typeof Role_Policy>[];
|
|
30
|
+
VpcConfig?: ConstructorParameters<typeof Function_VpcConfig>[0];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const LambdaFunction = Composite<LambdaFunctionProps>((props) => {
|
|
34
|
+
const managedPolicies = [BASIC_EXECUTION_ARN];
|
|
35
|
+
if (props.VpcConfig) {
|
|
36
|
+
managedPolicies.push(VPC_ACCESS_ARN);
|
|
37
|
+
}
|
|
38
|
+
if (props.ManagedPolicyArns) {
|
|
39
|
+
managedPolicies.push(...props.ManagedPolicyArns);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const role = new Role({
|
|
43
|
+
AssumeRolePolicyDocument: lambdaTrustPolicy,
|
|
44
|
+
ManagedPolicyArns: managedPolicies,
|
|
45
|
+
Policies: props.Policies,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const func = new Function({
|
|
49
|
+
FunctionName: props.name,
|
|
50
|
+
Runtime: props.Runtime as any,
|
|
51
|
+
Handler: props.Handler,
|
|
52
|
+
Code: props.Code,
|
|
53
|
+
Role: role.Arn,
|
|
54
|
+
Timeout: props.Timeout ?? 30,
|
|
55
|
+
MemorySize: props.MemorySize,
|
|
56
|
+
Environment: props.Environment,
|
|
57
|
+
VpcConfig: props.VpcConfig ? new Function_VpcConfig(props.VpcConfig) : undefined,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
return { role, func };
|
|
61
|
+
}, "LambdaFunction");
|
|
62
|
+
|
|
63
|
+
export const LambdaNode = withDefaults(LambdaFunction, {
|
|
64
|
+
Runtime: "nodejs20.x",
|
|
65
|
+
Handler: "index.handler",
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
export const LambdaPython = withDefaults(LambdaFunction, {
|
|
69
|
+
Runtime: "python3.12",
|
|
70
|
+
Handler: "handler.handler",
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
/** @deprecated Use `LambdaNode` instead */
|
|
74
|
+
export const NodeLambda = LambdaNode;
|
|
75
|
+
/** @deprecated Use `LambdaPython` instead */
|
|
76
|
+
export const PythonLambda = LambdaPython;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Composite } from "@intentius/chant";
|
|
2
|
+
import {
|
|
3
|
+
Bucket,
|
|
4
|
+
Bucket_BucketEncryption,
|
|
5
|
+
Bucket_ServerSideEncryptionRule,
|
|
6
|
+
Bucket_ServerSideEncryptionByDefault,
|
|
7
|
+
Bucket_PublicAccessBlockConfiguration,
|
|
8
|
+
Role_Policy,
|
|
9
|
+
} from "../generated";
|
|
10
|
+
import { Sub } from "../intrinsics";
|
|
11
|
+
import { S3Actions } from "../actions/s3";
|
|
12
|
+
import { LambdaFunction, type LambdaFunctionProps } from "./lambda-function";
|
|
13
|
+
|
|
14
|
+
export interface LambdaS3Props extends LambdaFunctionProps {
|
|
15
|
+
bucketName?: string;
|
|
16
|
+
access?: "ReadOnly" | "ReadWrite" | "Full";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const LambdaS3 = Composite<LambdaS3Props>((props) => {
|
|
20
|
+
const encryptionDefault = new Bucket_ServerSideEncryptionByDefault({
|
|
21
|
+
SSEAlgorithm: "AES256",
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const encryptionRule = new Bucket_ServerSideEncryptionRule({
|
|
25
|
+
ServerSideEncryptionByDefault: encryptionDefault,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const bucketEncryption = new Bucket_BucketEncryption({
|
|
29
|
+
ServerSideEncryptionConfiguration: [encryptionRule],
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const publicAccessBlock = new Bucket_PublicAccessBlockConfiguration({
|
|
33
|
+
BlockPublicAcls: true,
|
|
34
|
+
BlockPublicPolicy: true,
|
|
35
|
+
IgnorePublicAcls: true,
|
|
36
|
+
RestrictPublicBuckets: true,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const bucket = new Bucket({
|
|
40
|
+
BucketName: props.bucketName,
|
|
41
|
+
BucketEncryption: bucketEncryption,
|
|
42
|
+
PublicAccessBlockConfiguration: publicAccessBlock,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const access = props.access ?? "ReadWrite";
|
|
46
|
+
const s3PolicyDocument = {
|
|
47
|
+
Version: "2012-10-17",
|
|
48
|
+
Statement: [
|
|
49
|
+
{
|
|
50
|
+
Effect: "Allow",
|
|
51
|
+
Action: S3Actions[access],
|
|
52
|
+
Resource: [bucket.Arn, Sub`${bucket.Arn}/*`],
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const s3Policy = new Role_Policy({
|
|
58
|
+
PolicyName: `S3${access}`,
|
|
59
|
+
PolicyDocument: s3PolicyDocument,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const policies = props.Policies ? [s3Policy, ...props.Policies] : [s3Policy];
|
|
63
|
+
const env = props.Environment ?? { Variables: {} };
|
|
64
|
+
const variables = { ...((env as any).Variables ?? {}), BUCKET_NAME: bucket.Ref };
|
|
65
|
+
const { role, func } = LambdaFunction({
|
|
66
|
+
...props,
|
|
67
|
+
Policies: policies,
|
|
68
|
+
Environment: { Variables: variables },
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
return { bucket, role, func };
|
|
72
|
+
}, "LambdaS3");
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Composite } from "@intentius/chant";
|
|
2
|
+
import { Topic, Subscription, Permission } from "../generated";
|
|
3
|
+
import { LambdaFunction, type LambdaFunctionProps } from "./lambda-function";
|
|
4
|
+
|
|
5
|
+
export interface LambdaSnsProps extends LambdaFunctionProps {
|
|
6
|
+
topicName?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const LambdaSns = Composite<LambdaSnsProps>((props) => {
|
|
10
|
+
const { role, func } = LambdaFunction(props);
|
|
11
|
+
|
|
12
|
+
const topic = new Topic({
|
|
13
|
+
TopicName: props.topicName,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const subscription = new Subscription({
|
|
17
|
+
TopicArn: topic.TopicArn,
|
|
18
|
+
Protocol: "lambda",
|
|
19
|
+
Endpoint: func.Arn,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const permission = new Permission({
|
|
23
|
+
FunctionName: func.Arn,
|
|
24
|
+
Action: "lambda:InvokeFunction",
|
|
25
|
+
Principal: "sns.amazonaws.com",
|
|
26
|
+
SourceArn: topic.TopicArn,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
return { topic, role, func, subscription, permission };
|
|
30
|
+
}, "LambdaSns");
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Composite } from "@intentius/chant";
|
|
2
|
+
import { Queue, EventSourceMapping, Role_Policy } from "../generated";
|
|
3
|
+
import { SQSActions } from "../actions/sqs";
|
|
4
|
+
import { LambdaFunction, type LambdaFunctionProps } from "./lambda-function";
|
|
5
|
+
|
|
6
|
+
export interface LambdaSqsProps extends LambdaFunctionProps {
|
|
7
|
+
queueName?: string;
|
|
8
|
+
batchSize?: number;
|
|
9
|
+
maxBatchingWindow?: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const LambdaSqs = Composite<LambdaSqsProps>((props) => {
|
|
13
|
+
const queue = new Queue({
|
|
14
|
+
QueueName: props.queueName,
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const sqsPolicyDocument = {
|
|
18
|
+
Version: "2012-10-17",
|
|
19
|
+
Statement: [
|
|
20
|
+
{
|
|
21
|
+
Effect: "Allow",
|
|
22
|
+
Action: SQSActions.ReceiveMessage,
|
|
23
|
+
Resource: queue.Arn,
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const sqsPolicy = new Role_Policy({
|
|
29
|
+
PolicyName: "SQSReceive",
|
|
30
|
+
PolicyDocument: sqsPolicyDocument,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const policies = props.Policies ? [sqsPolicy, ...props.Policies] : [sqsPolicy];
|
|
34
|
+
const { role, func } = LambdaFunction({ ...props, Policies: policies });
|
|
35
|
+
|
|
36
|
+
new EventSourceMapping({
|
|
37
|
+
EventSourceArn: queue.Arn,
|
|
38
|
+
FunctionName: func.Arn,
|
|
39
|
+
BatchSize: props.batchSize ?? 10,
|
|
40
|
+
MaximumBatchingWindowInSeconds: props.maxBatchingWindow,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
return { queue, role, func };
|
|
44
|
+
}, "LambdaSqs");
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Composite } from "@intentius/chant";
|
|
2
|
+
import { EventRule, EventRule_Target, Permission } from "../generated";
|
|
3
|
+
import { LambdaFunction, type LambdaFunctionProps } from "./lambda-function";
|
|
4
|
+
|
|
5
|
+
export interface ScheduledLambdaProps extends LambdaFunctionProps {
|
|
6
|
+
ruleName?: string;
|
|
7
|
+
schedule: string;
|
|
8
|
+
enabled?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const LambdaScheduled = Composite<ScheduledLambdaProps>((props) => {
|
|
12
|
+
const { role, func } = LambdaFunction(props);
|
|
13
|
+
|
|
14
|
+
const rule = new EventRule({
|
|
15
|
+
Name: props.ruleName,
|
|
16
|
+
ScheduleExpression: props.schedule,
|
|
17
|
+
State: (props.enabled ?? true) ? "ENABLED" : "DISABLED",
|
|
18
|
+
Targets: [
|
|
19
|
+
new EventRule_Target({
|
|
20
|
+
Arn: func.Arn,
|
|
21
|
+
Id: "Target0",
|
|
22
|
+
}),
|
|
23
|
+
],
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const permission = new Permission({
|
|
27
|
+
FunctionName: func.Arn,
|
|
28
|
+
Action: "lambda:InvokeFunction",
|
|
29
|
+
Principal: "events.amazonaws.com",
|
|
30
|
+
SourceArn: rule.Arn,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
return { role, func, rule, permission };
|
|
34
|
+
}, "LambdaScheduled");
|
|
35
|
+
|
|
36
|
+
/** @deprecated Use `LambdaScheduled` instead */
|
|
37
|
+
export const ScheduledLambda = LambdaScheduled;
|