@standards-kit/conform 0.1.0
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/artifactregistry-QQWBMEQN.js +38 -0
- package/dist/artifactregistry-QQWBMEQN.js.map +1 -0
- package/dist/chunk-J5S6GRGW.js +314 -0
- package/dist/chunk-J5S6GRGW.js.map +1 -0
- package/dist/chunk-KHO6NIAI.js +1367 -0
- package/dist/chunk-KHO6NIAI.js.map +1 -0
- package/dist/chunk-M7G73Q6P.js +662 -0
- package/dist/chunk-M7G73Q6P.js.map +1 -0
- package/dist/chunk-P7TIZJ4C.js +85 -0
- package/dist/chunk-P7TIZJ4C.js.map +1 -0
- package/dist/chunk-RXA4FO7L.js +279 -0
- package/dist/chunk-RXA4FO7L.js.map +1 -0
- package/dist/cli.js +7432 -0
- package/dist/cli.js.map +1 -0
- package/dist/cloudrun-O36R23SH.js +31 -0
- package/dist/cloudrun-O36R23SH.js.map +1 -0
- package/dist/cloudwatch-KSZ4A256.js +56 -0
- package/dist/cloudwatch-KSZ4A256.js.map +1 -0
- package/dist/dynamodb-5KVESCVJ.js +51 -0
- package/dist/dynamodb-5KVESCVJ.js.map +1 -0
- package/dist/ec2-HKPE6GZV.js +151 -0
- package/dist/ec2-HKPE6GZV.js.map +1 -0
- package/dist/ecs-OS3NJZTA.js +141 -0
- package/dist/ecs-OS3NJZTA.js.map +1 -0
- package/dist/elasticache-7TCRHYYM.js +151 -0
- package/dist/elasticache-7TCRHYYM.js.map +1 -0
- package/dist/elb-PEDLXW5R.js +151 -0
- package/dist/elb-PEDLXW5R.js.map +1 -0
- package/dist/generate-D4MFMOHP.js +28 -0
- package/dist/generate-D4MFMOHP.js.map +1 -0
- package/dist/iam-7H5HFWVQ.js +96 -0
- package/dist/iam-7H5HFWVQ.js.map +1 -0
- package/dist/iam-DJI64AGK.js +39 -0
- package/dist/iam-DJI64AGK.js.map +1 -0
- package/dist/index.js +7980 -0
- package/dist/index.js.map +1 -0
- package/dist/infra-UXM5XQX3.js +566 -0
- package/dist/infra-UXM5XQX3.js.map +1 -0
- package/dist/lambda-NFB5UILT.js +60 -0
- package/dist/lambda-NFB5UILT.js.map +1 -0
- package/dist/manifest-7AIL2FK2.js +23 -0
- package/dist/manifest-7AIL2FK2.js.map +1 -0
- package/dist/mcp-O5O7XVFG.js +204 -0
- package/dist/mcp-O5O7XVFG.js.map +1 -0
- package/dist/rds-KLG5O5SI.js +151 -0
- package/dist/rds-KLG5O5SI.js.map +1 -0
- package/dist/registry-V65CC7IN.js +15 -0
- package/dist/registry-V65CC7IN.js.map +1 -0
- package/dist/s3-2DH7PRVR.js +49 -0
- package/dist/s3-2DH7PRVR.js.map +1 -0
- package/dist/scan-EELS42BP.js +593 -0
- package/dist/scan-EELS42BP.js.map +1 -0
- package/dist/secretmanager-RDL62EFW.js +31 -0
- package/dist/secretmanager-RDL62EFW.js.map +1 -0
- package/dist/secretsmanager-MOOIHLAO.js +50 -0
- package/dist/secretsmanager-MOOIHLAO.js.map +1 -0
- package/dist/sns-Y36LVTWA.js +50 -0
- package/dist/sns-Y36LVTWA.js.map +1 -0
- package/dist/sqs-RRS3GRHK.js +61 -0
- package/dist/sqs-RRS3GRHK.js.map +1 -0
- package/dist/src-KZRTG3EU.js +45 -0
- package/dist/src-KZRTG3EU.js.map +1 -0
- package/dist/standards-RXK5G4IG.js +37 -0
- package/dist/standards-RXK5G4IG.js.map +1 -0
- package/dist/sync-RLYBGYNY.js +877 -0
- package/dist/sync-RLYBGYNY.js.map +1 -0
- package/dist/validate-AABLVQJS.js +327 -0
- package/dist/validate-AABLVQJS.js.map +1 -0
- package/dist/validator-6PL5I5EC.js +156 -0
- package/dist/validator-6PL5I5EC.js.map +1 -0
- package/package.json +91 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// src/infra/checkers/gcp/cloudrun.ts
|
|
2
|
+
import { ServicesClient } from "@google-cloud/run";
|
|
3
|
+
var client = null;
|
|
4
|
+
function getClient() {
|
|
5
|
+
client ??= new ServicesClient();
|
|
6
|
+
return client;
|
|
7
|
+
}
|
|
8
|
+
function result(raw, resourceId, exists, error) {
|
|
9
|
+
return { arn: raw, exists, error, service: "run", resourceType: "services", resourceId };
|
|
10
|
+
}
|
|
11
|
+
var CloudRunChecker = {
|
|
12
|
+
async check(resource) {
|
|
13
|
+
const { project, location, resourceId, raw } = resource;
|
|
14
|
+
const serviceName = `projects/${project}/locations/${location}/services/${resourceId}`;
|
|
15
|
+
try {
|
|
16
|
+
const runClient = getClient();
|
|
17
|
+
await runClient.getService({ name: serviceName });
|
|
18
|
+
return result(raw, resourceId, true);
|
|
19
|
+
} catch (error) {
|
|
20
|
+
const err = error;
|
|
21
|
+
if (err.code === 5 || err.message?.includes("NOT_FOUND")) {
|
|
22
|
+
return result(raw, resourceId, false);
|
|
23
|
+
}
|
|
24
|
+
return result(raw, resourceId, false, err.message ?? "Unknown error");
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
export {
|
|
29
|
+
CloudRunChecker
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=cloudrun-O36R23SH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/infra/checkers/gcp/cloudrun.ts"],"sourcesContent":["/**\n * GCP Cloud Run resource checker\n */\n\nimport { ServicesClient } from \"@google-cloud/run\";\n\nimport type { ParsedGcpResource, ResourceCheckResult } from \"../../types.js\";\nimport type { GcpResourceChecker } from \"../types.js\";\n\nlet client: ServicesClient | null = null;\n\nfunction getClient(): ServicesClient {\n client ??= new ServicesClient();\n return client;\n}\n\nfunction result(\n raw: string,\n resourceId: string,\n exists: boolean,\n error?: string\n): ResourceCheckResult {\n return { arn: raw, exists, error, service: \"run\", resourceType: \"services\", resourceId };\n}\n\nexport const CloudRunChecker: GcpResourceChecker = {\n async check(resource: ParsedGcpResource): Promise<ResourceCheckResult> {\n const { project, location, resourceId, raw } = resource;\n const serviceName = `projects/${project}/locations/${location}/services/${resourceId}`;\n\n try {\n const runClient = getClient();\n await runClient.getService({ name: serviceName });\n return result(raw, resourceId, true);\n } catch (error) {\n const err = error as { code?: number; message?: string };\n if (err.code === 5 || err.message?.includes(\"NOT_FOUND\")) {\n return result(raw, resourceId, false);\n }\n return result(raw, resourceId, false, err.message ?? \"Unknown error\");\n }\n },\n};\n"],"mappings":";AAIA,SAAS,sBAAsB;AAK/B,IAAI,SAAgC;AAEpC,SAAS,YAA4B;AACnC,aAAW,IAAI,eAAe;AAC9B,SAAO;AACT;AAEA,SAAS,OACP,KACA,YACA,QACA,OACqB;AACrB,SAAO,EAAE,KAAK,KAAK,QAAQ,OAAO,SAAS,OAAO,cAAc,YAAY,WAAW;AACzF;AAEO,IAAM,kBAAsC;AAAA,EACjD,MAAM,MAAM,UAA2D;AACrE,UAAM,EAAE,SAAS,UAAU,YAAY,IAAI,IAAI;AAC/C,UAAM,cAAc,YAAY,OAAO,cAAc,QAAQ,aAAa,UAAU;AAEpF,QAAI;AACF,YAAM,YAAY,UAAU;AAC5B,YAAM,UAAU,WAAW,EAAE,MAAM,YAAY,CAAC;AAChD,aAAO,OAAO,KAAK,YAAY,IAAI;AAAA,IACrC,SAAS,OAAO;AACd,YAAM,MAAM;AACZ,UAAI,IAAI,SAAS,KAAK,IAAI,SAAS,SAAS,WAAW,GAAG;AACxD,eAAO,OAAO,KAAK,YAAY,KAAK;AAAA,MACtC;AACA,aAAO,OAAO,KAAK,YAAY,OAAO,IAAI,WAAW,eAAe;AAAA,IACtE;AAAA,EACF;AACF;","names":[]}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// src/infra/checkers/cloudwatch.ts
|
|
2
|
+
import { CloudWatchLogsClient, DescribeLogGroupsCommand } from "@aws-sdk/client-cloudwatch-logs";
|
|
3
|
+
var clientCache = /* @__PURE__ */ new Map();
|
|
4
|
+
function getClient(region) {
|
|
5
|
+
let client = clientCache.get(region);
|
|
6
|
+
if (!client) {
|
|
7
|
+
client = new CloudWatchLogsClient({ region });
|
|
8
|
+
clientCache.set(region, client);
|
|
9
|
+
}
|
|
10
|
+
return client;
|
|
11
|
+
}
|
|
12
|
+
var CloudWatchLogsChecker = {
|
|
13
|
+
async check(arn) {
|
|
14
|
+
const { resourceId, region, raw } = arn;
|
|
15
|
+
const client = getClient(region);
|
|
16
|
+
try {
|
|
17
|
+
const response = await client.send(
|
|
18
|
+
new DescribeLogGroupsCommand({
|
|
19
|
+
logGroupNamePrefix: resourceId,
|
|
20
|
+
limit: 1
|
|
21
|
+
})
|
|
22
|
+
);
|
|
23
|
+
const found = response.logGroups?.some((lg) => lg.logGroupName === resourceId);
|
|
24
|
+
return {
|
|
25
|
+
arn: raw,
|
|
26
|
+
exists: Boolean(found),
|
|
27
|
+
service: "logs",
|
|
28
|
+
resourceType: "log-group",
|
|
29
|
+
resourceId
|
|
30
|
+
};
|
|
31
|
+
} catch (error) {
|
|
32
|
+
const err = error;
|
|
33
|
+
if (err.name === "ResourceNotFoundException") {
|
|
34
|
+
return {
|
|
35
|
+
arn: raw,
|
|
36
|
+
exists: false,
|
|
37
|
+
service: "logs",
|
|
38
|
+
resourceType: "log-group",
|
|
39
|
+
resourceId
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
arn: raw,
|
|
44
|
+
exists: false,
|
|
45
|
+
error: err.message || "Unknown error",
|
|
46
|
+
service: "logs",
|
|
47
|
+
resourceType: "log-group",
|
|
48
|
+
resourceId
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
export {
|
|
54
|
+
CloudWatchLogsChecker
|
|
55
|
+
};
|
|
56
|
+
//# sourceMappingURL=cloudwatch-KSZ4A256.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/infra/checkers/cloudwatch.ts"],"sourcesContent":["/**\n * CloudWatch Logs resource checker\n */\n\nimport { CloudWatchLogsClient, DescribeLogGroupsCommand } from \"@aws-sdk/client-cloudwatch-logs\";\n\nimport type { ParsedArn, ResourceCheckResult } from \"../types.js\";\nimport type { ResourceChecker } from \"./types.js\";\n\n/**\n * Cache of CloudWatch Logs clients by region\n */\nconst clientCache = new Map<string, CloudWatchLogsClient>();\n\n/**\n * Get or create a CloudWatch Logs client for a region\n */\nfunction getClient(region: string): CloudWatchLogsClient {\n let client = clientCache.get(region);\n if (!client) {\n client = new CloudWatchLogsClient({ region });\n clientCache.set(region, client);\n }\n return client;\n}\n\n/**\n * CloudWatch Logs log group checker\n */\nexport const CloudWatchLogsChecker: ResourceChecker = {\n async check(arn: ParsedArn): Promise<ResourceCheckResult> {\n const { resourceId, region, raw } = arn;\n\n const client = getClient(region);\n\n try {\n // DescribeLogGroups filters by prefix, so we need to check the results\n const response = await client.send(\n new DescribeLogGroupsCommand({\n logGroupNamePrefix: resourceId,\n limit: 1,\n })\n );\n\n // Check if we found an exact match\n const found = response.logGroups?.some((lg) => lg.logGroupName === resourceId);\n\n return {\n arn: raw,\n exists: Boolean(found),\n service: \"logs\",\n resourceType: \"log-group\",\n resourceId,\n };\n } catch (error) {\n const err = error as Error & { name?: string };\n\n if (err.name === \"ResourceNotFoundException\") {\n return {\n arn: raw,\n exists: false,\n service: \"logs\",\n resourceType: \"log-group\",\n resourceId,\n };\n }\n\n return {\n arn: raw,\n exists: false,\n error: err.message || \"Unknown error\",\n service: \"logs\",\n resourceType: \"log-group\",\n resourceId,\n };\n }\n },\n};\n"],"mappings":";AAIA,SAAS,sBAAsB,gCAAgC;AAQ/D,IAAM,cAAc,oBAAI,IAAkC;AAK1D,SAAS,UAAU,QAAsC;AACvD,MAAI,SAAS,YAAY,IAAI,MAAM;AACnC,MAAI,CAAC,QAAQ;AACX,aAAS,IAAI,qBAAqB,EAAE,OAAO,CAAC;AAC5C,gBAAY,IAAI,QAAQ,MAAM;AAAA,EAChC;AACA,SAAO;AACT;AAKO,IAAM,wBAAyC;AAAA,EACpD,MAAM,MAAM,KAA8C;AACxD,UAAM,EAAE,YAAY,QAAQ,IAAI,IAAI;AAEpC,UAAM,SAAS,UAAU,MAAM;AAE/B,QAAI;AAEF,YAAM,WAAW,MAAM,OAAO;AAAA,QAC5B,IAAI,yBAAyB;AAAA,UAC3B,oBAAoB;AAAA,UACpB,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AAGA,YAAM,QAAQ,SAAS,WAAW,KAAK,CAAC,OAAO,GAAG,iBAAiB,UAAU;AAE7E,aAAO;AAAA,QACL,KAAK;AAAA,QACL,QAAQ,QAAQ,KAAK;AAAA,QACrB,SAAS;AAAA,QACT,cAAc;AAAA,QACd;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,YAAM,MAAM;AAEZ,UAAI,IAAI,SAAS,6BAA6B;AAC5C,eAAO;AAAA,UACL,KAAK;AAAA,UACL,QAAQ;AAAA,UACR,SAAS;AAAA,UACT,cAAc;AAAA,UACd;AAAA,QACF;AAAA,MACF;AAEA,aAAO;AAAA,QACL,KAAK;AAAA,QACL,QAAQ;AAAA,QACR,OAAO,IAAI,WAAW;AAAA,QACtB,SAAS;AAAA,QACT,cAAc;AAAA,QACd;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// src/infra/checkers/dynamodb.ts
|
|
2
|
+
import { DescribeTableCommand, DynamoDBClient } from "@aws-sdk/client-dynamodb";
|
|
3
|
+
var clientCache = /* @__PURE__ */ new Map();
|
|
4
|
+
function getClient(region) {
|
|
5
|
+
let client = clientCache.get(region);
|
|
6
|
+
if (!client) {
|
|
7
|
+
client = new DynamoDBClient({ region });
|
|
8
|
+
clientCache.set(region, client);
|
|
9
|
+
}
|
|
10
|
+
return client;
|
|
11
|
+
}
|
|
12
|
+
var DynamoDBChecker = {
|
|
13
|
+
async check(arn) {
|
|
14
|
+
const { resourceType, resourceId, region, raw } = arn;
|
|
15
|
+
const tableName = resourceId.split("/")[0];
|
|
16
|
+
const client = getClient(region);
|
|
17
|
+
try {
|
|
18
|
+
await client.send(new DescribeTableCommand({ TableName: tableName }));
|
|
19
|
+
return {
|
|
20
|
+
arn: raw,
|
|
21
|
+
exists: true,
|
|
22
|
+
service: "dynamodb",
|
|
23
|
+
resourceType,
|
|
24
|
+
resourceId
|
|
25
|
+
};
|
|
26
|
+
} catch (error) {
|
|
27
|
+
const err = error;
|
|
28
|
+
if (err.name === "ResourceNotFoundException") {
|
|
29
|
+
return {
|
|
30
|
+
arn: raw,
|
|
31
|
+
exists: false,
|
|
32
|
+
service: "dynamodb",
|
|
33
|
+
resourceType,
|
|
34
|
+
resourceId
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
arn: raw,
|
|
39
|
+
exists: false,
|
|
40
|
+
error: err.message || "Unknown error",
|
|
41
|
+
service: "dynamodb",
|
|
42
|
+
resourceType,
|
|
43
|
+
resourceId
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
export {
|
|
49
|
+
DynamoDBChecker
|
|
50
|
+
};
|
|
51
|
+
//# sourceMappingURL=dynamodb-5KVESCVJ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/infra/checkers/dynamodb.ts"],"sourcesContent":["/**\n * DynamoDB resource checker\n */\n\nimport { DescribeTableCommand, DynamoDBClient } from \"@aws-sdk/client-dynamodb\";\n\nimport type { ParsedArn, ResourceCheckResult } from \"../types.js\";\nimport type { ResourceChecker } from \"./types.js\";\n\n/**\n * Cache of DynamoDB clients by region\n */\nconst clientCache = new Map<string, DynamoDBClient>();\n\n/**\n * Get or create a DynamoDB client for a region\n */\nfunction getClient(region: string): DynamoDBClient {\n let client = clientCache.get(region);\n if (!client) {\n client = new DynamoDBClient({ region });\n clientCache.set(region, client);\n }\n return client;\n}\n\n/**\n * DynamoDB table checker\n */\nexport const DynamoDBChecker: ResourceChecker = {\n async check(arn: ParsedArn): Promise<ResourceCheckResult> {\n const { resourceType, resourceId, region, raw } = arn;\n\n // Extract table name (might be \"table-name\" or \"table-name/index/index-name\")\n const tableName = resourceId.split(\"/\")[0];\n\n const client = getClient(region);\n\n try {\n await client.send(new DescribeTableCommand({ TableName: tableName }));\n return {\n arn: raw,\n exists: true,\n service: \"dynamodb\",\n resourceType,\n resourceId,\n };\n } catch (error) {\n const err = error as Error & { name?: string };\n\n if (err.name === \"ResourceNotFoundException\") {\n return {\n arn: raw,\n exists: false,\n service: \"dynamodb\",\n resourceType,\n resourceId,\n };\n }\n\n return {\n arn: raw,\n exists: false,\n error: err.message || \"Unknown error\",\n service: \"dynamodb\",\n resourceType,\n resourceId,\n };\n }\n },\n};\n"],"mappings":";AAIA,SAAS,sBAAsB,sBAAsB;AAQrD,IAAM,cAAc,oBAAI,IAA4B;AAKpD,SAAS,UAAU,QAAgC;AACjD,MAAI,SAAS,YAAY,IAAI,MAAM;AACnC,MAAI,CAAC,QAAQ;AACX,aAAS,IAAI,eAAe,EAAE,OAAO,CAAC;AACtC,gBAAY,IAAI,QAAQ,MAAM;AAAA,EAChC;AACA,SAAO;AACT;AAKO,IAAM,kBAAmC;AAAA,EAC9C,MAAM,MAAM,KAA8C;AACxD,UAAM,EAAE,cAAc,YAAY,QAAQ,IAAI,IAAI;AAGlD,UAAM,YAAY,WAAW,MAAM,GAAG,EAAE,CAAC;AAEzC,UAAM,SAAS,UAAU,MAAM;AAE/B,QAAI;AACF,YAAM,OAAO,KAAK,IAAI,qBAAqB,EAAE,WAAW,UAAU,CAAC,CAAC;AACpE,aAAO;AAAA,QACL,KAAK;AAAA,QACL,QAAQ;AAAA,QACR,SAAS;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,YAAM,MAAM;AAEZ,UAAI,IAAI,SAAS,6BAA6B;AAC5C,eAAO;AAAA,UACL,KAAK;AAAA,UACL,QAAQ;AAAA,UACR,SAAS;AAAA,UACT;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAEA,aAAO;AAAA,QACL,KAAK;AAAA,QACL,QAAQ;AAAA,QACR,OAAO,IAAI,WAAW;AAAA,QACtB,SAAS;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
// src/infra/checkers/ec2.ts
|
|
2
|
+
import {
|
|
3
|
+
DescribeInstancesCommand,
|
|
4
|
+
DescribeSecurityGroupsCommand,
|
|
5
|
+
DescribeKeyPairsCommand,
|
|
6
|
+
EC2Client
|
|
7
|
+
} from "@aws-sdk/client-ec2";
|
|
8
|
+
var clientCache = /* @__PURE__ */ new Map();
|
|
9
|
+
function getClient(region) {
|
|
10
|
+
let client = clientCache.get(region);
|
|
11
|
+
if (!client) {
|
|
12
|
+
client = new EC2Client({ region });
|
|
13
|
+
clientCache.set(region, client);
|
|
14
|
+
}
|
|
15
|
+
return client;
|
|
16
|
+
}
|
|
17
|
+
async function checkInstance(client, arn) {
|
|
18
|
+
const { resourceId, raw } = arn;
|
|
19
|
+
try {
|
|
20
|
+
const response = await client.send(
|
|
21
|
+
new DescribeInstancesCommand({ InstanceIds: [resourceId] })
|
|
22
|
+
);
|
|
23
|
+
const instance = response.Reservations?.[0]?.Instances?.[0];
|
|
24
|
+
const exists = !!instance && instance.State?.Name !== "terminated";
|
|
25
|
+
return {
|
|
26
|
+
arn: raw,
|
|
27
|
+
exists,
|
|
28
|
+
service: "ec2",
|
|
29
|
+
resourceType: "instance",
|
|
30
|
+
resourceId
|
|
31
|
+
};
|
|
32
|
+
} catch (error) {
|
|
33
|
+
const err = error;
|
|
34
|
+
if (err.name === "InvalidInstanceID.NotFound") {
|
|
35
|
+
return {
|
|
36
|
+
arn: raw,
|
|
37
|
+
exists: false,
|
|
38
|
+
service: "ec2",
|
|
39
|
+
resourceType: "instance",
|
|
40
|
+
resourceId
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
arn: raw,
|
|
45
|
+
exists: false,
|
|
46
|
+
error: err.message || "Unknown error",
|
|
47
|
+
service: "ec2",
|
|
48
|
+
resourceType: "instance",
|
|
49
|
+
resourceId
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async function checkSecurityGroup(client, arn) {
|
|
54
|
+
const { resourceId, raw } = arn;
|
|
55
|
+
try {
|
|
56
|
+
const response = await client.send(
|
|
57
|
+
new DescribeSecurityGroupsCommand({ GroupIds: [resourceId] })
|
|
58
|
+
);
|
|
59
|
+
const securityGroup = response.SecurityGroups?.[0];
|
|
60
|
+
const exists = !!securityGroup;
|
|
61
|
+
return {
|
|
62
|
+
arn: raw,
|
|
63
|
+
exists,
|
|
64
|
+
service: "ec2",
|
|
65
|
+
resourceType: "security-group",
|
|
66
|
+
resourceId
|
|
67
|
+
};
|
|
68
|
+
} catch (error) {
|
|
69
|
+
const err = error;
|
|
70
|
+
if (err.name === "InvalidGroup.NotFound") {
|
|
71
|
+
return {
|
|
72
|
+
arn: raw,
|
|
73
|
+
exists: false,
|
|
74
|
+
service: "ec2",
|
|
75
|
+
resourceType: "security-group",
|
|
76
|
+
resourceId
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
arn: raw,
|
|
81
|
+
exists: false,
|
|
82
|
+
error: err.message || "Unknown error",
|
|
83
|
+
service: "ec2",
|
|
84
|
+
resourceType: "security-group",
|
|
85
|
+
resourceId
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
async function checkKeyPair(client, arn) {
|
|
90
|
+
const { resourceId, raw } = arn;
|
|
91
|
+
try {
|
|
92
|
+
const response = await client.send(
|
|
93
|
+
new DescribeKeyPairsCommand({ KeyNames: [resourceId] })
|
|
94
|
+
);
|
|
95
|
+
const keyPair = response.KeyPairs?.[0];
|
|
96
|
+
const exists = !!keyPair;
|
|
97
|
+
return {
|
|
98
|
+
arn: raw,
|
|
99
|
+
exists,
|
|
100
|
+
service: "ec2",
|
|
101
|
+
resourceType: "key-pair",
|
|
102
|
+
resourceId
|
|
103
|
+
};
|
|
104
|
+
} catch (error) {
|
|
105
|
+
const err = error;
|
|
106
|
+
if (err.name === "InvalidKeyPair.NotFound") {
|
|
107
|
+
return {
|
|
108
|
+
arn: raw,
|
|
109
|
+
exists: false,
|
|
110
|
+
service: "ec2",
|
|
111
|
+
resourceType: "key-pair",
|
|
112
|
+
resourceId
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
arn: raw,
|
|
117
|
+
exists: false,
|
|
118
|
+
error: err.message || "Unknown error",
|
|
119
|
+
service: "ec2",
|
|
120
|
+
resourceType: "key-pair",
|
|
121
|
+
resourceId
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
var EC2Checker = {
|
|
126
|
+
async check(arn) {
|
|
127
|
+
const { resourceType, resourceId, region, raw } = arn;
|
|
128
|
+
const client = getClient(region);
|
|
129
|
+
switch (resourceType) {
|
|
130
|
+
case "instance":
|
|
131
|
+
return checkInstance(client, arn);
|
|
132
|
+
case "security-group":
|
|
133
|
+
return checkSecurityGroup(client, arn);
|
|
134
|
+
case "key-pair":
|
|
135
|
+
return checkKeyPair(client, arn);
|
|
136
|
+
default:
|
|
137
|
+
return {
|
|
138
|
+
arn: raw,
|
|
139
|
+
exists: false,
|
|
140
|
+
error: `Unsupported EC2 resource type: ${resourceType}`,
|
|
141
|
+
service: "ec2",
|
|
142
|
+
resourceType,
|
|
143
|
+
resourceId
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
export {
|
|
149
|
+
EC2Checker
|
|
150
|
+
};
|
|
151
|
+
//# sourceMappingURL=ec2-HKPE6GZV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/infra/checkers/ec2.ts"],"sourcesContent":["/**\n * EC2 resource checker\n *\n * Supports:\n * - Instances\n * - Security groups\n * - Key pairs\n */\n\nimport {\n DescribeInstancesCommand,\n DescribeSecurityGroupsCommand,\n DescribeKeyPairsCommand,\n EC2Client,\n} from \"@aws-sdk/client-ec2\";\n\nimport type { ParsedArn, ResourceCheckResult } from \"../types.js\";\nimport type { ResourceChecker } from \"./types.js\";\n\n/**\n * Cache of EC2 clients by region\n */\nconst clientCache = new Map<string, EC2Client>();\n\n/**\n * Get or create an EC2 client for a region\n */\nfunction getClient(region: string): EC2Client {\n let client = clientCache.get(region);\n if (!client) {\n client = new EC2Client({ region });\n clientCache.set(region, client);\n }\n return client;\n}\n\n/**\n * Check if an EC2 instance exists\n */\nasync function checkInstance(\n client: EC2Client,\n arn: ParsedArn\n): Promise<ResourceCheckResult> {\n const { resourceId, raw } = arn;\n\n try {\n const response = await client.send(\n new DescribeInstancesCommand({ InstanceIds: [resourceId] })\n );\n\n const instance = response.Reservations?.[0]?.Instances?.[0];\n const exists = !!instance && instance.State?.Name !== \"terminated\";\n\n return {\n arn: raw,\n exists,\n service: \"ec2\",\n resourceType: \"instance\",\n resourceId,\n };\n } catch (error) {\n const err = error as Error & { name?: string };\n\n if (err.name === \"InvalidInstanceID.NotFound\") {\n return {\n arn: raw,\n exists: false,\n service: \"ec2\",\n resourceType: \"instance\",\n resourceId,\n };\n }\n\n return {\n arn: raw,\n exists: false,\n error: err.message || \"Unknown error\",\n service: \"ec2\",\n resourceType: \"instance\",\n resourceId,\n };\n }\n}\n\n/**\n * Check if an EC2 security group exists\n */\nasync function checkSecurityGroup(\n client: EC2Client,\n arn: ParsedArn\n): Promise<ResourceCheckResult> {\n const { resourceId, raw } = arn;\n\n try {\n const response = await client.send(\n new DescribeSecurityGroupsCommand({ GroupIds: [resourceId] })\n );\n\n const securityGroup = response.SecurityGroups?.[0];\n const exists = !!securityGroup;\n\n return {\n arn: raw,\n exists,\n service: \"ec2\",\n resourceType: \"security-group\",\n resourceId,\n };\n } catch (error) {\n const err = error as Error & { name?: string };\n\n if (err.name === \"InvalidGroup.NotFound\") {\n return {\n arn: raw,\n exists: false,\n service: \"ec2\",\n resourceType: \"security-group\",\n resourceId,\n };\n }\n\n return {\n arn: raw,\n exists: false,\n error: err.message || \"Unknown error\",\n service: \"ec2\",\n resourceType: \"security-group\",\n resourceId,\n };\n }\n}\n\n/**\n * Check if an EC2 key pair exists\n */\nasync function checkKeyPair(\n client: EC2Client,\n arn: ParsedArn\n): Promise<ResourceCheckResult> {\n const { resourceId, raw } = arn;\n\n try {\n const response = await client.send(\n new DescribeKeyPairsCommand({ KeyNames: [resourceId] })\n );\n\n const keyPair = response.KeyPairs?.[0];\n const exists = !!keyPair;\n\n return {\n arn: raw,\n exists,\n service: \"ec2\",\n resourceType: \"key-pair\",\n resourceId,\n };\n } catch (error) {\n const err = error as Error & { name?: string };\n\n if (err.name === \"InvalidKeyPair.NotFound\") {\n return {\n arn: raw,\n exists: false,\n service: \"ec2\",\n resourceType: \"key-pair\",\n resourceId,\n };\n }\n\n return {\n arn: raw,\n exists: false,\n error: err.message || \"Unknown error\",\n service: \"ec2\",\n resourceType: \"key-pair\",\n resourceId,\n };\n }\n}\n\n/**\n * EC2 resource checker\n */\nexport const EC2Checker: ResourceChecker = {\n async check(arn: ParsedArn): Promise<ResourceCheckResult> {\n const { resourceType, resourceId, region, raw } = arn;\n const client = getClient(region);\n\n switch (resourceType) {\n case \"instance\":\n return checkInstance(client, arn);\n\n case \"security-group\":\n return checkSecurityGroup(client, arn);\n\n case \"key-pair\":\n return checkKeyPair(client, arn);\n\n default:\n return {\n arn: raw,\n exists: false,\n error: `Unsupported EC2 resource type: ${resourceType}`,\n service: \"ec2\",\n resourceType,\n resourceId,\n };\n }\n },\n};\n"],"mappings":";AASA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAQP,IAAM,cAAc,oBAAI,IAAuB;AAK/C,SAAS,UAAU,QAA2B;AAC5C,MAAI,SAAS,YAAY,IAAI,MAAM;AACnC,MAAI,CAAC,QAAQ;AACX,aAAS,IAAI,UAAU,EAAE,OAAO,CAAC;AACjC,gBAAY,IAAI,QAAQ,MAAM;AAAA,EAChC;AACA,SAAO;AACT;AAKA,eAAe,cACb,QACA,KAC8B;AAC9B,QAAM,EAAE,YAAY,IAAI,IAAI;AAE5B,MAAI;AACF,UAAM,WAAW,MAAM,OAAO;AAAA,MAC5B,IAAI,yBAAyB,EAAE,aAAa,CAAC,UAAU,EAAE,CAAC;AAAA,IAC5D;AAEA,UAAM,WAAW,SAAS,eAAe,CAAC,GAAG,YAAY,CAAC;AAC1D,UAAM,SAAS,CAAC,CAAC,YAAY,SAAS,OAAO,SAAS;AAEtD,WAAO;AAAA,MACL,KAAK;AAAA,MACL;AAAA,MACA,SAAS;AAAA,MACT,cAAc;AAAA,MACd;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,UAAM,MAAM;AAEZ,QAAI,IAAI,SAAS,8BAA8B;AAC7C,aAAO;AAAA,QACL,KAAK;AAAA,QACL,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,cAAc;AAAA,QACd;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,MACL,KAAK;AAAA,MACL,QAAQ;AAAA,MACR,OAAO,IAAI,WAAW;AAAA,MACtB,SAAS;AAAA,MACT,cAAc;AAAA,MACd;AAAA,IACF;AAAA,EACF;AACF;AAKA,eAAe,mBACb,QACA,KAC8B;AAC9B,QAAM,EAAE,YAAY,IAAI,IAAI;AAE5B,MAAI;AACF,UAAM,WAAW,MAAM,OAAO;AAAA,MAC5B,IAAI,8BAA8B,EAAE,UAAU,CAAC,UAAU,EAAE,CAAC;AAAA,IAC9D;AAEA,UAAM,gBAAgB,SAAS,iBAAiB,CAAC;AACjD,UAAM,SAAS,CAAC,CAAC;AAEjB,WAAO;AAAA,MACL,KAAK;AAAA,MACL;AAAA,MACA,SAAS;AAAA,MACT,cAAc;AAAA,MACd;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,UAAM,MAAM;AAEZ,QAAI,IAAI,SAAS,yBAAyB;AACxC,aAAO;AAAA,QACL,KAAK;AAAA,QACL,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,cAAc;AAAA,QACd;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,MACL,KAAK;AAAA,MACL,QAAQ;AAAA,MACR,OAAO,IAAI,WAAW;AAAA,MACtB,SAAS;AAAA,MACT,cAAc;AAAA,MACd;AAAA,IACF;AAAA,EACF;AACF;AAKA,eAAe,aACb,QACA,KAC8B;AAC9B,QAAM,EAAE,YAAY,IAAI,IAAI;AAE5B,MAAI;AACF,UAAM,WAAW,MAAM,OAAO;AAAA,MAC5B,IAAI,wBAAwB,EAAE,UAAU,CAAC,UAAU,EAAE,CAAC;AAAA,IACxD;AAEA,UAAM,UAAU,SAAS,WAAW,CAAC;AACrC,UAAM,SAAS,CAAC,CAAC;AAEjB,WAAO;AAAA,MACL,KAAK;AAAA,MACL;AAAA,MACA,SAAS;AAAA,MACT,cAAc;AAAA,MACd;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,UAAM,MAAM;AAEZ,QAAI,IAAI,SAAS,2BAA2B;AAC1C,aAAO;AAAA,QACL,KAAK;AAAA,QACL,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,cAAc;AAAA,QACd;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,MACL,KAAK;AAAA,MACL,QAAQ;AAAA,MACR,OAAO,IAAI,WAAW;AAAA,MACtB,SAAS;AAAA,MACT,cAAc;AAAA,MACd;AAAA,IACF;AAAA,EACF;AACF;AAKO,IAAM,aAA8B;AAAA,EACzC,MAAM,MAAM,KAA8C;AACxD,UAAM,EAAE,cAAc,YAAY,QAAQ,IAAI,IAAI;AAClD,UAAM,SAAS,UAAU,MAAM;AAE/B,YAAQ,cAAc;AAAA,MACpB,KAAK;AACH,eAAO,cAAc,QAAQ,GAAG;AAAA,MAElC,KAAK;AACH,eAAO,mBAAmB,QAAQ,GAAG;AAAA,MAEvC,KAAK;AACH,eAAO,aAAa,QAAQ,GAAG;AAAA,MAEjC;AACE,eAAO;AAAA,UACL,KAAK;AAAA,UACL,QAAQ;AAAA,UACR,OAAO,kCAAkC,YAAY;AAAA,UACrD,SAAS;AAAA,UACT;AAAA,UACA;AAAA,QACF;AAAA,IACJ;AAAA,EACF;AACF;","names":[]}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
// src/infra/checkers/ecs.ts
|
|
2
|
+
import {
|
|
3
|
+
DescribeClustersCommand,
|
|
4
|
+
DescribeServicesCommand,
|
|
5
|
+
DescribeTaskDefinitionCommand,
|
|
6
|
+
ECSClient
|
|
7
|
+
} from "@aws-sdk/client-ecs";
|
|
8
|
+
var clientCache = /* @__PURE__ */ new Map();
|
|
9
|
+
function getClient(region) {
|
|
10
|
+
let client = clientCache.get(region);
|
|
11
|
+
if (!client) {
|
|
12
|
+
client = new ECSClient({ region });
|
|
13
|
+
clientCache.set(region, client);
|
|
14
|
+
}
|
|
15
|
+
return client;
|
|
16
|
+
}
|
|
17
|
+
async function checkCluster(client, arn) {
|
|
18
|
+
const { resourceId, raw } = arn;
|
|
19
|
+
try {
|
|
20
|
+
const response = await client.send(
|
|
21
|
+
new DescribeClustersCommand({ clusters: [raw] })
|
|
22
|
+
);
|
|
23
|
+
const cluster = response.clusters?.[0];
|
|
24
|
+
const exists = cluster?.status === "ACTIVE";
|
|
25
|
+
return {
|
|
26
|
+
arn: raw,
|
|
27
|
+
exists,
|
|
28
|
+
service: "ecs",
|
|
29
|
+
resourceType: "cluster",
|
|
30
|
+
resourceId
|
|
31
|
+
};
|
|
32
|
+
} catch (error) {
|
|
33
|
+
const err = error;
|
|
34
|
+
return {
|
|
35
|
+
arn: raw,
|
|
36
|
+
exists: false,
|
|
37
|
+
error: err.message || "Unknown error",
|
|
38
|
+
service: "ecs",
|
|
39
|
+
resourceType: "cluster",
|
|
40
|
+
resourceId
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
async function checkService(client, arn) {
|
|
45
|
+
const { resourceId, raw, accountId, region } = arn;
|
|
46
|
+
const parts = resourceId.split("/");
|
|
47
|
+
if (parts.length < 2) {
|
|
48
|
+
return {
|
|
49
|
+
arn: raw,
|
|
50
|
+
exists: false,
|
|
51
|
+
error: "Invalid service ARN format",
|
|
52
|
+
service: "ecs",
|
|
53
|
+
resourceType: "service",
|
|
54
|
+
resourceId
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
const clusterName = parts[0];
|
|
58
|
+
const serviceName = parts[1];
|
|
59
|
+
const clusterArn = `arn:aws:ecs:${region}:${accountId}:cluster/${clusterName}`;
|
|
60
|
+
try {
|
|
61
|
+
const response = await client.send(
|
|
62
|
+
new DescribeServicesCommand({
|
|
63
|
+
cluster: clusterArn,
|
|
64
|
+
services: [serviceName]
|
|
65
|
+
})
|
|
66
|
+
);
|
|
67
|
+
const service = response.services?.[0];
|
|
68
|
+
const exists = service?.status === "ACTIVE";
|
|
69
|
+
return {
|
|
70
|
+
arn: raw,
|
|
71
|
+
exists,
|
|
72
|
+
service: "ecs",
|
|
73
|
+
resourceType: "service",
|
|
74
|
+
resourceId
|
|
75
|
+
};
|
|
76
|
+
} catch (error) {
|
|
77
|
+
const err = error;
|
|
78
|
+
return {
|
|
79
|
+
arn: raw,
|
|
80
|
+
exists: false,
|
|
81
|
+
error: err.message || "Unknown error",
|
|
82
|
+
service: "ecs",
|
|
83
|
+
resourceType: "service",
|
|
84
|
+
resourceId
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
async function checkTaskDefinition(client, arn) {
|
|
89
|
+
const { resourceId, raw } = arn;
|
|
90
|
+
try {
|
|
91
|
+
const response = await client.send(
|
|
92
|
+
new DescribeTaskDefinitionCommand({ taskDefinition: raw })
|
|
93
|
+
);
|
|
94
|
+
const taskDef = response.taskDefinition;
|
|
95
|
+
const exists = taskDef?.status === "ACTIVE";
|
|
96
|
+
return {
|
|
97
|
+
arn: raw,
|
|
98
|
+
exists,
|
|
99
|
+
service: "ecs",
|
|
100
|
+
resourceType: "task-definition",
|
|
101
|
+
resourceId
|
|
102
|
+
};
|
|
103
|
+
} catch (error) {
|
|
104
|
+
const err = error;
|
|
105
|
+
return {
|
|
106
|
+
arn: raw,
|
|
107
|
+
exists: false,
|
|
108
|
+
error: err.message || "Unknown error",
|
|
109
|
+
service: "ecs",
|
|
110
|
+
resourceType: "task-definition",
|
|
111
|
+
resourceId
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
var ECSChecker = {
|
|
116
|
+
async check(arn) {
|
|
117
|
+
const { resourceType, resourceId, region, raw } = arn;
|
|
118
|
+
const client = getClient(region);
|
|
119
|
+
switch (resourceType) {
|
|
120
|
+
case "cluster":
|
|
121
|
+
return checkCluster(client, arn);
|
|
122
|
+
case "service":
|
|
123
|
+
return checkService(client, arn);
|
|
124
|
+
case "task-definition":
|
|
125
|
+
return checkTaskDefinition(client, arn);
|
|
126
|
+
default:
|
|
127
|
+
return {
|
|
128
|
+
arn: raw,
|
|
129
|
+
exists: false,
|
|
130
|
+
error: `Unsupported ECS resource type: ${resourceType}`,
|
|
131
|
+
service: "ecs",
|
|
132
|
+
resourceType,
|
|
133
|
+
resourceId
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
export {
|
|
139
|
+
ECSChecker
|
|
140
|
+
};
|
|
141
|
+
//# sourceMappingURL=ecs-OS3NJZTA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/infra/checkers/ecs.ts"],"sourcesContent":["/**\n * ECS resource checker\n *\n * Supports:\n * - Clusters\n * - Services\n * - Task definitions\n */\n\nimport {\n DescribeClustersCommand,\n DescribeServicesCommand,\n DescribeTaskDefinitionCommand,\n ECSClient,\n} from \"@aws-sdk/client-ecs\";\n\nimport type { ParsedArn, ResourceCheckResult } from \"../types.js\";\nimport type { ResourceChecker } from \"./types.js\";\n\n/**\n * Cache of ECS clients by region\n */\nconst clientCache = new Map<string, ECSClient>();\n\n/**\n * Get or create an ECS client for a region\n */\nfunction getClient(region: string): ECSClient {\n let client = clientCache.get(region);\n if (!client) {\n client = new ECSClient({ region });\n clientCache.set(region, client);\n }\n return client;\n}\n\n/**\n * Check if an ECS cluster exists\n */\nasync function checkCluster(\n client: ECSClient,\n arn: ParsedArn\n): Promise<ResourceCheckResult> {\n const { resourceId, raw } = arn;\n\n try {\n const response = await client.send(\n new DescribeClustersCommand({ clusters: [raw] })\n );\n\n const cluster = response.clusters?.[0];\n const exists = cluster?.status === \"ACTIVE\";\n\n return {\n arn: raw,\n exists,\n service: \"ecs\",\n resourceType: \"cluster\",\n resourceId,\n };\n } catch (error) {\n const err = error as Error;\n return {\n arn: raw,\n exists: false,\n error: err.message || \"Unknown error\",\n service: \"ecs\",\n resourceType: \"cluster\",\n resourceId,\n };\n }\n}\n\n/**\n * Check if an ECS service exists\n *\n * Service ARN format: arn:aws:ecs:region:account:service/cluster/service-name\n */\nasync function checkService(\n client: ECSClient,\n arn: ParsedArn\n): Promise<ResourceCheckResult> {\n const { resourceId, raw, accountId, region } = arn;\n\n // resourceId format: cluster-name/service-name\n const parts = resourceId.split(\"/\");\n if (parts.length < 2) {\n return {\n arn: raw,\n exists: false,\n error: \"Invalid service ARN format\",\n service: \"ecs\",\n resourceType: \"service\",\n resourceId,\n };\n }\n\n const clusterName = parts[0];\n const serviceName = parts[1];\n const clusterArn = `arn:aws:ecs:${region}:${accountId}:cluster/${clusterName}`;\n\n try {\n const response = await client.send(\n new DescribeServicesCommand({\n cluster: clusterArn,\n services: [serviceName],\n })\n );\n\n const service = response.services?.[0];\n const exists = service?.status === \"ACTIVE\";\n\n return {\n arn: raw,\n exists,\n service: \"ecs\",\n resourceType: \"service\",\n resourceId,\n };\n } catch (error) {\n const err = error as Error;\n return {\n arn: raw,\n exists: false,\n error: err.message || \"Unknown error\",\n service: \"ecs\",\n resourceType: \"service\",\n resourceId,\n };\n }\n}\n\n/**\n * Check if an ECS task definition exists\n *\n * Task definition ARN format: arn:aws:ecs:region:account:task-definition/name:revision\n * or: arn:aws:ecs:region:account:task-definition/name (latest)\n */\nasync function checkTaskDefinition(\n client: ECSClient,\n arn: ParsedArn\n): Promise<ResourceCheckResult> {\n const { resourceId, raw } = arn;\n\n try {\n const response = await client.send(\n new DescribeTaskDefinitionCommand({ taskDefinition: raw })\n );\n\n const taskDef = response.taskDefinition;\n const exists = taskDef?.status === \"ACTIVE\";\n\n return {\n arn: raw,\n exists,\n service: \"ecs\",\n resourceType: \"task-definition\",\n resourceId,\n };\n } catch (error) {\n const err = error as Error;\n return {\n arn: raw,\n exists: false,\n error: err.message || \"Unknown error\",\n service: \"ecs\",\n resourceType: \"task-definition\",\n resourceId,\n };\n }\n}\n\n/**\n * ECS resource checker\n */\nexport const ECSChecker: ResourceChecker = {\n async check(arn: ParsedArn): Promise<ResourceCheckResult> {\n const { resourceType, resourceId, region, raw } = arn;\n const client = getClient(region);\n\n switch (resourceType) {\n case \"cluster\":\n return checkCluster(client, arn);\n\n case \"service\":\n return checkService(client, arn);\n\n case \"task-definition\":\n return checkTaskDefinition(client, arn);\n\n default:\n return {\n arn: raw,\n exists: false,\n error: `Unsupported ECS resource type: ${resourceType}`,\n service: \"ecs\",\n resourceType,\n resourceId,\n };\n }\n },\n};\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
// src/infra/checkers/elasticache.ts
|
|
2
|
+
import {
|
|
3
|
+
DescribeCacheClustersCommand,
|
|
4
|
+
DescribeCacheSubnetGroupsCommand,
|
|
5
|
+
DescribeReplicationGroupsCommand,
|
|
6
|
+
ElastiCacheClient
|
|
7
|
+
} from "@aws-sdk/client-elasticache";
|
|
8
|
+
var clientCache = /* @__PURE__ */ new Map();
|
|
9
|
+
function getClient(region) {
|
|
10
|
+
let client = clientCache.get(region);
|
|
11
|
+
if (!client) {
|
|
12
|
+
client = new ElastiCacheClient({ region });
|
|
13
|
+
clientCache.set(region, client);
|
|
14
|
+
}
|
|
15
|
+
return client;
|
|
16
|
+
}
|
|
17
|
+
async function checkCacheCluster(client, arn) {
|
|
18
|
+
const { resourceId, raw } = arn;
|
|
19
|
+
try {
|
|
20
|
+
const response = await client.send(
|
|
21
|
+
new DescribeCacheClustersCommand({ CacheClusterId: resourceId })
|
|
22
|
+
);
|
|
23
|
+
const cluster = response.CacheClusters?.[0];
|
|
24
|
+
const exists = !!cluster && cluster.CacheClusterStatus !== "deleting";
|
|
25
|
+
return {
|
|
26
|
+
arn: raw,
|
|
27
|
+
exists,
|
|
28
|
+
service: "elasticache",
|
|
29
|
+
resourceType: "cluster",
|
|
30
|
+
resourceId
|
|
31
|
+
};
|
|
32
|
+
} catch (error) {
|
|
33
|
+
const err = error;
|
|
34
|
+
if (err.name === "CacheClusterNotFoundFault") {
|
|
35
|
+
return {
|
|
36
|
+
arn: raw,
|
|
37
|
+
exists: false,
|
|
38
|
+
service: "elasticache",
|
|
39
|
+
resourceType: "cluster",
|
|
40
|
+
resourceId
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
arn: raw,
|
|
45
|
+
exists: false,
|
|
46
|
+
error: err.message || "Unknown error",
|
|
47
|
+
service: "elasticache",
|
|
48
|
+
resourceType: "cluster",
|
|
49
|
+
resourceId
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async function checkSubnetGroup(client, arn) {
|
|
54
|
+
const { resourceId, raw } = arn;
|
|
55
|
+
try {
|
|
56
|
+
const response = await client.send(
|
|
57
|
+
new DescribeCacheSubnetGroupsCommand({ CacheSubnetGroupName: resourceId })
|
|
58
|
+
);
|
|
59
|
+
const subnetGroup = response.CacheSubnetGroups?.[0];
|
|
60
|
+
const exists = !!subnetGroup;
|
|
61
|
+
return {
|
|
62
|
+
arn: raw,
|
|
63
|
+
exists,
|
|
64
|
+
service: "elasticache",
|
|
65
|
+
resourceType: "subnetgroup",
|
|
66
|
+
resourceId
|
|
67
|
+
};
|
|
68
|
+
} catch (error) {
|
|
69
|
+
const err = error;
|
|
70
|
+
if (err.name === "CacheSubnetGroupNotFoundFault") {
|
|
71
|
+
return {
|
|
72
|
+
arn: raw,
|
|
73
|
+
exists: false,
|
|
74
|
+
service: "elasticache",
|
|
75
|
+
resourceType: "subnetgroup",
|
|
76
|
+
resourceId
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
arn: raw,
|
|
81
|
+
exists: false,
|
|
82
|
+
error: err.message || "Unknown error",
|
|
83
|
+
service: "elasticache",
|
|
84
|
+
resourceType: "subnetgroup",
|
|
85
|
+
resourceId
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
async function checkReplicationGroup(client, arn) {
|
|
90
|
+
const { resourceId, raw } = arn;
|
|
91
|
+
try {
|
|
92
|
+
const response = await client.send(
|
|
93
|
+
new DescribeReplicationGroupsCommand({ ReplicationGroupId: resourceId })
|
|
94
|
+
);
|
|
95
|
+
const replicationGroup = response.ReplicationGroups?.[0];
|
|
96
|
+
const exists = !!replicationGroup && replicationGroup.Status !== "deleting";
|
|
97
|
+
return {
|
|
98
|
+
arn: raw,
|
|
99
|
+
exists,
|
|
100
|
+
service: "elasticache",
|
|
101
|
+
resourceType: "replicationgroup",
|
|
102
|
+
resourceId
|
|
103
|
+
};
|
|
104
|
+
} catch (error) {
|
|
105
|
+
const err = error;
|
|
106
|
+
if (err.name === "ReplicationGroupNotFoundFault") {
|
|
107
|
+
return {
|
|
108
|
+
arn: raw,
|
|
109
|
+
exists: false,
|
|
110
|
+
service: "elasticache",
|
|
111
|
+
resourceType: "replicationgroup",
|
|
112
|
+
resourceId
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
arn: raw,
|
|
117
|
+
exists: false,
|
|
118
|
+
error: err.message || "Unknown error",
|
|
119
|
+
service: "elasticache",
|
|
120
|
+
resourceType: "replicationgroup",
|
|
121
|
+
resourceId
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
var ElastiCacheChecker = {
|
|
126
|
+
async check(arn) {
|
|
127
|
+
const { resourceType, resourceId, region, raw } = arn;
|
|
128
|
+
const client = getClient(region);
|
|
129
|
+
switch (resourceType) {
|
|
130
|
+
case "cluster":
|
|
131
|
+
return checkCacheCluster(client, arn);
|
|
132
|
+
case "subnetgroup":
|
|
133
|
+
return checkSubnetGroup(client, arn);
|
|
134
|
+
case "replicationgroup":
|
|
135
|
+
return checkReplicationGroup(client, arn);
|
|
136
|
+
default:
|
|
137
|
+
return {
|
|
138
|
+
arn: raw,
|
|
139
|
+
exists: false,
|
|
140
|
+
error: `Unsupported ElastiCache resource type: ${resourceType}`,
|
|
141
|
+
service: "elasticache",
|
|
142
|
+
resourceType,
|
|
143
|
+
resourceId
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
export {
|
|
149
|
+
ElastiCacheChecker
|
|
150
|
+
};
|
|
151
|
+
//# sourceMappingURL=elasticache-7TCRHYYM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/infra/checkers/elasticache.ts"],"sourcesContent":["/**\n * ElastiCache resource checker\n *\n * Supports:\n * - Cache clusters\n * - Subnet groups\n * - Replication groups\n */\n\nimport {\n DescribeCacheClustersCommand,\n DescribeCacheSubnetGroupsCommand,\n DescribeReplicationGroupsCommand,\n ElastiCacheClient,\n} from \"@aws-sdk/client-elasticache\";\n\nimport type { ParsedArn, ResourceCheckResult } from \"../types.js\";\nimport type { ResourceChecker } from \"./types.js\";\n\n/**\n * Cache of ElastiCache clients by region\n */\nconst clientCache = new Map<string, ElastiCacheClient>();\n\n/**\n * Get or create an ElastiCache client for a region\n */\nfunction getClient(region: string): ElastiCacheClient {\n let client = clientCache.get(region);\n if (!client) {\n client = new ElastiCacheClient({ region });\n clientCache.set(region, client);\n }\n return client;\n}\n\n/**\n * Check if an ElastiCache cluster exists\n */\nasync function checkCacheCluster(\n client: ElastiCacheClient,\n arn: ParsedArn\n): Promise<ResourceCheckResult> {\n const { resourceId, raw } = arn;\n\n try {\n const response = await client.send(\n new DescribeCacheClustersCommand({ CacheClusterId: resourceId })\n );\n\n const cluster = response.CacheClusters?.[0];\n const exists = !!cluster && cluster.CacheClusterStatus !== \"deleting\";\n\n return {\n arn: raw,\n exists,\n service: \"elasticache\",\n resourceType: \"cluster\",\n resourceId,\n };\n } catch (error) {\n const err = error as Error & { name?: string };\n\n if (err.name === \"CacheClusterNotFoundFault\") {\n return {\n arn: raw,\n exists: false,\n service: \"elasticache\",\n resourceType: \"cluster\",\n resourceId,\n };\n }\n\n return {\n arn: raw,\n exists: false,\n error: err.message || \"Unknown error\",\n service: \"elasticache\",\n resourceType: \"cluster\",\n resourceId,\n };\n }\n}\n\n/**\n * Check if an ElastiCache subnet group exists\n */\nasync function checkSubnetGroup(\n client: ElastiCacheClient,\n arn: ParsedArn\n): Promise<ResourceCheckResult> {\n const { resourceId, raw } = arn;\n\n try {\n const response = await client.send(\n new DescribeCacheSubnetGroupsCommand({ CacheSubnetGroupName: resourceId })\n );\n\n const subnetGroup = response.CacheSubnetGroups?.[0];\n const exists = !!subnetGroup;\n\n return {\n arn: raw,\n exists,\n service: \"elasticache\",\n resourceType: \"subnetgroup\",\n resourceId,\n };\n } catch (error) {\n const err = error as Error & { name?: string };\n\n if (err.name === \"CacheSubnetGroupNotFoundFault\") {\n return {\n arn: raw,\n exists: false,\n service: \"elasticache\",\n resourceType: \"subnetgroup\",\n resourceId,\n };\n }\n\n return {\n arn: raw,\n exists: false,\n error: err.message || \"Unknown error\",\n service: \"elasticache\",\n resourceType: \"subnetgroup\",\n resourceId,\n };\n }\n}\n\n/**\n * Check if an ElastiCache replication group exists\n */\nasync function checkReplicationGroup(\n client: ElastiCacheClient,\n arn: ParsedArn\n): Promise<ResourceCheckResult> {\n const { resourceId, raw } = arn;\n\n try {\n const response = await client.send(\n new DescribeReplicationGroupsCommand({ ReplicationGroupId: resourceId })\n );\n\n const replicationGroup = response.ReplicationGroups?.[0];\n const exists = !!replicationGroup && replicationGroup.Status !== \"deleting\";\n\n return {\n arn: raw,\n exists,\n service: \"elasticache\",\n resourceType: \"replicationgroup\",\n resourceId,\n };\n } catch (error) {\n const err = error as Error & { name?: string };\n\n if (err.name === \"ReplicationGroupNotFoundFault\") {\n return {\n arn: raw,\n exists: false,\n service: \"elasticache\",\n resourceType: \"replicationgroup\",\n resourceId,\n };\n }\n\n return {\n arn: raw,\n exists: false,\n error: err.message || \"Unknown error\",\n service: \"elasticache\",\n resourceType: \"replicationgroup\",\n resourceId,\n };\n }\n}\n\n/**\n * ElastiCache resource checker\n */\nexport const ElastiCacheChecker: ResourceChecker = {\n async check(arn: ParsedArn): Promise<ResourceCheckResult> {\n const { resourceType, resourceId, region, raw } = arn;\n const client = getClient(region);\n\n switch (resourceType) {\n case \"cluster\":\n return checkCacheCluster(client, arn);\n\n case \"subnetgroup\":\n return checkSubnetGroup(client, arn);\n\n case \"replicationgroup\":\n return checkReplicationGroup(client, arn);\n\n default:\n return {\n arn: raw,\n exists: false,\n error: `Unsupported ElastiCache resource type: ${resourceType}`,\n service: \"elasticache\",\n resourceType,\n resourceId,\n };\n }\n },\n};\n"],"mappings":"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","names":[]}
|