@quiltdata/benchling-webhook 0.8.8 → 0.8.9-20251130T212657Z
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/README.md +110 -0
- package/dist/bin/benchling-webhook.js +6 -0
- package/dist/bin/benchling-webhook.js.map +1 -1
- package/dist/bin/cli.js +37 -2
- package/dist/bin/cli.js.map +1 -1
- package/dist/bin/commands/deploy.d.ts +2 -0
- package/dist/bin/commands/deploy.d.ts.map +1 -1
- package/dist/bin/commands/deploy.js +122 -2
- package/dist/bin/commands/deploy.js.map +1 -1
- package/dist/bin/commands/destroy.d.ts +16 -0
- package/dist/bin/commands/destroy.d.ts.map +1 -0
- package/dist/bin/commands/destroy.js +258 -0
- package/dist/bin/commands/destroy.js.map +1 -0
- package/dist/bin/commands/infer-quilt-config.d.ts.map +1 -1
- package/dist/bin/commands/infer-quilt-config.js +13 -8
- package/dist/bin/commands/infer-quilt-config.js.map +1 -1
- package/dist/bin/commands/logs.d.ts.map +1 -1
- package/dist/bin/commands/logs.js +29 -6
- package/dist/bin/commands/logs.js.map +1 -1
- package/dist/bin/commands/setup-profile.d.ts +1 -1
- package/dist/bin/commands/setup-profile.d.ts.map +1 -1
- package/dist/bin/commands/setup-profile.js +46 -1
- package/dist/bin/commands/setup-profile.js.map +1 -1
- package/dist/bin/commands/status.d.ts +17 -0
- package/dist/bin/commands/status.d.ts.map +1 -1
- package/dist/bin/commands/status.js +186 -35
- package/dist/bin/commands/status.js.map +1 -1
- package/dist/bin/commands/sync-secrets.d.ts +1 -1
- package/dist/bin/commands/sync-secrets.js +1 -1
- package/dist/bin/xdg-launch.d.ts +1 -1
- package/dist/bin/xdg-launch.d.ts.map +1 -1
- package/dist/bin/xdg-launch.js +105 -26
- package/dist/bin/xdg-launch.js.map +1 -1
- package/dist/lib/benchling-webhook-stack.d.ts +1 -1
- package/dist/lib/benchling-webhook-stack.d.ts.map +1 -1
- package/dist/lib/benchling-webhook-stack.js +83 -17
- package/dist/lib/benchling-webhook-stack.js.map +1 -1
- package/dist/lib/configuration-saver.d.ts +1 -1
- package/dist/lib/configuration-saver.d.ts.map +1 -1
- package/dist/lib/configuration-saver.js +4 -5
- package/dist/lib/configuration-saver.js.map +1 -1
- package/dist/lib/constants.d.ts +5 -0
- package/dist/lib/constants.d.ts.map +1 -1
- package/dist/lib/constants.js +6 -1
- package/dist/lib/constants.js.map +1 -1
- package/dist/lib/fargate-service.d.ts +4 -5
- package/dist/lib/fargate-service.d.ts.map +1 -1
- package/dist/lib/fargate-service.js +14 -59
- package/dist/lib/fargate-service.js.map +1 -1
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +3 -3
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/network-load-balancer.d.ts +27 -0
- package/dist/lib/network-load-balancer.d.ts.map +1 -0
- package/dist/lib/network-load-balancer.js +109 -0
- package/dist/lib/network-load-balancer.js.map +1 -0
- package/dist/lib/rest-api-gateway.d.ts +22 -0
- package/dist/lib/rest-api-gateway.d.ts.map +1 -0
- package/dist/lib/rest-api-gateway.js +221 -0
- package/dist/lib/rest-api-gateway.js.map +1 -0
- package/dist/lib/types/config.d.ts +53 -8
- package/dist/lib/types/config.d.ts.map +1 -1
- package/dist/lib/types/config.js +1 -1
- package/dist/lib/types/config.js.map +1 -1
- package/dist/lib/utils/service-resolver.d.ts +1 -1
- package/dist/lib/utils/service-resolver.js +1 -1
- package/dist/lib/wizard/phase2-stack-query.d.ts.map +1 -1
- package/dist/lib/wizard/phase2-stack-query.js +57 -14
- package/dist/lib/wizard/phase2-stack-query.js.map +1 -1
- package/dist/lib/wizard/phase3-parameter-collection.d.ts.map +1 -1
- package/dist/lib/wizard/phase3-parameter-collection.js +55 -1
- package/dist/lib/wizard/phase3-parameter-collection.js.map +1 -1
- package/dist/lib/wizard/phase6-integrated-mode.d.ts.map +1 -1
- package/dist/lib/wizard/phase6-integrated-mode.js +3 -1
- package/dist/lib/wizard/phase6-integrated-mode.js.map +1 -1
- package/dist/lib/wizard/phase7-standalone-mode.d.ts.map +1 -1
- package/dist/lib/wizard/phase7-standalone-mode.js +3 -1
- package/dist/lib/wizard/phase7-standalone-mode.js.map +1 -1
- package/dist/lib/wizard/types.d.ts +24 -0
- package/dist/lib/wizard/types.d.ts.map +1 -1
- package/dist/lib/xdg-base.d.ts +17 -1
- package/dist/lib/xdg-base.d.ts.map +1 -1
- package/dist/lib/xdg-base.js +30 -1
- package/dist/lib/xdg-base.js.map +1 -1
- package/dist/lib/xdg-config.d.ts +1 -1
- package/dist/lib/xdg-config.js +1 -1
- package/dist/package.json +6 -3
- package/dist/scripts/discover-vpc.d.ts +69 -0
- package/dist/scripts/discover-vpc.d.ts.map +1 -0
- package/dist/scripts/discover-vpc.js +196 -0
- package/dist/scripts/discover-vpc.js.map +1 -0
- package/package.json +6 -3
- package/dist/lib/alb-api-gateway.d.ts +0 -23
- package/dist/lib/alb-api-gateway.d.ts.map +0 -1
- package/dist/lib/alb-api-gateway.js +0 -211
- package/dist/lib/alb-api-gateway.js.map +0 -1
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quiltdata/benchling-webhook",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.9-20251130T212657Z",
|
|
4
4
|
"description": "AWS CDK deployment for Benchling webhook processing using Fargate - Deploy directly with npx",
|
|
5
5
|
"main": "dist/lib/index.js",
|
|
6
6
|
"types": "dist/lib/index.d.ts",
|
|
@@ -21,6 +21,9 @@
|
|
|
21
21
|
"deploy:dev": "ts-node bin/cli.ts deploy --stage dev --profile dev",
|
|
22
22
|
"deploy:prod": "ts-node bin/cli.ts deploy --stage prod",
|
|
23
23
|
"deploy:notes": "bash scripts/release-notes.sh",
|
|
24
|
+
"destroy": "ts-node bin/cli.ts destroy",
|
|
25
|
+
"destroy:dev": "ts-node bin/cli.ts destroy --stage dev --profile dev",
|
|
26
|
+
"destroy:prod": "ts-node bin/cli.ts destroy --stage prod",
|
|
24
27
|
"launch": "ts-node bin/xdg-launch.ts",
|
|
25
28
|
"dev": "npm run launch -- --mode native --profile dev --verbose",
|
|
26
29
|
"dev:docker": "npm run launch -- --mode docker-dev --profile dev --verbose",
|
|
@@ -74,7 +77,6 @@
|
|
|
74
77
|
"devDependencies": {
|
|
75
78
|
"@eslint/js": "^9.22.0",
|
|
76
79
|
"@types/adm-zip": "^0.5.7",
|
|
77
|
-
"@types/aws-lambda": "^8.10.156",
|
|
78
80
|
"@types/jest": "^30.0.0",
|
|
79
81
|
"@types/node": "^24.0.0",
|
|
80
82
|
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
|
@@ -94,6 +96,7 @@
|
|
|
94
96
|
"dependencies": {
|
|
95
97
|
"@aws-sdk/client-cloudformation": "^3.920.0",
|
|
96
98
|
"@aws-sdk/client-cloudwatch-logs": "^3.933.0",
|
|
99
|
+
"@aws-sdk/client-ec2": "^3.940.0",
|
|
97
100
|
"@aws-sdk/client-ecs": "^3.933.0",
|
|
98
101
|
"@aws-sdk/client-elastic-load-balancing-v2": "^3.932.0",
|
|
99
102
|
"@aws-sdk/client-s3": "^3.758.0",
|
|
@@ -105,7 +108,7 @@
|
|
|
105
108
|
"adm-zip": "^0.5.10",
|
|
106
109
|
"ajv": "^8.17.1",
|
|
107
110
|
"ajv-formats": "^3.0.1",
|
|
108
|
-
"aws-cdk-lib": "2.
|
|
111
|
+
"aws-cdk-lib": "2.230.0",
|
|
109
112
|
"boxen": "^8.0.0",
|
|
110
113
|
"chalk": "^5.0.0",
|
|
111
114
|
"commander": "^14.0.2",
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VPC Discovery Module
|
|
3
|
+
*
|
|
4
|
+
* Discovers VPC resources from Quilt CloudFormation stack and validates
|
|
5
|
+
* them against architecture requirements.
|
|
6
|
+
*
|
|
7
|
+
* @module scripts/discover-vpc
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* VPC discovery options
|
|
11
|
+
*/
|
|
12
|
+
export interface VpcDiscoveryOptions {
|
|
13
|
+
/** CloudFormation stack ARN */
|
|
14
|
+
stackArn: string;
|
|
15
|
+
/** AWS region */
|
|
16
|
+
region: string;
|
|
17
|
+
/** AWS profile to use (optional) */
|
|
18
|
+
awsProfile?: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Discovered subnet information
|
|
22
|
+
*/
|
|
23
|
+
export interface DiscoveredSubnet {
|
|
24
|
+
/** Subnet ID */
|
|
25
|
+
subnetId: string;
|
|
26
|
+
/** Availability zone */
|
|
27
|
+
availabilityZone: string;
|
|
28
|
+
/** CIDR block */
|
|
29
|
+
cidrBlock: string;
|
|
30
|
+
/** Whether subnet is public (has IGW route) */
|
|
31
|
+
isPublic: boolean;
|
|
32
|
+
/** Whether subnet has NAT Gateway in route table */
|
|
33
|
+
hasNatGateway: boolean;
|
|
34
|
+
/** Subnet name from tags */
|
|
35
|
+
name?: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Discovered VPC information
|
|
39
|
+
*/
|
|
40
|
+
export interface DiscoveredVpc {
|
|
41
|
+
/** VPC ID */
|
|
42
|
+
vpcId: string;
|
|
43
|
+
/** VPC name from tags */
|
|
44
|
+
name?: string;
|
|
45
|
+
/** CIDR block */
|
|
46
|
+
cidrBlock: string;
|
|
47
|
+
/** AWS region */
|
|
48
|
+
region: string;
|
|
49
|
+
/** Subnets in VPC */
|
|
50
|
+
subnets: DiscoveredSubnet[];
|
|
51
|
+
/** Security group IDs */
|
|
52
|
+
securityGroups: string[];
|
|
53
|
+
/** Whether VPC meets architecture requirements */
|
|
54
|
+
isValid: boolean;
|
|
55
|
+
/** Validation error messages */
|
|
56
|
+
validationErrors: string[];
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Discovers VPC resources from CloudFormation stack
|
|
60
|
+
*
|
|
61
|
+
* Quilt stacks don't create their own VPC - they use existing VPCs.
|
|
62
|
+
* We discover the VPC by looking at the OutboundSecurityGroup output,
|
|
63
|
+
* which references the VPC used by the stack.
|
|
64
|
+
*
|
|
65
|
+
* @param options - Discovery options
|
|
66
|
+
* @returns Discovered VPC or null if not found
|
|
67
|
+
*/
|
|
68
|
+
export declare function discoverVpcFromStack(options: VpcDiscoveryOptions): Promise<DiscoveredVpc | null>;
|
|
69
|
+
//# sourceMappingURL=discover-vpc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discover-vpc.d.ts","sourceRoot":"","sources":["../../scripts/discover-vpc.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAcH;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAChC,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,oCAAoC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC7B,gBAAgB;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,wBAAwB;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,+CAA+C;IAC/C,QAAQ,EAAE,OAAO,CAAC;IAClB,oDAAoD;IACpD,aAAa,EAAE,OAAO,CAAC;IACvB,4BAA4B;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC1B,aAAa;IACb,KAAK,EAAE,MAAM,CAAC;IACd,yBAAyB;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iBAAiB;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,yBAAyB;IACzB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,kDAAkD;IAClD,OAAO,EAAE,OAAO,CAAC;IACjB,gCAAgC;IAChC,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC9B;AAcD;;;;;;;;;GASG;AACH,wBAAsB,oBAAoB,CACtC,OAAO,EAAE,mBAAmB,GAC7B,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAsK/B"}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* VPC Discovery Module
|
|
4
|
+
*
|
|
5
|
+
* Discovers VPC resources from Quilt CloudFormation stack and validates
|
|
6
|
+
* them against architecture requirements.
|
|
7
|
+
*
|
|
8
|
+
* @module scripts/discover-vpc
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.discoverVpcFromStack = discoverVpcFromStack;
|
|
12
|
+
const client_cloudformation_1 = require("@aws-sdk/client-cloudformation");
|
|
13
|
+
const client_ec2_1 = require("@aws-sdk/client-ec2");
|
|
14
|
+
/**
|
|
15
|
+
* Extracts stack name from ARN
|
|
16
|
+
*/
|
|
17
|
+
function extractStackNameFromArn(arn) {
|
|
18
|
+
// ARN format: arn:aws:cloudformation:region:account:stack/stack-name/guid
|
|
19
|
+
const parts = arn.split("/");
|
|
20
|
+
if (parts.length >= 2) {
|
|
21
|
+
return parts[1];
|
|
22
|
+
}
|
|
23
|
+
throw new Error(`Invalid stack ARN format: ${arn}`);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Discovers VPC resources from CloudFormation stack
|
|
27
|
+
*
|
|
28
|
+
* Quilt stacks don't create their own VPC - they use existing VPCs.
|
|
29
|
+
* We discover the VPC by looking at the OutboundSecurityGroup output,
|
|
30
|
+
* which references the VPC used by the stack.
|
|
31
|
+
*
|
|
32
|
+
* @param options - Discovery options
|
|
33
|
+
* @returns Discovered VPC or null if not found
|
|
34
|
+
*/
|
|
35
|
+
async function discoverVpcFromStack(options) {
|
|
36
|
+
const { stackArn, region } = options;
|
|
37
|
+
// Initialize AWS clients
|
|
38
|
+
const cfnConfig = { region };
|
|
39
|
+
const ec2Config = { region };
|
|
40
|
+
const cfnClient = new client_cloudformation_1.CloudFormationClient(cfnConfig);
|
|
41
|
+
const ec2Client = new client_ec2_1.EC2Client(ec2Config);
|
|
42
|
+
try {
|
|
43
|
+
// Step 1: Get OutboundSecurityGroup from stack outputs
|
|
44
|
+
const stackName = extractStackNameFromArn(stackArn);
|
|
45
|
+
const describeStacksCmd = new client_cloudformation_1.DescribeStacksCommand({
|
|
46
|
+
StackName: stackName,
|
|
47
|
+
});
|
|
48
|
+
const stacksResponse = await cfnClient.send(describeStacksCmd);
|
|
49
|
+
const stack = stacksResponse.Stacks?.[0];
|
|
50
|
+
if (!stack) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
// Find OutboundSecurityGroup output
|
|
54
|
+
const outboundSgOutput = stack.Outputs?.find((o) => o.OutputKey === "OutboundSecurityGroup");
|
|
55
|
+
if (!outboundSgOutput || !outboundSgOutput.OutputValue) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
const securityGroupId = outboundSgOutput.OutputValue;
|
|
59
|
+
// Step 2: Get VPC ID from security group
|
|
60
|
+
const sgDetailsCmd = new client_ec2_1.DescribeSecurityGroupsCommand({
|
|
61
|
+
GroupIds: [securityGroupId],
|
|
62
|
+
});
|
|
63
|
+
const sgDetailsResponse = await ec2Client.send(sgDetailsCmd);
|
|
64
|
+
const securityGroup = sgDetailsResponse.SecurityGroups?.[0];
|
|
65
|
+
if (!securityGroup || !securityGroup.VpcId) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
const vpcId = securityGroup.VpcId;
|
|
69
|
+
// Step 3: Enrich VPC metadata via EC2 API
|
|
70
|
+
const vpcDetailsCmd = new client_ec2_1.DescribeVpcsCommand({
|
|
71
|
+
VpcIds: [vpcId],
|
|
72
|
+
});
|
|
73
|
+
const vpcDetailsResponse = await ec2Client.send(vpcDetailsCmd);
|
|
74
|
+
const vpcDetails = vpcDetailsResponse.Vpcs?.[0];
|
|
75
|
+
if (!vpcDetails) {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
const vpcName = vpcDetails.Tags?.find((t) => t.Key === "Name")?.Value;
|
|
79
|
+
const cidrBlock = vpcDetails.CidrBlock || "";
|
|
80
|
+
// Step 4: Get subnet details
|
|
81
|
+
const subnetsCmd = new client_ec2_1.DescribeSubnetsCommand({
|
|
82
|
+
Filters: [
|
|
83
|
+
{
|
|
84
|
+
Name: "vpc-id",
|
|
85
|
+
Values: [vpcId],
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
});
|
|
89
|
+
const subnetsResponse = await ec2Client.send(subnetsCmd);
|
|
90
|
+
const ec2Subnets = subnetsResponse.Subnets || [];
|
|
91
|
+
// Step 5: Get route tables to determine subnet types
|
|
92
|
+
const routeTablesCmd = new client_ec2_1.DescribeRouteTablesCommand({
|
|
93
|
+
Filters: [
|
|
94
|
+
{
|
|
95
|
+
Name: "vpc-id",
|
|
96
|
+
Values: [vpcId],
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
});
|
|
100
|
+
const routeTablesResponse = await ec2Client.send(routeTablesCmd);
|
|
101
|
+
const routeTables = routeTablesResponse.RouteTables || [];
|
|
102
|
+
// Build map of subnet -> route table -> NAT/IGW status
|
|
103
|
+
const subnetRouteMap = new Map();
|
|
104
|
+
for (const routeTable of routeTables) {
|
|
105
|
+
// Check if route table has IGW or NAT Gateway
|
|
106
|
+
const hasIgw = routeTable.Routes?.some((r) => r.GatewayId?.startsWith("igw-"));
|
|
107
|
+
const hasNat = routeTable.Routes?.some((r) => r.NatGatewayId?.startsWith("nat-"));
|
|
108
|
+
// Map subnets to this route table
|
|
109
|
+
const subnetIds = routeTable.Associations?.map((a) => a.SubnetId).filter((id) => !!id) || [];
|
|
110
|
+
for (const subnetId of subnetIds) {
|
|
111
|
+
subnetRouteMap.set(subnetId, {
|
|
112
|
+
isPublic: !!hasIgw,
|
|
113
|
+
hasNatGateway: !!hasNat,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// Build discovered subnets
|
|
118
|
+
const subnets = ec2Subnets.map((subnet) => {
|
|
119
|
+
const subnetId = subnet.SubnetId || "";
|
|
120
|
+
const routeInfo = subnetRouteMap.get(subnetId) || {
|
|
121
|
+
isPublic: false,
|
|
122
|
+
hasNatGateway: false,
|
|
123
|
+
};
|
|
124
|
+
const name = subnet.Tags?.find((t) => t.Key === "Name")?.Value;
|
|
125
|
+
return {
|
|
126
|
+
subnetId,
|
|
127
|
+
availabilityZone: subnet.AvailabilityZone || "",
|
|
128
|
+
cidrBlock: subnet.CidrBlock || "",
|
|
129
|
+
isPublic: routeInfo.isPublic,
|
|
130
|
+
hasNatGateway: routeInfo.hasNatGateway,
|
|
131
|
+
name,
|
|
132
|
+
};
|
|
133
|
+
});
|
|
134
|
+
// Step 6: Get security groups
|
|
135
|
+
const securityGroupsCmd = new client_ec2_1.DescribeSecurityGroupsCommand({
|
|
136
|
+
Filters: [
|
|
137
|
+
{
|
|
138
|
+
Name: "vpc-id",
|
|
139
|
+
Values: [vpcId],
|
|
140
|
+
},
|
|
141
|
+
],
|
|
142
|
+
});
|
|
143
|
+
const securityGroupsResponse = await ec2Client.send(securityGroupsCmd);
|
|
144
|
+
const securityGroups = (securityGroupsResponse.SecurityGroups || [])
|
|
145
|
+
.map((sg) => sg.GroupId)
|
|
146
|
+
.filter((id) => !!id);
|
|
147
|
+
// Step 7: Build discovered VPC
|
|
148
|
+
const discoveredVpc = {
|
|
149
|
+
vpcId,
|
|
150
|
+
name: vpcName,
|
|
151
|
+
cidrBlock,
|
|
152
|
+
region,
|
|
153
|
+
subnets,
|
|
154
|
+
securityGroups,
|
|
155
|
+
isValid: false,
|
|
156
|
+
validationErrors: [],
|
|
157
|
+
};
|
|
158
|
+
// Step 8: Validate VPC
|
|
159
|
+
validateVpc(discoveredVpc);
|
|
160
|
+
return discoveredVpc;
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
const err = error;
|
|
164
|
+
throw new Error(`VPC discovery failed: ${err.message}`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Validates VPC meets architecture requirements
|
|
169
|
+
*
|
|
170
|
+
* Requirements:
|
|
171
|
+
* - Must have ≥2 private subnets in different AZs
|
|
172
|
+
* - Private subnets must have NAT Gateway for outbound access
|
|
173
|
+
*
|
|
174
|
+
* @param vpc - Discovered VPC to validate
|
|
175
|
+
*/
|
|
176
|
+
function validateVpc(vpc) {
|
|
177
|
+
const errors = [];
|
|
178
|
+
// Check private subnets
|
|
179
|
+
const privateSubnets = vpc.subnets.filter((s) => !s.isPublic);
|
|
180
|
+
if (privateSubnets.length < 2) {
|
|
181
|
+
errors.push(`Insufficient private subnets (found ${privateSubnets.length}, need ≥2)`);
|
|
182
|
+
}
|
|
183
|
+
// Check AZ distribution
|
|
184
|
+
const azs = new Set(privateSubnets.map((s) => s.availabilityZone));
|
|
185
|
+
if (azs.size < 2) {
|
|
186
|
+
errors.push(`Private subnets span only ${azs.size} AZ(s) (need ≥2 for high availability)`);
|
|
187
|
+
}
|
|
188
|
+
// Check NAT Gateway
|
|
189
|
+
const hasNat = vpc.subnets.some((s) => s.hasNatGateway);
|
|
190
|
+
if (!hasNat) {
|
|
191
|
+
errors.push("No NAT Gateway configured (required for ECS outbound access)");
|
|
192
|
+
}
|
|
193
|
+
vpc.isValid = errors.length === 0;
|
|
194
|
+
vpc.validationErrors = errors;
|
|
195
|
+
}
|
|
196
|
+
//# sourceMappingURL=discover-vpc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discover-vpc.js","sourceRoot":"","sources":["../../scripts/discover-vpc.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quiltdata/benchling-webhook",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.9-20251130T212657Z",
|
|
4
4
|
"description": "AWS CDK deployment for Benchling webhook processing using Fargate - Deploy directly with npx",
|
|
5
5
|
"main": "dist/lib/index.js",
|
|
6
6
|
"types": "dist/lib/index.d.ts",
|
|
@@ -21,6 +21,9 @@
|
|
|
21
21
|
"deploy:dev": "ts-node bin/cli.ts deploy --stage dev --profile dev",
|
|
22
22
|
"deploy:prod": "ts-node bin/cli.ts deploy --stage prod",
|
|
23
23
|
"deploy:notes": "bash scripts/release-notes.sh",
|
|
24
|
+
"destroy": "ts-node bin/cli.ts destroy",
|
|
25
|
+
"destroy:dev": "ts-node bin/cli.ts destroy --stage dev --profile dev",
|
|
26
|
+
"destroy:prod": "ts-node bin/cli.ts destroy --stage prod",
|
|
24
27
|
"launch": "ts-node bin/xdg-launch.ts",
|
|
25
28
|
"dev": "npm run launch -- --mode native --profile dev --verbose",
|
|
26
29
|
"dev:docker": "npm run launch -- --mode docker-dev --profile dev --verbose",
|
|
@@ -74,7 +77,6 @@
|
|
|
74
77
|
"devDependencies": {
|
|
75
78
|
"@eslint/js": "^9.22.0",
|
|
76
79
|
"@types/adm-zip": "^0.5.7",
|
|
77
|
-
"@types/aws-lambda": "^8.10.156",
|
|
78
80
|
"@types/jest": "^30.0.0",
|
|
79
81
|
"@types/node": "^24.0.0",
|
|
80
82
|
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
|
@@ -94,6 +96,7 @@
|
|
|
94
96
|
"dependencies": {
|
|
95
97
|
"@aws-sdk/client-cloudformation": "^3.920.0",
|
|
96
98
|
"@aws-sdk/client-cloudwatch-logs": "^3.933.0",
|
|
99
|
+
"@aws-sdk/client-ec2": "^3.940.0",
|
|
97
100
|
"@aws-sdk/client-ecs": "^3.933.0",
|
|
98
101
|
"@aws-sdk/client-elastic-load-balancing-v2": "^3.932.0",
|
|
99
102
|
"@aws-sdk/client-s3": "^3.758.0",
|
|
@@ -105,7 +108,7 @@
|
|
|
105
108
|
"adm-zip": "^0.5.10",
|
|
106
109
|
"ajv": "^8.17.1",
|
|
107
110
|
"ajv-formats": "^3.0.1",
|
|
108
|
-
"aws-cdk-lib": "2.
|
|
111
|
+
"aws-cdk-lib": "2.230.0",
|
|
109
112
|
"boxen": "^8.0.0",
|
|
110
113
|
"chalk": "^5.0.0",
|
|
111
114
|
"commander": "^14.0.2",
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import * as apigateway from "aws-cdk-lib/aws-apigateway";
|
|
2
|
-
import * as logs from "aws-cdk-lib/aws-logs";
|
|
3
|
-
import * as elbv2 from "aws-cdk-lib/aws-elasticloadbalancingv2";
|
|
4
|
-
import { Construct } from "constructs";
|
|
5
|
-
import { ProfileConfig } from "./types/config";
|
|
6
|
-
/**
|
|
7
|
-
* Properties for AlbApiGateway construct (v0.7.0+)
|
|
8
|
-
*
|
|
9
|
-
* Uses ProfileConfig to access security settings like webhook allow list.
|
|
10
|
-
*/
|
|
11
|
-
export interface AlbApiGatewayProps {
|
|
12
|
-
readonly loadBalancer: elbv2.ApplicationLoadBalancer;
|
|
13
|
-
readonly config: ProfileConfig;
|
|
14
|
-
}
|
|
15
|
-
export declare class AlbApiGateway {
|
|
16
|
-
readonly api: apigateway.RestApi;
|
|
17
|
-
readonly logGroup: logs.ILogGroup;
|
|
18
|
-
constructor(scope: Construct, id: string, props: AlbApiGatewayProps);
|
|
19
|
-
private createResourcePolicy;
|
|
20
|
-
private createCloudWatchRole;
|
|
21
|
-
private addWebhookEndpoints;
|
|
22
|
-
}
|
|
23
|
-
//# sourceMappingURL=alb-api-gateway.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"alb-api-gateway.d.ts","sourceRoot":"","sources":["../../lib/alb-api-gateway.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,UAAU,MAAM,4BAA4B,CAAC;AAEzD,OAAO,KAAK,IAAI,MAAM,sBAAsB,CAAC;AAC7C,OAAO,KAAK,KAAK,MAAM,wCAAwC,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE/C;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IAC/B,QAAQ,CAAC,YAAY,EAAE,KAAK,CAAC,uBAAuB,CAAC;IACrD,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;CAClC;AAED,qBAAa,aAAa;IACtB,SAAgB,GAAG,EAAE,UAAU,CAAC,OAAO,CAAC;IACxC,SAAgB,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC;gBAGrC,KAAK,EAAE,SAAS,EAChB,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,kBAAkB;IA0E7B,OAAO,CAAC,oBAAoB;IAwC5B,OAAO,CAAC,oBAAoB;IAiB5B,OAAO,CAAC,mBAAmB;CAqE9B"}
|
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.AlbApiGateway = void 0;
|
|
37
|
-
const cdk = __importStar(require("aws-cdk-lib"));
|
|
38
|
-
const apigateway = __importStar(require("aws-cdk-lib/aws-apigateway"));
|
|
39
|
-
const iam = __importStar(require("aws-cdk-lib/aws-iam"));
|
|
40
|
-
const logs = __importStar(require("aws-cdk-lib/aws-logs"));
|
|
41
|
-
class AlbApiGateway {
|
|
42
|
-
constructor(scope, id, props) {
|
|
43
|
-
const { config } = props;
|
|
44
|
-
this.logGroup = new logs.LogGroup(scope, "ApiGatewayAccessLogs", {
|
|
45
|
-
logGroupName: "/aws/apigateway/benchling-webhook",
|
|
46
|
-
retention: logs.RetentionDays.ONE_WEEK,
|
|
47
|
-
removalPolicy: cdk.RemovalPolicy.DESTROY,
|
|
48
|
-
});
|
|
49
|
-
this.createCloudWatchRole(scope);
|
|
50
|
-
// Get webhook allow list from config
|
|
51
|
-
const webhookAllowList = config.security?.webhookAllowList || "";
|
|
52
|
-
// Parse IP allowlist for resource policy
|
|
53
|
-
let allowedIps = undefined;
|
|
54
|
-
if (webhookAllowList) {
|
|
55
|
-
if (cdk.Token.isUnresolved(webhookAllowList)) {
|
|
56
|
-
// For CDK tokens (parameters), we can't evaluate at synth time
|
|
57
|
-
// Split and let CloudFormation handle it
|
|
58
|
-
allowedIps = cdk.Fn.split(",", webhookAllowList);
|
|
59
|
-
}
|
|
60
|
-
else if (webhookAllowList.trim() !== "") {
|
|
61
|
-
// For concrete values, parse and filter
|
|
62
|
-
const parsed = webhookAllowList
|
|
63
|
-
.split(",")
|
|
64
|
-
.map(ip => ip.trim())
|
|
65
|
-
.filter(ip => ip.length > 0);
|
|
66
|
-
if (parsed.length > 0) {
|
|
67
|
-
allowedIps = parsed;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
// Create resource policy for IP filtering at the edge
|
|
72
|
-
// Only create policy if we have IPs and they're not from an empty parameter
|
|
73
|
-
const policyDocument = this.createResourcePolicy(allowedIps, webhookAllowList);
|
|
74
|
-
this.api = new apigateway.RestApi(scope, "BenchlingWebhookAPI", {
|
|
75
|
-
restApiName: "BenchlingWebhookAPI",
|
|
76
|
-
policy: policyDocument,
|
|
77
|
-
deployOptions: {
|
|
78
|
-
stageName: "prod",
|
|
79
|
-
accessLogDestination: new apigateway.LogGroupLogDestination(this.logGroup),
|
|
80
|
-
methodOptions: {
|
|
81
|
-
"/*/*": {
|
|
82
|
-
loggingLevel: apigateway.MethodLoggingLevel.INFO,
|
|
83
|
-
dataTraceEnabled: true,
|
|
84
|
-
},
|
|
85
|
-
},
|
|
86
|
-
},
|
|
87
|
-
});
|
|
88
|
-
this.addWebhookEndpoints(props.loadBalancer);
|
|
89
|
-
// Output API Gateway ID for execution logs
|
|
90
|
-
new cdk.CfnOutput(scope, "ApiGatewayId", {
|
|
91
|
-
value: this.api.restApiId,
|
|
92
|
-
description: "API Gateway REST API ID",
|
|
93
|
-
});
|
|
94
|
-
// Output execution log group name
|
|
95
|
-
new cdk.CfnOutput(scope, "ApiGatewayExecutionLogGroup", {
|
|
96
|
-
value: `API-Gateway-Execution-Logs_${this.api.restApiId}/prod`,
|
|
97
|
-
description: "API Gateway execution log group for detailed request/response logs",
|
|
98
|
-
});
|
|
99
|
-
// Output ALB DNS for direct testing
|
|
100
|
-
new cdk.CfnOutput(scope, "LoadBalancerDNS", {
|
|
101
|
-
value: props.loadBalancer.loadBalancerDnsName,
|
|
102
|
-
description: "Application Load Balancer DNS name for direct testing",
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
createResourcePolicy(allowedIps, rawParameter) {
|
|
106
|
-
// Don't create policy if no IPs provided
|
|
107
|
-
if (!allowedIps) {
|
|
108
|
-
return undefined;
|
|
109
|
-
}
|
|
110
|
-
// Don't create policy for empty arrays
|
|
111
|
-
if (Array.isArray(allowedIps) && allowedIps.length === 0) {
|
|
112
|
-
return undefined;
|
|
113
|
-
}
|
|
114
|
-
// For CDK tokens (CloudFormation parameters), we can't evaluate at synth time
|
|
115
|
-
// Don't create policy for parameters since we can't conditionally apply them
|
|
116
|
-
// API Gateway doesn't support conditional policies, so we skip the policy entirely
|
|
117
|
-
// when using parameters. This means WebhookAllowList parameter won't work for
|
|
118
|
-
// runtime IP filtering - IPs must be set at deployment time.
|
|
119
|
-
if (rawParameter && cdk.Token.isUnresolved(rawParameter)) {
|
|
120
|
-
return undefined;
|
|
121
|
-
}
|
|
122
|
-
return new iam.PolicyDocument({
|
|
123
|
-
statements: [
|
|
124
|
-
new iam.PolicyStatement({
|
|
125
|
-
effect: iam.Effect.ALLOW,
|
|
126
|
-
principals: [new iam.AnyPrincipal()],
|
|
127
|
-
actions: ["execute-api:Invoke"],
|
|
128
|
-
resources: ["execute-api:/*"],
|
|
129
|
-
conditions: {
|
|
130
|
-
IpAddress: {
|
|
131
|
-
"aws:SourceIp": allowedIps,
|
|
132
|
-
},
|
|
133
|
-
},
|
|
134
|
-
}),
|
|
135
|
-
],
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
createCloudWatchRole(scope) {
|
|
139
|
-
const cloudWatchRole = new iam.Role(scope, "ApiGatewayCloudWatchRole", {
|
|
140
|
-
assumedBy: new iam.ServicePrincipal("apigateway.amazonaws.com"),
|
|
141
|
-
managedPolicies: [
|
|
142
|
-
iam.ManagedPolicy.fromAwsManagedPolicyName("service-role/AmazonAPIGatewayPushToCloudWatchLogs"),
|
|
143
|
-
],
|
|
144
|
-
});
|
|
145
|
-
new apigateway.CfnAccount(scope, "ApiGatewayAccount", {
|
|
146
|
-
cloudWatchRoleArn: cloudWatchRole.roleArn,
|
|
147
|
-
});
|
|
148
|
-
return cloudWatchRole;
|
|
149
|
-
}
|
|
150
|
-
addWebhookEndpoints(loadBalancer) {
|
|
151
|
-
// Create HTTP integration to ALB
|
|
152
|
-
const albIntegration = new apigateway.HttpIntegration(`http://${loadBalancer.loadBalancerDnsName}/{proxy}`, {
|
|
153
|
-
httpMethod: "ANY",
|
|
154
|
-
options: {
|
|
155
|
-
requestParameters: {
|
|
156
|
-
"integration.request.path.proxy": "method.request.path.proxy",
|
|
157
|
-
},
|
|
158
|
-
integrationResponses: [
|
|
159
|
-
{
|
|
160
|
-
statusCode: "200",
|
|
161
|
-
},
|
|
162
|
-
{
|
|
163
|
-
statusCode: "400",
|
|
164
|
-
selectionPattern: "4\\d{2}",
|
|
165
|
-
},
|
|
166
|
-
{
|
|
167
|
-
statusCode: "500",
|
|
168
|
-
selectionPattern: "5\\d{2}",
|
|
169
|
-
},
|
|
170
|
-
],
|
|
171
|
-
},
|
|
172
|
-
});
|
|
173
|
-
// Create proxy resource to forward all requests to ALB
|
|
174
|
-
const proxyResource = this.api.root.addResource("{proxy+}");
|
|
175
|
-
proxyResource.addMethod("ANY", albIntegration, {
|
|
176
|
-
requestParameters: {
|
|
177
|
-
"method.request.path.proxy": true,
|
|
178
|
-
},
|
|
179
|
-
methodResponses: [
|
|
180
|
-
{ statusCode: "200" },
|
|
181
|
-
{ statusCode: "400" },
|
|
182
|
-
{ statusCode: "500" },
|
|
183
|
-
],
|
|
184
|
-
});
|
|
185
|
-
// Also handle root path
|
|
186
|
-
this.api.root.addMethod("ANY", new apigateway.HttpIntegration(`http://${loadBalancer.loadBalancerDnsName}/`, {
|
|
187
|
-
httpMethod: "ANY",
|
|
188
|
-
options: {
|
|
189
|
-
integrationResponses: [
|
|
190
|
-
{ statusCode: "200" },
|
|
191
|
-
{
|
|
192
|
-
statusCode: "400",
|
|
193
|
-
selectionPattern: "4\\d{2}",
|
|
194
|
-
},
|
|
195
|
-
{
|
|
196
|
-
statusCode: "500",
|
|
197
|
-
selectionPattern: "5\\d{2}",
|
|
198
|
-
},
|
|
199
|
-
],
|
|
200
|
-
},
|
|
201
|
-
}), {
|
|
202
|
-
methodResponses: [
|
|
203
|
-
{ statusCode: "200" },
|
|
204
|
-
{ statusCode: "400" },
|
|
205
|
-
{ statusCode: "500" },
|
|
206
|
-
],
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
exports.AlbApiGateway = AlbApiGateway;
|
|
211
|
-
//# sourceMappingURL=alb-api-gateway.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"alb-api-gateway.js","sourceRoot":"","sources":["../../lib/alb-api-gateway.ts"],"names":[],"mappings":"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"}
|