@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,566 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_MANIFEST_NAME,
|
|
3
|
+
generateManifestFromFile,
|
|
4
|
+
generateManifestFromStdin,
|
|
5
|
+
generateMultiAccountFromFile,
|
|
6
|
+
generateMultiAccountFromStdin,
|
|
7
|
+
generateWithMerge,
|
|
8
|
+
mergeIntoManifest,
|
|
9
|
+
parseStackExport,
|
|
10
|
+
parseStackExportMultiAccount,
|
|
11
|
+
readExistingManifest,
|
|
12
|
+
writeManifest
|
|
13
|
+
} from "./chunk-J5S6GRGW.js";
|
|
14
|
+
import {
|
|
15
|
+
AccountIdSchema,
|
|
16
|
+
AccountKeySchema,
|
|
17
|
+
ArnSchema,
|
|
18
|
+
CloudProviderSchema,
|
|
19
|
+
GcpResourcePathSchema,
|
|
20
|
+
InfraScanResultSchema,
|
|
21
|
+
InfraScanSummarySchema,
|
|
22
|
+
LegacyManifestSchema,
|
|
23
|
+
ManifestAccountSchema,
|
|
24
|
+
ManifestError,
|
|
25
|
+
ManifestSchema,
|
|
26
|
+
MultiAccountManifestSchema,
|
|
27
|
+
ParsedArnSchema,
|
|
28
|
+
ParsedGcpResourceSchema,
|
|
29
|
+
PulumiResourceSchema,
|
|
30
|
+
PulumiStackExportSchema,
|
|
31
|
+
ResourceCheckResultSchema,
|
|
32
|
+
ResourceIdentifierSchema,
|
|
33
|
+
detectAccountFromResource,
|
|
34
|
+
formatAccountKey,
|
|
35
|
+
getAllResources,
|
|
36
|
+
isLegacyManifest,
|
|
37
|
+
isLegacyManifestSchema,
|
|
38
|
+
isMultiAccountManifest,
|
|
39
|
+
isMultiAccountManifestSchema,
|
|
40
|
+
isValidAccountKey,
|
|
41
|
+
isValidArn,
|
|
42
|
+
isValidArnFormat,
|
|
43
|
+
isValidGcpResource,
|
|
44
|
+
isValidGcpResourcePath,
|
|
45
|
+
normalizeManifest,
|
|
46
|
+
parseAccountKey,
|
|
47
|
+
parseArn,
|
|
48
|
+
parseGcpResource,
|
|
49
|
+
readManifest,
|
|
50
|
+
validateAccountKey,
|
|
51
|
+
validateArn,
|
|
52
|
+
validateGcpResourcePath,
|
|
53
|
+
validateLegacyManifest,
|
|
54
|
+
validateManifest,
|
|
55
|
+
validateMultiAccountManifest,
|
|
56
|
+
validateStackExport
|
|
57
|
+
} from "./chunk-M7G73Q6P.js";
|
|
58
|
+
import {
|
|
59
|
+
ExitCode
|
|
60
|
+
} from "./chunk-P7TIZJ4C.js";
|
|
61
|
+
import {
|
|
62
|
+
getProjectRoot,
|
|
63
|
+
loadConfigAsync
|
|
64
|
+
} from "./chunk-KHO6NIAI.js";
|
|
65
|
+
|
|
66
|
+
// src/infra/index.ts
|
|
67
|
+
import * as path from "path";
|
|
68
|
+
import chalk2 from "chalk";
|
|
69
|
+
|
|
70
|
+
// src/infra/output.ts
|
|
71
|
+
import chalk from "chalk";
|
|
72
|
+
function formatScanText(result) {
|
|
73
|
+
const lines = [];
|
|
74
|
+
formatHeader(lines, result);
|
|
75
|
+
if (result.accountResults && Object.keys(result.accountResults).length > 0) {
|
|
76
|
+
formatAccountResults(lines, result.accountResults);
|
|
77
|
+
formatOverallSummary(lines, result.summary);
|
|
78
|
+
} else {
|
|
79
|
+
formatResultsByStatus(lines, result.results);
|
|
80
|
+
formatSummary(lines, result.summary);
|
|
81
|
+
}
|
|
82
|
+
return lines.join("\n");
|
|
83
|
+
}
|
|
84
|
+
function formatHeader(lines, result) {
|
|
85
|
+
lines.push(chalk.bold("Infrastructure Scan Results"));
|
|
86
|
+
lines.push(`Manifest: ${result.manifest}`);
|
|
87
|
+
if (result.project) {
|
|
88
|
+
lines.push(`Project: ${result.project}`);
|
|
89
|
+
}
|
|
90
|
+
lines.push("");
|
|
91
|
+
}
|
|
92
|
+
function formatResultsByStatus(lines, results) {
|
|
93
|
+
const found = results.filter((r) => r.exists && !r.error);
|
|
94
|
+
const missing = results.filter((r) => !r.exists && !r.error);
|
|
95
|
+
const errors = results.filter((r) => r.error);
|
|
96
|
+
formatResultSection(lines, found, {
|
|
97
|
+
colorFn: chalk.green.bold,
|
|
98
|
+
label: "Found",
|
|
99
|
+
formatLine: formatFoundLine
|
|
100
|
+
});
|
|
101
|
+
formatResultSection(lines, missing, {
|
|
102
|
+
colorFn: chalk.red.bold,
|
|
103
|
+
label: "Missing",
|
|
104
|
+
formatLine: formatMissingLine
|
|
105
|
+
});
|
|
106
|
+
formatResultSection(lines, errors, {
|
|
107
|
+
colorFn: chalk.yellow.bold,
|
|
108
|
+
label: "Errors",
|
|
109
|
+
formatLine: formatErrorLine
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
function formatResultSection(lines, results, config) {
|
|
113
|
+
if (results.length === 0) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
lines.push(config.colorFn(`${config.label} (${results.length}):`));
|
|
117
|
+
for (const r of results) {
|
|
118
|
+
lines.push(config.formatLine(r));
|
|
119
|
+
}
|
|
120
|
+
lines.push("");
|
|
121
|
+
}
|
|
122
|
+
function formatFoundLine(r) {
|
|
123
|
+
const icon = chalk.green("\u2713");
|
|
124
|
+
const resourceInfo = `${r.service}/${r.resourceType}/${r.resourceId}`;
|
|
125
|
+
return ` ${icon} ${resourceInfo}`;
|
|
126
|
+
}
|
|
127
|
+
function formatMissingLine(r) {
|
|
128
|
+
const icon = chalk.red("\u2717");
|
|
129
|
+
const resourceInfo = `${r.service}/${r.resourceType}/${r.resourceId}`;
|
|
130
|
+
return ` ${icon} ${resourceInfo}`;
|
|
131
|
+
}
|
|
132
|
+
function formatErrorLine(r) {
|
|
133
|
+
const icon = chalk.yellow("!");
|
|
134
|
+
const resourceInfo = `${r.service}/${r.resourceType}/${r.resourceId}`;
|
|
135
|
+
const errorText = r.error ?? "Unknown error";
|
|
136
|
+
return ` ${icon} ${resourceInfo} - ${chalk.yellow(errorText)}`;
|
|
137
|
+
}
|
|
138
|
+
function formatSummary(lines, summary) {
|
|
139
|
+
lines.push(chalk.bold("Summary:"));
|
|
140
|
+
lines.push(` Total: ${summary.total}`);
|
|
141
|
+
lines.push(chalk.green(` Found: ${summary.found}`));
|
|
142
|
+
lines.push(chalk.red(` Missing: ${summary.missing}`));
|
|
143
|
+
if (summary.errors > 0) {
|
|
144
|
+
lines.push(chalk.yellow(` Errors: ${summary.errors}`));
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function formatOverallSummary(lines, summary) {
|
|
148
|
+
lines.push(chalk.bold("Overall Summary:"));
|
|
149
|
+
lines.push(` Total: ${summary.total}`);
|
|
150
|
+
lines.push(chalk.green(` Found: ${summary.found}`));
|
|
151
|
+
lines.push(chalk.red(` Missing: ${summary.missing}`));
|
|
152
|
+
if (summary.errors > 0) {
|
|
153
|
+
lines.push(chalk.yellow(` Errors: ${summary.errors}`));
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
function formatAccountResults(lines, accountResults) {
|
|
157
|
+
for (const [accountKey, account] of Object.entries(accountResults)) {
|
|
158
|
+
const accountLabel = account.alias ? `${account.alias} (${accountKey})` : accountKey;
|
|
159
|
+
lines.push(chalk.bold.cyan(`
|
|
160
|
+
Account: ${accountLabel}`));
|
|
161
|
+
lines.push(chalk.gray("\u2500".repeat(40)));
|
|
162
|
+
formatAccountResourceResults(lines, account.results);
|
|
163
|
+
const { summary } = account;
|
|
164
|
+
const summaryParts = [];
|
|
165
|
+
if (summary.found > 0) {
|
|
166
|
+
summaryParts.push(chalk.green(`${summary.found} found`));
|
|
167
|
+
}
|
|
168
|
+
if (summary.missing > 0) {
|
|
169
|
+
summaryParts.push(chalk.red(`${summary.missing} missing`));
|
|
170
|
+
}
|
|
171
|
+
if (summary.errors > 0) {
|
|
172
|
+
summaryParts.push(chalk.yellow(`${summary.errors} errors`));
|
|
173
|
+
}
|
|
174
|
+
lines.push(` ${chalk.dim("Summary:")} ${summaryParts.join(", ")}`);
|
|
175
|
+
}
|
|
176
|
+
lines.push("");
|
|
177
|
+
}
|
|
178
|
+
function formatAccountResourceResults(lines, results) {
|
|
179
|
+
for (const r of results) {
|
|
180
|
+
if (r.error) {
|
|
181
|
+
const icon = chalk.yellow("!");
|
|
182
|
+
lines.push(` ${icon} ${r.arn} - ${chalk.yellow(r.error)}`);
|
|
183
|
+
} else if (r.exists) {
|
|
184
|
+
const icon = chalk.green("\u2713");
|
|
185
|
+
lines.push(` ${icon} ${r.arn}`);
|
|
186
|
+
} else {
|
|
187
|
+
const icon = chalk.red("\u2717");
|
|
188
|
+
lines.push(` ${icon} ${r.arn}`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
function formatScanJson(result) {
|
|
193
|
+
return JSON.stringify(result, null, 2);
|
|
194
|
+
}
|
|
195
|
+
function formatScan(result, format) {
|
|
196
|
+
return format === "json" ? formatScanJson(result) : formatScanText(result);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// src/infra/checkers/index.ts
|
|
200
|
+
var SUPPORTED_SERVICES = [
|
|
201
|
+
"s3",
|
|
202
|
+
"lambda",
|
|
203
|
+
"dynamodb",
|
|
204
|
+
"sqs",
|
|
205
|
+
"sns",
|
|
206
|
+
"iam",
|
|
207
|
+
"secretsmanager",
|
|
208
|
+
"logs",
|
|
209
|
+
"ecs",
|
|
210
|
+
"rds",
|
|
211
|
+
"ec2",
|
|
212
|
+
"elasticache",
|
|
213
|
+
"elasticloadbalancing"
|
|
214
|
+
];
|
|
215
|
+
function isSupportedService(service) {
|
|
216
|
+
return SUPPORTED_SERVICES.includes(service);
|
|
217
|
+
}
|
|
218
|
+
var checkerFactories = {
|
|
219
|
+
s3: async () => (await import("./s3-2DH7PRVR.js")).S3Checker,
|
|
220
|
+
lambda: async () => (await import("./lambda-NFB5UILT.js")).LambdaChecker,
|
|
221
|
+
dynamodb: async () => (await import("./dynamodb-5KVESCVJ.js")).DynamoDBChecker,
|
|
222
|
+
sqs: async () => (await import("./sqs-RRS3GRHK.js")).SQSChecker,
|
|
223
|
+
sns: async () => (await import("./sns-Y36LVTWA.js")).SNSChecker,
|
|
224
|
+
iam: async () => (await import("./iam-7H5HFWVQ.js")).IAMChecker,
|
|
225
|
+
secretsmanager: async () => (await import("./secretsmanager-MOOIHLAO.js")).SecretsManagerChecker,
|
|
226
|
+
logs: async () => (await import("./cloudwatch-KSZ4A256.js")).CloudWatchLogsChecker,
|
|
227
|
+
ecs: async () => (await import("./ecs-OS3NJZTA.js")).ECSChecker,
|
|
228
|
+
rds: async () => (await import("./rds-KLG5O5SI.js")).RDSChecker,
|
|
229
|
+
ec2: async () => (await import("./ec2-HKPE6GZV.js")).EC2Checker,
|
|
230
|
+
elasticache: async () => (await import("./elasticache-7TCRHYYM.js")).ElastiCacheChecker,
|
|
231
|
+
elasticloadbalancing: async () => (await import("./elb-PEDLXW5R.js")).ELBChecker
|
|
232
|
+
};
|
|
233
|
+
var checkerCache = /* @__PURE__ */ new Map();
|
|
234
|
+
async function getChecker(service) {
|
|
235
|
+
if (!isSupportedService(service)) {
|
|
236
|
+
return void 0;
|
|
237
|
+
}
|
|
238
|
+
const cached = checkerCache.get(service);
|
|
239
|
+
if (cached) {
|
|
240
|
+
return cached;
|
|
241
|
+
}
|
|
242
|
+
const factory = checkerFactories[service];
|
|
243
|
+
const checker = await factory();
|
|
244
|
+
checkerCache.set(service, checker);
|
|
245
|
+
return checker;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// src/infra/checkers/gcp/index.ts
|
|
249
|
+
var SUPPORTED_GCP_SERVICES = ["run", "secretmanager", "artifactregistry", "iam"];
|
|
250
|
+
function isSupportedGcpService(service) {
|
|
251
|
+
return SUPPORTED_GCP_SERVICES.includes(service);
|
|
252
|
+
}
|
|
253
|
+
var checkerFactories2 = {
|
|
254
|
+
run: async () => (await import("./cloudrun-O36R23SH.js")).CloudRunChecker,
|
|
255
|
+
secretmanager: async () => (await import("./secretmanager-RDL62EFW.js")).SecretManagerChecker,
|
|
256
|
+
artifactregistry: async () => (await import("./artifactregistry-QQWBMEQN.js")).ArtifactRegistryChecker,
|
|
257
|
+
iam: async () => (await import("./iam-DJI64AGK.js")).ServiceAccountChecker
|
|
258
|
+
};
|
|
259
|
+
var checkerCache2 = /* @__PURE__ */ new Map();
|
|
260
|
+
async function getGcpChecker(service) {
|
|
261
|
+
if (!isSupportedGcpService(service)) {
|
|
262
|
+
return void 0;
|
|
263
|
+
}
|
|
264
|
+
const cached = checkerCache2.get(service);
|
|
265
|
+
if (cached) {
|
|
266
|
+
return cached;
|
|
267
|
+
}
|
|
268
|
+
const factory = checkerFactories2[service];
|
|
269
|
+
const checker = await factory();
|
|
270
|
+
checkerCache2.set(service, checker);
|
|
271
|
+
return checker;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// src/infra/scan.ts
|
|
275
|
+
var DEFAULT_CONCURRENCY = 10;
|
|
276
|
+
async function scanManifest(manifest, manifestPath, options = {}) {
|
|
277
|
+
const concurrency = options.concurrency ?? DEFAULT_CONCURRENCY;
|
|
278
|
+
if (isMultiAccountManifest(manifest)) {
|
|
279
|
+
return scanMultiAccountManifest(manifest, manifestPath, options);
|
|
280
|
+
}
|
|
281
|
+
const resources = getAllResources(manifest);
|
|
282
|
+
const results = await checkResourcesWithConcurrency(resources, concurrency);
|
|
283
|
+
const summary = calculateSummary(results);
|
|
284
|
+
return {
|
|
285
|
+
manifest: manifestPath,
|
|
286
|
+
project: manifest.project,
|
|
287
|
+
results,
|
|
288
|
+
summary
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
async function scanMultiAccountManifest(manifest, manifestPath, options = {}) {
|
|
292
|
+
const concurrency = options.concurrency ?? DEFAULT_CONCURRENCY;
|
|
293
|
+
const accountResults = {};
|
|
294
|
+
const allResults = [];
|
|
295
|
+
const accountsToScan = filterAccounts(manifest, options.account);
|
|
296
|
+
for (const [accountKey, account] of Object.entries(accountsToScan)) {
|
|
297
|
+
const results = await checkResourcesWithConcurrency(account.resources, concurrency);
|
|
298
|
+
const summary = calculateSummary(results);
|
|
299
|
+
accountResults[accountKey] = {
|
|
300
|
+
alias: account.alias,
|
|
301
|
+
results,
|
|
302
|
+
summary
|
|
303
|
+
};
|
|
304
|
+
allResults.push(...results);
|
|
305
|
+
}
|
|
306
|
+
const overallSummary = calculateSummary(allResults);
|
|
307
|
+
return {
|
|
308
|
+
manifest: manifestPath,
|
|
309
|
+
project: manifest.project,
|
|
310
|
+
results: allResults,
|
|
311
|
+
summary: overallSummary,
|
|
312
|
+
accountResults
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
function filterAccounts(manifest, accountFilter) {
|
|
316
|
+
if (!accountFilter) {
|
|
317
|
+
return manifest.accounts;
|
|
318
|
+
}
|
|
319
|
+
if (accountFilter in manifest.accounts) {
|
|
320
|
+
return { [accountFilter]: manifest.accounts[accountFilter] };
|
|
321
|
+
}
|
|
322
|
+
for (const [key, account] of Object.entries(manifest.accounts)) {
|
|
323
|
+
if (account.alias === accountFilter) {
|
|
324
|
+
return { [key]: account };
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
return {};
|
|
328
|
+
}
|
|
329
|
+
async function checkResourcesWithConcurrency(arns, concurrency) {
|
|
330
|
+
const results = [];
|
|
331
|
+
for (let i = 0; i < arns.length; i += concurrency) {
|
|
332
|
+
const batch = arns.slice(i, i + concurrency);
|
|
333
|
+
const batchResults = await Promise.all(batch.map((arn) => checkResource(arn)));
|
|
334
|
+
results.push(...batchResults);
|
|
335
|
+
}
|
|
336
|
+
results.sort((a, b) => a.arn.localeCompare(b.arn));
|
|
337
|
+
return results;
|
|
338
|
+
}
|
|
339
|
+
async function checkResource(resource) {
|
|
340
|
+
if (isValidArn(resource)) {
|
|
341
|
+
return checkAwsResource(resource);
|
|
342
|
+
}
|
|
343
|
+
if (isValidGcpResource(resource)) {
|
|
344
|
+
return checkGcpResource(resource);
|
|
345
|
+
}
|
|
346
|
+
return {
|
|
347
|
+
arn: resource,
|
|
348
|
+
exists: false,
|
|
349
|
+
error: "Invalid resource format (not a valid AWS ARN or GCP resource path)",
|
|
350
|
+
service: "unknown",
|
|
351
|
+
resourceType: "unknown",
|
|
352
|
+
resourceId: resource
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
async function checkAwsResource(arn) {
|
|
356
|
+
const parsed = parseArn(arn);
|
|
357
|
+
if (!parsed) {
|
|
358
|
+
return errorResult({ arn, error: "Invalid ARN format" });
|
|
359
|
+
}
|
|
360
|
+
if (!isSupportedService(parsed.service)) {
|
|
361
|
+
const msg = `Unsupported AWS service: ${parsed.service}. Supported: ${SUPPORTED_SERVICES.join(", ")}`;
|
|
362
|
+
return errorResult({
|
|
363
|
+
arn,
|
|
364
|
+
error: msg,
|
|
365
|
+
service: parsed.service,
|
|
366
|
+
resourceType: parsed.resourceType,
|
|
367
|
+
resourceId: parsed.resourceId
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
const checker = await getChecker(parsed.service);
|
|
371
|
+
if (!checker) {
|
|
372
|
+
return errorResult({ arn, error: `No checker for AWS service: ${parsed.service}`, service: parsed.service });
|
|
373
|
+
}
|
|
374
|
+
return checker.check(parsed);
|
|
375
|
+
}
|
|
376
|
+
async function checkGcpResource(resource) {
|
|
377
|
+
const parsed = parseGcpResource(resource);
|
|
378
|
+
if (!parsed) {
|
|
379
|
+
return errorResult({ arn: resource, error: "Invalid GCP resource path format" });
|
|
380
|
+
}
|
|
381
|
+
if (!isSupportedGcpService(parsed.service)) {
|
|
382
|
+
const msg = `Unsupported GCP service: ${parsed.service}. Supported: ${SUPPORTED_GCP_SERVICES.join(", ")}`;
|
|
383
|
+
return errorResult({
|
|
384
|
+
arn: resource,
|
|
385
|
+
error: msg,
|
|
386
|
+
service: parsed.service,
|
|
387
|
+
resourceType: parsed.resourceType,
|
|
388
|
+
resourceId: parsed.resourceId
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
const checker = await getGcpChecker(parsed.service);
|
|
392
|
+
if (!checker) {
|
|
393
|
+
return errorResult({ arn: resource, error: `No checker for GCP service: ${parsed.service}`, service: parsed.service });
|
|
394
|
+
}
|
|
395
|
+
return checker.check(parsed);
|
|
396
|
+
}
|
|
397
|
+
function errorResult(params) {
|
|
398
|
+
const { arn, error, service = "unknown", resourceType = "unknown", resourceId = arn } = params;
|
|
399
|
+
return { arn, exists: false, error, service, resourceType, resourceId };
|
|
400
|
+
}
|
|
401
|
+
function calculateSummary(results) {
|
|
402
|
+
let found = 0;
|
|
403
|
+
let missing = 0;
|
|
404
|
+
let errors = 0;
|
|
405
|
+
for (const result of results) {
|
|
406
|
+
if (result.error) {
|
|
407
|
+
errors++;
|
|
408
|
+
} else if (result.exists) {
|
|
409
|
+
found++;
|
|
410
|
+
} else {
|
|
411
|
+
missing++;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
return {
|
|
415
|
+
total: results.length,
|
|
416
|
+
found,
|
|
417
|
+
missing,
|
|
418
|
+
errors
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// src/infra/index.ts
|
|
423
|
+
async function scanInfra(options = {}) {
|
|
424
|
+
const resolvedManifestPath = await resolveManifestPath(options);
|
|
425
|
+
const manifest = readManifest(resolvedManifestPath);
|
|
426
|
+
return scanManifest(manifest, resolvedManifestPath, { account: options.account });
|
|
427
|
+
}
|
|
428
|
+
async function resolveManifestPath(options) {
|
|
429
|
+
const { manifestPath, configPath } = options;
|
|
430
|
+
if (manifestPath) {
|
|
431
|
+
return path.isAbsolute(manifestPath) ? manifestPath : path.resolve(process.cwd(), manifestPath);
|
|
432
|
+
}
|
|
433
|
+
const { config, configPath: loadedConfigPath } = await loadConfigAsync(configPath);
|
|
434
|
+
const projectRoot = getProjectRoot(loadedConfigPath);
|
|
435
|
+
const infraConfig = config.infra;
|
|
436
|
+
if (!infraConfig?.enabled) {
|
|
437
|
+
throw new ManifestError("Infra scanning is not enabled in standards.toml");
|
|
438
|
+
}
|
|
439
|
+
const manifestName = infraConfig.manifest;
|
|
440
|
+
return path.resolve(projectRoot, manifestName);
|
|
441
|
+
}
|
|
442
|
+
async function runInfraScan(options = {}) {
|
|
443
|
+
const { format = "text", manifestPath, configPath, account } = options;
|
|
444
|
+
try {
|
|
445
|
+
const result = await scanInfra({ manifestPath, configPath, account });
|
|
446
|
+
outputResult(result, format);
|
|
447
|
+
} catch (error) {
|
|
448
|
+
handleError(error, format);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
function outputResult(result, format) {
|
|
452
|
+
process.stdout.write(`${formatScan(result, format)}
|
|
453
|
+
`);
|
|
454
|
+
if (result.summary.errors > 0) {
|
|
455
|
+
process.exit(ExitCode.RUNTIME_ERROR);
|
|
456
|
+
} else if (result.summary.missing > 0) {
|
|
457
|
+
process.exit(ExitCode.VIOLATIONS_FOUND);
|
|
458
|
+
} else {
|
|
459
|
+
process.exit(ExitCode.SUCCESS);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
function handleError(error, format) {
|
|
463
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
464
|
+
const isConfigError = error instanceof ManifestError;
|
|
465
|
+
if (format === "json") {
|
|
466
|
+
process.stdout.write(`${JSON.stringify({ error: message }, null, 2)}
|
|
467
|
+
`);
|
|
468
|
+
} else {
|
|
469
|
+
console.error(chalk2.red(`Error: ${message}`));
|
|
470
|
+
}
|
|
471
|
+
process.exit(isConfigError ? ExitCode.CONFIG_ERROR : ExitCode.RUNTIME_ERROR);
|
|
472
|
+
}
|
|
473
|
+
async function runInfraGenerate(options = {}) {
|
|
474
|
+
const {
|
|
475
|
+
generateWithMerge: generateWithMerge2,
|
|
476
|
+
writeManifest: writeManifest2,
|
|
477
|
+
DEFAULT_MANIFEST_NAME: DEFAULT_MANIFEST_NAME2
|
|
478
|
+
} = await import("./generate-D4MFMOHP.js");
|
|
479
|
+
const { getAllResources: getAllResources2, isMultiAccountManifest: isMultiAccountManifest2 } = await import("./manifest-7AIL2FK2.js");
|
|
480
|
+
try {
|
|
481
|
+
const manifest = await generateWithMerge2(options.input, {
|
|
482
|
+
project: options.project,
|
|
483
|
+
output: options.output,
|
|
484
|
+
account: options.account,
|
|
485
|
+
accountId: options.accountId,
|
|
486
|
+
merge: options.merge
|
|
487
|
+
});
|
|
488
|
+
writeManifest2(manifest, { output: options.output, stdout: options.stdout });
|
|
489
|
+
if (!options.stdout) {
|
|
490
|
+
const outputPath = options.output ?? DEFAULT_MANIFEST_NAME2;
|
|
491
|
+
const resourceCount = getAllResources2(manifest).length;
|
|
492
|
+
const accountCount = isMultiAccountManifest2(manifest) ? Object.keys(manifest.accounts).length : 1;
|
|
493
|
+
const accountLabel = accountCount === 1 ? "account" : "accounts";
|
|
494
|
+
console.error(
|
|
495
|
+
chalk2.green(`\u2713 Generated ${outputPath} with ${resourceCount} resources across ${accountCount} ${accountLabel}`)
|
|
496
|
+
);
|
|
497
|
+
}
|
|
498
|
+
process.exit(ExitCode.SUCCESS);
|
|
499
|
+
} catch (error) {
|
|
500
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
501
|
+
console.error(chalk2.red(`Error: ${message}`));
|
|
502
|
+
process.exit(ExitCode.RUNTIME_ERROR);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
export {
|
|
506
|
+
AccountIdSchema,
|
|
507
|
+
AccountKeySchema,
|
|
508
|
+
ArnSchema,
|
|
509
|
+
CloudProviderSchema,
|
|
510
|
+
DEFAULT_MANIFEST_NAME,
|
|
511
|
+
GcpResourcePathSchema,
|
|
512
|
+
InfraScanResultSchema,
|
|
513
|
+
InfraScanSummarySchema,
|
|
514
|
+
LegacyManifestSchema,
|
|
515
|
+
ManifestAccountSchema,
|
|
516
|
+
ManifestError,
|
|
517
|
+
ManifestSchema,
|
|
518
|
+
MultiAccountManifestSchema,
|
|
519
|
+
ParsedArnSchema,
|
|
520
|
+
ParsedGcpResourceSchema,
|
|
521
|
+
PulumiResourceSchema,
|
|
522
|
+
PulumiStackExportSchema,
|
|
523
|
+
ResourceCheckResultSchema,
|
|
524
|
+
ResourceIdentifierSchema,
|
|
525
|
+
SUPPORTED_GCP_SERVICES,
|
|
526
|
+
SUPPORTED_SERVICES,
|
|
527
|
+
detectAccountFromResource,
|
|
528
|
+
formatAccountKey,
|
|
529
|
+
generateManifestFromFile,
|
|
530
|
+
generateManifestFromStdin,
|
|
531
|
+
generateMultiAccountFromFile,
|
|
532
|
+
generateMultiAccountFromStdin,
|
|
533
|
+
generateWithMerge,
|
|
534
|
+
getAllResources,
|
|
535
|
+
isLegacyManifest,
|
|
536
|
+
isLegacyManifestSchema,
|
|
537
|
+
isMultiAccountManifest,
|
|
538
|
+
isMultiAccountManifestSchema,
|
|
539
|
+
isSupportedGcpService,
|
|
540
|
+
isSupportedService,
|
|
541
|
+
isValidAccountKey,
|
|
542
|
+
isValidArn,
|
|
543
|
+
isValidArnFormat,
|
|
544
|
+
isValidGcpResource,
|
|
545
|
+
isValidGcpResourcePath,
|
|
546
|
+
mergeIntoManifest,
|
|
547
|
+
normalizeManifest,
|
|
548
|
+
parseAccountKey,
|
|
549
|
+
parseArn,
|
|
550
|
+
parseGcpResource,
|
|
551
|
+
parseStackExport,
|
|
552
|
+
parseStackExportMultiAccount,
|
|
553
|
+
readExistingManifest,
|
|
554
|
+
runInfraGenerate,
|
|
555
|
+
runInfraScan,
|
|
556
|
+
scanInfra,
|
|
557
|
+
validateAccountKey,
|
|
558
|
+
validateArn,
|
|
559
|
+
validateGcpResourcePath,
|
|
560
|
+
validateLegacyManifest,
|
|
561
|
+
validateManifest,
|
|
562
|
+
validateMultiAccountManifest,
|
|
563
|
+
validateStackExport,
|
|
564
|
+
writeManifest
|
|
565
|
+
};
|
|
566
|
+
//# sourceMappingURL=infra-UXM5XQX3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/infra/index.ts","../src/infra/output.ts","../src/infra/checkers/index.ts","../src/infra/checkers/gcp/index.ts","../src/infra/scan.ts"],"sourcesContent":["/**\n * Infra scan module - Public API\n *\n * Provides functionality to verify AWS resources declared in a manifest actually exist.\n */\n\nimport * as path from \"node:path\";\n\nimport chalk from \"chalk\";\n\nimport { getProjectRoot, loadConfigAsync } from \"@standards-kit/core\";\nimport { ExitCode } from \"@standards-kit/core\";\n\nimport { ManifestError, readManifest } from \"./manifest.js\";\nimport { formatScan } from \"./output.js\";\nimport { scanManifest } from \"./scan.js\";\nimport type { InfraScanResult, RunInfraScanOptions, ScanInfraOptions } from \"./types.js\";\n\n// Re-export types\nexport type {\n AccountId,\n AccountScanResult,\n Arn,\n CloudProvider,\n GcpResourcePath,\n InfraScanResult,\n InfraScanSummary,\n LegacyManifest,\n Manifest,\n ManifestAccount,\n MultiAccountManifest,\n ParsedArn,\n ParsedGcpResource,\n PulumiResource,\n PulumiStackExport,\n ResourceCheckResult,\n ResourceIdentifier,\n ScanInfraOptions,\n} from \"./types.js\";\n\n// Re-export Zod schemas and validation functions for public API\nexport {\n // Schemas - for external consumers to validate manifests\n ArnSchema,\n AccountIdSchema,\n AccountKeySchema,\n CloudProviderSchema,\n GcpResourcePathSchema,\n InfraScanResultSchema,\n InfraScanSummarySchema,\n LegacyManifestSchema,\n ManifestAccountSchema,\n ManifestSchema,\n MultiAccountManifestSchema,\n ParsedArnSchema,\n ParsedGcpResourceSchema,\n PulumiResourceSchema,\n PulumiStackExportSchema,\n ResourceCheckResultSchema,\n ResourceIdentifierSchema,\n // Validation functions\n isValidArnFormat,\n isValidGcpResourcePath,\n isValidAccountKey,\n isMultiAccountManifestSchema,\n isLegacyManifestSchema,\n validateArn,\n validateGcpResourcePath,\n validateAccountKey,\n validateManifest,\n validateMultiAccountManifest,\n validateLegacyManifest,\n validateStackExport,\n} from \"./types.js\";\nexport {\n ManifestError,\n isMultiAccountManifest,\n isLegacyManifest,\n parseAccountKey,\n formatAccountKey,\n normalizeManifest,\n detectAccountFromResource,\n getAllResources,\n} from \"./manifest.js\";\nexport { parseArn, isValidArn } from \"./arn.js\";\nexport { parseGcpResource, isValidGcpResource } from \"./gcp.js\";\nexport { SUPPORTED_SERVICES, isSupportedService } from \"./checkers/index.js\";\nexport { SUPPORTED_GCP_SERVICES, isSupportedGcpService } from \"./checkers/gcp/index.js\";\n\n// Re-export generate functionality\nexport {\n DEFAULT_MANIFEST_NAME,\n generateManifestFromStdin,\n generateManifestFromFile,\n generateMultiAccountFromStdin,\n generateMultiAccountFromFile,\n generateWithMerge,\n mergeIntoManifest,\n parseStackExport,\n parseStackExportMultiAccount,\n readExistingManifest,\n writeManifest,\n type GenerateManifestOptions,\n} from \"./generate.js\";\n\n/**\n * Scan infrastructure resources declared in a manifest.\n *\n * This is the programmatic API for drift-toolkit integration.\n *\n * @param options - Options for the scan\n * @returns Scan result with all resource check results and summary\n *\n * @example\n * ```typescript\n * import { scanInfra } from \"check-my-toolkit\";\n *\n * const result = await scanInfra({ manifestPath: \"./infra-manifest.json\" });\n * console.log(result.summary);\n * // { total: 5, found: 4, missing: 1, errors: 0 }\n * ```\n */\nexport async function scanInfra(options: ScanInfraOptions = {}): Promise<InfraScanResult> {\n const resolvedManifestPath = await resolveManifestPath(options);\n const manifest = readManifest(resolvedManifestPath);\n return scanManifest(manifest, resolvedManifestPath, { account: options.account });\n}\n\nasync function resolveManifestPath(options: ScanInfraOptions): Promise<string> {\n const { manifestPath, configPath } = options;\n\n if (manifestPath) {\n return path.isAbsolute(manifestPath)\n ? manifestPath\n : path.resolve(process.cwd(), manifestPath);\n }\n\n const { config, configPath: loadedConfigPath } = await loadConfigAsync(configPath);\n const projectRoot = getProjectRoot(loadedConfigPath);\n\n const infraConfig = config.infra;\n if (!infraConfig?.enabled) {\n throw new ManifestError(\"Infra scanning is not enabled in standards.toml\");\n }\n\n const manifestName = infraConfig.manifest;\n return path.resolve(projectRoot, manifestName);\n}\n\n/**\n * Run infra scan from CLI\n */\nexport async function runInfraScan(options: RunInfraScanOptions = {}): Promise<void> {\n const { format = \"text\", manifestPath, configPath, account } = options;\n\n try {\n const result = await scanInfra({ manifestPath, configPath, account });\n outputResult(result, format);\n } catch (error) {\n handleError(error, format);\n }\n}\n\nfunction outputResult(result: InfraScanResult, format: \"text\" | \"json\"): never {\n process.stdout.write(`${formatScan(result, format)}\\n`);\n\n if (result.summary.errors > 0) {\n process.exit(ExitCode.RUNTIME_ERROR);\n } else if (result.summary.missing > 0) {\n process.exit(ExitCode.VIOLATIONS_FOUND);\n } else {\n process.exit(ExitCode.SUCCESS);\n }\n}\n\nfunction handleError(error: unknown, format: \"text\" | \"json\"): never {\n const message = error instanceof Error ? error.message : \"Unknown error\";\n const isConfigError = error instanceof ManifestError;\n\n if (format === \"json\") {\n process.stdout.write(`${JSON.stringify({ error: message }, null, 2)}\\n`);\n } else {\n console.error(chalk.red(`Error: ${message}`));\n }\n\n process.exit(isConfigError ? ExitCode.CONFIG_ERROR : ExitCode.RUNTIME_ERROR);\n}\n\n/**\n * Options for CLI generate command\n */\nexport interface RunInfraGenerateOptions {\n /** Input file path (if not provided, reads from stdin) */\n input?: string;\n /** Output file path (defaults to infra-manifest.json) */\n output?: string;\n /** Project name override */\n project?: string;\n /** Output to stdout instead of file */\n stdout?: boolean;\n /** Account alias (e.g., \"prod-aws\") for multi-account manifests */\n account?: string;\n /** Explicit account ID (e.g., \"aws:111111111111\") */\n accountId?: string;\n /** Merge into existing manifest instead of overwriting */\n merge?: boolean;\n}\n\n/**\n * Run infra generate from CLI\n */\nexport async function runInfraGenerate(options: RunInfraGenerateOptions = {}): Promise<void> {\n const {\n generateWithMerge,\n writeManifest,\n DEFAULT_MANIFEST_NAME,\n } = await import(\"./generate.js\");\n const { getAllResources, isMultiAccountManifest } = await import(\"./manifest.js\");\n\n try {\n const manifest = await generateWithMerge(options.input, {\n project: options.project,\n output: options.output,\n account: options.account,\n accountId: options.accountId,\n merge: options.merge,\n });\n\n writeManifest(manifest, { output: options.output, stdout: options.stdout });\n\n if (!options.stdout) {\n const outputPath = options.output ?? DEFAULT_MANIFEST_NAME;\n const resourceCount = getAllResources(manifest).length;\n const accountCount = isMultiAccountManifest(manifest)\n ? Object.keys(manifest.accounts).length\n : 1;\n const accountLabel = accountCount === 1 ? \"account\" : \"accounts\";\n\n console.error(\n chalk.green(`✓ Generated ${outputPath} with ${resourceCount} resources across ${accountCount} ${accountLabel}`)\n );\n }\n\n process.exit(ExitCode.SUCCESS);\n } catch (error) {\n const message = error instanceof Error ? error.message : \"Unknown error\";\n console.error(chalk.red(`Error: ${message}`));\n process.exit(ExitCode.RUNTIME_ERROR);\n }\n}\n","/**\n * Output formatters for infra scan results\n */\n\nimport chalk from \"chalk\";\n\nimport type { AccountScanResult, InfraScanResult, ResourceCheckResult } from \"./types.js\";\n\n/**\n * Format scan result as text output\n */\nfunction formatScanText(result: InfraScanResult): string {\n const lines: string[] = [];\n\n formatHeader(lines, result);\n\n // If we have account results, format by account\n if (result.accountResults && Object.keys(result.accountResults).length > 0) {\n formatAccountResults(lines, result.accountResults);\n formatOverallSummary(lines, result.summary);\n } else {\n // Legacy format - flat results\n formatResultsByStatus(lines, result.results);\n formatSummary(lines, result.summary);\n }\n\n return lines.join(\"\\n\");\n}\n\nfunction formatHeader(lines: string[], result: InfraScanResult): void {\n lines.push(chalk.bold(\"Infrastructure Scan Results\"));\n lines.push(`Manifest: ${result.manifest}`);\n if (result.project) {\n lines.push(`Project: ${result.project}`);\n }\n lines.push(\"\");\n}\n\nfunction formatResultsByStatus(lines: string[], results: ResourceCheckResult[]): void {\n const found = results.filter((r) => r.exists && !r.error);\n const missing = results.filter((r) => !r.exists && !r.error);\n const errors = results.filter((r) => r.error);\n\n formatResultSection(lines, found, {\n colorFn: chalk.green.bold,\n label: \"Found\",\n formatLine: formatFoundLine,\n });\n formatResultSection(lines, missing, {\n colorFn: chalk.red.bold,\n label: \"Missing\",\n formatLine: formatMissingLine,\n });\n formatResultSection(lines, errors, {\n colorFn: chalk.yellow.bold,\n label: \"Errors\",\n formatLine: formatErrorLine,\n });\n}\n\ninterface SectionConfig {\n colorFn: (s: string) => string;\n label: string;\n formatLine: (r: ResourceCheckResult) => string;\n}\n\nfunction formatResultSection(\n lines: string[],\n results: ResourceCheckResult[],\n config: SectionConfig\n): void {\n if (results.length === 0) {\n return;\n }\n lines.push(config.colorFn(`${config.label} (${results.length}):`));\n for (const r of results) {\n lines.push(config.formatLine(r));\n }\n lines.push(\"\");\n}\n\nfunction formatFoundLine(r: ResourceCheckResult): string {\n const icon = chalk.green(\"✓\");\n const resourceInfo = `${r.service}/${r.resourceType}/${r.resourceId}`;\n return ` ${icon} ${resourceInfo}`;\n}\n\nfunction formatMissingLine(r: ResourceCheckResult): string {\n const icon = chalk.red(\"✗\");\n const resourceInfo = `${r.service}/${r.resourceType}/${r.resourceId}`;\n return ` ${icon} ${resourceInfo}`;\n}\n\nfunction formatErrorLine(r: ResourceCheckResult): string {\n const icon = chalk.yellow(\"!\");\n const resourceInfo = `${r.service}/${r.resourceType}/${r.resourceId}`;\n const errorText = r.error ?? \"Unknown error\";\n return ` ${icon} ${resourceInfo} - ${chalk.yellow(errorText)}`;\n}\n\nfunction formatSummary(\n lines: string[],\n summary: { total: number; found: number; missing: number; errors: number }\n): void {\n lines.push(chalk.bold(\"Summary:\"));\n lines.push(` Total: ${summary.total}`);\n lines.push(chalk.green(` Found: ${summary.found}`));\n lines.push(chalk.red(` Missing: ${summary.missing}`));\n if (summary.errors > 0) {\n lines.push(chalk.yellow(` Errors: ${summary.errors}`));\n }\n}\n\n/**\n * Format overall summary for multi-account manifests\n */\nfunction formatOverallSummary(\n lines: string[],\n summary: { total: number; found: number; missing: number; errors: number }\n): void {\n lines.push(chalk.bold(\"Overall Summary:\"));\n lines.push(` Total: ${summary.total}`);\n lines.push(chalk.green(` Found: ${summary.found}`));\n lines.push(chalk.red(` Missing: ${summary.missing}`));\n if (summary.errors > 0) {\n lines.push(chalk.yellow(` Errors: ${summary.errors}`));\n }\n}\n\n/**\n * Format results grouped by account\n */\nfunction formatAccountResults(\n lines: string[],\n accountResults: Record<string, AccountScanResult>\n): void {\n for (const [accountKey, account] of Object.entries(accountResults)) {\n const accountLabel = account.alias\n ? `${account.alias} (${accountKey})`\n : accountKey;\n\n lines.push(chalk.bold.cyan(`\\nAccount: ${accountLabel}`));\n lines.push(chalk.gray(\"─\".repeat(40)));\n\n // Format results for this account\n formatAccountResourceResults(lines, account.results);\n\n // Account-level summary\n const { summary } = account;\n const summaryParts: string[] = [];\n if (summary.found > 0) {\n summaryParts.push(chalk.green(`${summary.found} found`));\n }\n if (summary.missing > 0) {\n summaryParts.push(chalk.red(`${summary.missing} missing`));\n }\n if (summary.errors > 0) {\n summaryParts.push(chalk.yellow(`${summary.errors} errors`));\n }\n lines.push(` ${chalk.dim(\"Summary:\")} ${summaryParts.join(\", \")}`);\n }\n lines.push(\"\");\n}\n\n/**\n * Format resource results for a single account (inline style)\n */\nfunction formatAccountResourceResults(lines: string[], results: ResourceCheckResult[]): void {\n for (const r of results) {\n if (r.error) {\n const icon = chalk.yellow(\"!\");\n lines.push(` ${icon} ${r.arn} - ${chalk.yellow(r.error)}`);\n } else if (r.exists) {\n const icon = chalk.green(\"✓\");\n lines.push(` ${icon} ${r.arn}`);\n } else {\n const icon = chalk.red(\"✗\");\n lines.push(` ${icon} ${r.arn}`);\n }\n }\n}\n\n/**\n * Format scan result as JSON output\n */\nfunction formatScanJson(result: InfraScanResult): string {\n return JSON.stringify(result, null, 2);\n}\n\n/**\n * Format scan result based on output format\n */\nexport function formatScan(result: InfraScanResult, format: \"text\" | \"json\"): string {\n return format === \"json\" ? formatScanJson(result) : formatScanText(result);\n}\n","/**\n * Checker registry with lazy loading\n *\n * Checkers are loaded on-demand to avoid loading all AWS SDK clients upfront.\n */\n\nimport type { ResourceChecker } from \"./types.js\";\n\n/**\n * Supported AWS services for resource checking\n */\nexport const SUPPORTED_SERVICES = [\n \"s3\",\n \"lambda\",\n \"dynamodb\",\n \"sqs\",\n \"sns\",\n \"iam\",\n \"secretsmanager\",\n \"logs\",\n \"ecs\",\n \"rds\",\n \"ec2\",\n \"elasticache\",\n \"elasticloadbalancing\",\n] as const;\n\nexport type SupportedService = (typeof SUPPORTED_SERVICES)[number];\n\n/**\n * Check if a service is supported\n */\nexport function isSupportedService(service: string): service is SupportedService {\n return SUPPORTED_SERVICES.includes(service as SupportedService);\n}\n\n/**\n * Factory functions for checkers (lazy-loaded)\n */\nconst checkerFactories: Record<SupportedService, () => Promise<ResourceChecker>> = {\n s3: async () => (await import(\"./s3.js\")).S3Checker,\n lambda: async () => (await import(\"./lambda.js\")).LambdaChecker,\n dynamodb: async () => (await import(\"./dynamodb.js\")).DynamoDBChecker,\n sqs: async () => (await import(\"./sqs.js\")).SQSChecker,\n sns: async () => (await import(\"./sns.js\")).SNSChecker,\n iam: async () => (await import(\"./iam.js\")).IAMChecker,\n secretsmanager: async () => (await import(\"./secretsmanager.js\")).SecretsManagerChecker,\n logs: async () => (await import(\"./cloudwatch.js\")).CloudWatchLogsChecker,\n ecs: async () => (await import(\"./ecs.js\")).ECSChecker,\n rds: async () => (await import(\"./rds.js\")).RDSChecker,\n ec2: async () => (await import(\"./ec2.js\")).EC2Checker,\n elasticache: async () => (await import(\"./elasticache.js\")).ElastiCacheChecker,\n elasticloadbalancing: async () => (await import(\"./elb.js\")).ELBChecker,\n};\n\n/**\n * Cache of loaded checkers\n */\nconst checkerCache = new Map<SupportedService, ResourceChecker>();\n\n/**\n * Get a checker for a service, loading it if necessary\n *\n * @param service - The AWS service name\n * @returns The checker instance, or undefined if the service is not supported\n */\nexport async function getChecker(service: string): Promise<ResourceChecker | undefined> {\n if (!isSupportedService(service)) {\n return undefined;\n }\n\n // Return cached checker if available\n const cached = checkerCache.get(service);\n if (cached) {\n return cached;\n }\n\n // Load and cache the checker\n const factory = checkerFactories[service];\n const checker = await factory();\n checkerCache.set(service, checker);\n\n return checker;\n}\n\n/**\n * Clear the checker cache (useful for testing)\n */\nexport function clearCheckerCache(): void {\n checkerCache.clear();\n}\n","/**\n * GCP checker registry with lazy loading\n */\n\nimport type { GcpResourceChecker } from \"../types.js\";\n\n/**\n * Supported GCP services for resource checking\n */\nexport const SUPPORTED_GCP_SERVICES = [\"run\", \"secretmanager\", \"artifactregistry\", \"iam\"] as const;\n\nexport type SupportedGcpService = (typeof SUPPORTED_GCP_SERVICES)[number];\n\n/**\n * Check if a GCP service is supported\n */\nexport function isSupportedGcpService(service: string): service is SupportedGcpService {\n return SUPPORTED_GCP_SERVICES.includes(service as SupportedGcpService);\n}\n\n/**\n * Factory functions for GCP checkers (lazy-loaded)\n */\nconst checkerFactories: Record<SupportedGcpService, () => Promise<GcpResourceChecker>> = {\n run: async () => (await import(\"./cloudrun.js\")).CloudRunChecker,\n secretmanager: async () => (await import(\"./secretmanager.js\")).SecretManagerChecker,\n artifactregistry: async () => (await import(\"./artifactregistry.js\")).ArtifactRegistryChecker,\n iam: async () => (await import(\"./iam.js\")).ServiceAccountChecker,\n};\n\n/**\n * Cache of loaded GCP checkers\n */\nconst checkerCache = new Map<SupportedGcpService, GcpResourceChecker>();\n\n/**\n * Get a GCP checker for a service, loading it if necessary\n */\nexport async function getGcpChecker(service: string): Promise<GcpResourceChecker | undefined> {\n if (!isSupportedGcpService(service)) {\n return undefined;\n }\n\n const cached = checkerCache.get(service);\n if (cached) {\n return cached;\n }\n\n const factory = checkerFactories[service];\n const checker = await factory();\n checkerCache.set(service, checker);\n\n return checker;\n}\n","/**\n * Scan logic for infra scan\n *\n * Orchestrates checking all resources in a manifest (AWS and GCP)\n */\n\nimport { isValidArn, parseArn } from \"./arn.js\";\nimport { getChecker, isSupportedService, SUPPORTED_SERVICES } from \"./checkers/index.js\";\nimport {\n getGcpChecker,\n isSupportedGcpService,\n SUPPORTED_GCP_SERVICES,\n} from \"./checkers/gcp/index.js\";\nimport { isValidGcpResource, parseGcpResource } from \"./gcp.js\";\nimport { getAllResources, isMultiAccountManifest } from \"./manifest.js\";\nimport type {\n AccountScanResult,\n InfraScanResult,\n InfraScanSummary,\n Manifest,\n MultiAccountManifest,\n ResourceCheckResult,\n} from \"./types.js\";\n\n/**\n * Default concurrency for parallel checks\n */\nconst DEFAULT_CONCURRENCY = 10;\n\n/**\n * Options for scanning\n */\ninterface ScanOptions {\n /** Max number of parallel checks */\n concurrency?: number;\n /** Filter to specific account (by alias or account key) */\n account?: string;\n}\n\n/**\n * Scan all resources in a manifest\n *\n * @param manifest - The manifest containing resources to check\n * @param manifestPath - Path to the manifest file (for result metadata)\n * @param options - Scan options\n * @returns Scan result with all resource check results and summary\n */\nexport async function scanManifest(\n manifest: Manifest,\n manifestPath: string,\n options: ScanOptions = {}\n): Promise<InfraScanResult> {\n const concurrency = options.concurrency ?? DEFAULT_CONCURRENCY;\n\n // For multi-account manifests, scan by account\n if (isMultiAccountManifest(manifest)) {\n return scanMultiAccountManifest(manifest, manifestPath, options);\n }\n\n // Legacy manifest - simple flat scan\n const resources = getAllResources(manifest);\n const results = await checkResourcesWithConcurrency(resources, concurrency);\n const summary = calculateSummary(results);\n\n return {\n manifest: manifestPath,\n project: manifest.project,\n results,\n summary,\n };\n}\n\n/**\n * Scan a multi-account manifest\n */\nasync function scanMultiAccountManifest(\n manifest: MultiAccountManifest,\n manifestPath: string,\n options: ScanOptions = {}\n): Promise<InfraScanResult> {\n const concurrency = options.concurrency ?? DEFAULT_CONCURRENCY;\n const accountResults: Record<string, AccountScanResult> = {};\n const allResults: ResourceCheckResult[] = [];\n\n // Get accounts to scan (filter by account if specified)\n const accountsToScan = filterAccounts(manifest, options.account);\n\n for (const [accountKey, account] of Object.entries(accountsToScan)) {\n const results = await checkResourcesWithConcurrency(account.resources, concurrency);\n const summary = calculateSummary(results);\n\n accountResults[accountKey] = {\n alias: account.alias,\n results,\n summary,\n };\n\n allResults.push(...results);\n }\n\n // Calculate overall summary\n const overallSummary = calculateSummary(allResults);\n\n return {\n manifest: manifestPath,\n project: manifest.project,\n results: allResults,\n summary: overallSummary,\n accountResults,\n };\n}\n\n/**\n * Filter accounts based on account filter\n * Returns matching accounts or all accounts if no filter\n */\nfunction filterAccounts(\n manifest: MultiAccountManifest,\n accountFilter?: string\n): Record<string, { alias?: string; resources: string[] }> {\n if (!accountFilter) {\n return manifest.accounts;\n }\n\n // Check if filter is an account key (e.g., \"aws:123456\")\n if (accountFilter in manifest.accounts) {\n return { [accountFilter]: manifest.accounts[accountFilter] };\n }\n\n // Check if filter matches an alias\n for (const [key, account] of Object.entries(manifest.accounts)) {\n if (account.alias === accountFilter) {\n return { [key]: account };\n }\n }\n\n // No match found - return empty\n return {};\n}\n\n/**\n * Check resources with controlled concurrency using a simple batching approach\n */\nasync function checkResourcesWithConcurrency(\n arns: string[],\n concurrency: number\n): Promise<ResourceCheckResult[]> {\n const results: ResourceCheckResult[] = [];\n\n // Process in batches\n for (let i = 0; i < arns.length; i += concurrency) {\n const batch = arns.slice(i, i + concurrency);\n const batchResults = await Promise.all(batch.map((arn) => checkResource(arn)));\n results.push(...batchResults);\n }\n\n // Sort results to maintain consistent order (by ARN)\n results.sort((a, b) => a.arn.localeCompare(b.arn));\n\n return results;\n}\n\n/**\n * Check a single resource (AWS or GCP)\n */\nasync function checkResource(resource: string): Promise<ResourceCheckResult> {\n // Detect cloud provider and route to appropriate checker\n if (isValidArn(resource)) {\n return checkAwsResource(resource);\n }\n if (isValidGcpResource(resource)) {\n return checkGcpResource(resource);\n }\n\n return {\n arn: resource,\n exists: false,\n error: \"Invalid resource format (not a valid AWS ARN or GCP resource path)\",\n service: \"unknown\",\n resourceType: \"unknown\",\n resourceId: resource,\n };\n}\n\n/**\n * Check an AWS resource\n */\nasync function checkAwsResource(arn: string): Promise<ResourceCheckResult> {\n const parsed = parseArn(arn);\n if (!parsed) {\n return errorResult({ arn, error: \"Invalid ARN format\" });\n }\n\n if (!isSupportedService(parsed.service)) {\n const msg = `Unsupported AWS service: ${parsed.service}. Supported: ${SUPPORTED_SERVICES.join(\", \")}`;\n return errorResult({\n arn,\n error: msg,\n service: parsed.service,\n resourceType: parsed.resourceType,\n resourceId: parsed.resourceId,\n });\n }\n\n const checker = await getChecker(parsed.service);\n if (!checker) {\n return errorResult({ arn, error: `No checker for AWS service: ${parsed.service}`, service: parsed.service });\n }\n\n return checker.check(parsed);\n}\n\n/**\n * Check a GCP resource\n */\nasync function checkGcpResource(resource: string): Promise<ResourceCheckResult> {\n const parsed = parseGcpResource(resource);\n if (!parsed) {\n return errorResult({ arn: resource, error: \"Invalid GCP resource path format\" });\n }\n\n if (!isSupportedGcpService(parsed.service)) {\n const msg = `Unsupported GCP service: ${parsed.service}. Supported: ${SUPPORTED_GCP_SERVICES.join(\", \")}`;\n return errorResult({\n arn: resource,\n error: msg,\n service: parsed.service,\n resourceType: parsed.resourceType,\n resourceId: parsed.resourceId,\n });\n }\n\n const checker = await getGcpChecker(parsed.service);\n if (!checker) {\n return errorResult({ arn: resource, error: `No checker for GCP service: ${parsed.service}`, service: parsed.service });\n }\n\n return checker.check(parsed);\n}\n\ninterface ErrorResultParams {\n arn: string;\n error: string;\n service?: string;\n resourceType?: string;\n resourceId?: string;\n}\n\n/**\n * Create an error result\n */\nfunction errorResult(params: ErrorResultParams): ResourceCheckResult {\n const { arn, error, service = \"unknown\", resourceType = \"unknown\", resourceId = arn } = params;\n return { arn, exists: false, error, service, resourceType, resourceId };\n}\n\n/**\n * Calculate summary statistics from check results\n */\nfunction calculateSummary(results: ResourceCheckResult[]): InfraScanSummary {\n let found = 0;\n let missing = 0;\n let errors = 0;\n\n for (const result of results) {\n if (result.error) {\n errors++;\n } else if (result.exists) {\n found++;\n } else {\n missing++;\n }\n }\n\n return {\n total: results.length,\n found,\n missing,\n errors,\n };\n}\n"],"mappings":"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","names":["chalk","checkerFactories","checkerCache","chalk","generateWithMerge","writeManifest","DEFAULT_MANIFEST_NAME","getAllResources","isMultiAccountManifest"]}
|