cdk-insights 0.4.6 → 0.4.7-beta.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/cli/entry.js CHANGED
@@ -78757,6 +78757,107 @@ var recordCacheSet = () => {
78757
78757
  saveCacheStats();
78758
78758
  };
78759
78759
 
78760
+ // src/helpers/serviceSelection/serviceSelection.ts
78761
+ var SPECIFIC_SERVICE_NAMES = [
78762
+ "IAM",
78763
+ "S3",
78764
+ "Lambda",
78765
+ "DynamoDB",
78766
+ "RDS",
78767
+ "EC2",
78768
+ "SNS",
78769
+ "SQS",
78770
+ "StepFunctions",
78771
+ "CloudTrail",
78772
+ "ApiGateway",
78773
+ "SecretsManager",
78774
+ "KMS",
78775
+ "EventBridge"
78776
+ ];
78777
+ var SERVICE_NAME_TO_CHECK_KEYS = {
78778
+ IAM: ["iamPolicies"],
78779
+ S3: ["s3Buckets", "s3IntelligentTiering"],
78780
+ Lambda: ["lambdaEnvironmentVariables", "lambdaMemory"],
78781
+ DynamoDB: ["dynamoDBAutoScaling", "dynamoDBStreams"],
78782
+ RDS: ["rdsEncryption", "rdsMultiAZ"],
78783
+ EC2: ["ec2InstanceType", "natGatewayUsage", "securityGroups", "ebsUnusedVolumes"],
78784
+ SNS: ["sns"],
78785
+ SQS: ["sqs"],
78786
+ StepFunctions: ["stepFunctions"],
78787
+ CloudTrail: ["cloudTrailLogging"],
78788
+ ApiGateway: ["apiGateway"],
78789
+ SecretsManager: ["secretsManager"],
78790
+ KMS: ["kmsKeys"],
78791
+ EventBridge: ["eventBridgeRules"]
78792
+ };
78793
+ var CHECK_KEY_TO_SERVICE_NAME = Object.entries(
78794
+ SERVICE_NAME_TO_CHECK_KEYS
78795
+ ).reduce((acc, [service, keys]) => {
78796
+ for (const key of keys) {
78797
+ acc[key] = service;
78798
+ }
78799
+ return acc;
78800
+ }, {});
78801
+ var dedupe = (items) => {
78802
+ const seen = /* @__PURE__ */ new Set();
78803
+ const result = [];
78804
+ for (const item of items) {
78805
+ if (seen.has(item)) {
78806
+ continue;
78807
+ }
78808
+ seen.add(item);
78809
+ result.push(item);
78810
+ }
78811
+ return result;
78812
+ };
78813
+ var normalizeServiceSelection = (services) => {
78814
+ if (!services || services.length === 0) {
78815
+ return {
78816
+ services: ["All services"],
78817
+ removedAllServices: false,
78818
+ defaultedToAll: true
78819
+ };
78820
+ }
78821
+ const uniqueServices = dedupe(services);
78822
+ const hasAllServices = uniqueServices.includes("All services");
78823
+ const specificServices = uniqueServices.filter(
78824
+ (service) => service !== "All services"
78825
+ );
78826
+ if (hasAllServices && specificServices.length > 0) {
78827
+ return {
78828
+ services: specificServices,
78829
+ removedAllServices: true,
78830
+ defaultedToAll: false
78831
+ };
78832
+ }
78833
+ return {
78834
+ services: hasAllServices ? ["All services"] : uniqueServices,
78835
+ removedAllServices: false,
78836
+ defaultedToAll: false
78837
+ };
78838
+ };
78839
+ var mapServicesToCheckKeys = (services, allCheckKeys) => {
78840
+ if (services.length === 0 || services.includes("All services")) {
78841
+ return dedupe(allCheckKeys);
78842
+ }
78843
+ const resolvedKeys = services.flatMap((service) => {
78844
+ if (service === "All services") {
78845
+ return allCheckKeys;
78846
+ }
78847
+ return SERVICE_NAME_TO_CHECK_KEYS[service] ?? [];
78848
+ });
78849
+ return dedupe(resolvedKeys);
78850
+ };
78851
+ var getServiceLabelForCheckKey = (checkKey) => {
78852
+ return CHECK_KEY_TO_SERVICE_NAME[checkKey];
78853
+ };
78854
+ var isServiceName = (value) => {
78855
+ if (value === "All services") {
78856
+ return true;
78857
+ }
78858
+ return SPECIFIC_SERVICE_NAMES.includes(value);
78859
+ };
78860
+
78760
78861
  // node_modules/axios/lib/helpers/bind.js
78761
78862
  function bind(fn, thisArg) {
78762
78863
  return function wrap2() {
@@ -90323,25 +90424,6 @@ var memoizedServiceChecks = memoize(createAWSServiceChecks, {
90323
90424
  // 10 minutes
90324
90425
  maxSize: 10
90325
90426
  });
90326
- var getServiceCheckKeys = (serviceName) => {
90327
- const serviceMapping = {
90328
- "Lambda": ["lambdaEnvironmentVariables", "lambdaMemory"],
90329
- "S3": ["s3Buckets", "s3IntelligentTiering"],
90330
- "DynamoDB": ["dynamoDBAutoScaling", "dynamoDBStreams"],
90331
- "RDS": ["rdsEncryption", "rdsMultiAZ"],
90332
- "EC2": ["ec2InstanceType", "natGatewayUsage", "securityGroups", "ebsUnusedVolumes"],
90333
- "IAM": ["iamPolicies"],
90334
- "SNS": ["sns"],
90335
- "SQS": ["sqs"],
90336
- "StepFunctions": ["stepFunctions"],
90337
- "CloudTrail": ["cloudTrailLogging"],
90338
- "ApiGateway": ["apiGateway"],
90339
- "SecretsManager": ["secretsManager"],
90340
- "KMS": ["kmsKeys"],
90341
- "EventBridge": ["eventBridgeRules"]
90342
- };
90343
- return serviceMapping[serviceName] || [serviceName];
90344
- };
90345
90427
  var createResourceFilter = (selectedServices) => {
90346
90428
  if (selectedServices.includes("All services")) {
90347
90429
  return (cloudFormationResource) => !cloudFormationResource.Type.startsWith("AWS::CDK::");
@@ -90358,13 +90440,16 @@ var createResourceFilter = (selectedServices) => {
90358
90440
  };
90359
90441
  var runStaticAnalysis = (cloudformationTemplate, createFinding2, selectedServices = [], solutionsRegistry = {}) => {
90360
90442
  const serviceChecks = memoizedServiceChecks();
90361
- const allServiceKeys = Object.keys(serviceChecks);
90362
- const servicesToAnalyze = selectedServices.length > 0 && !selectedServices.includes("All services") ? selectedServices : allServiceKeys.filter(
90443
+ const allServiceKeys = Object.keys(serviceChecks).filter(
90363
90444
  (serviceKey) => serviceKey !== "solutionsPatterns"
90364
90445
  );
90365
- const isAllServices = selectedServices.includes("All services") || selectedServices.length === 0;
90446
+ const { services: normalizedServices } = normalizeServiceSelection(selectedServices);
90447
+ const servicesToAnalyze = mapServicesToCheckKeys(
90448
+ normalizedServices,
90449
+ allServiceKeys
90450
+ );
90366
90451
  const analysisFindings = {};
90367
- const resourceFilter = createResourceFilter(selectedServices);
90452
+ const resourceFilter = createResourceFilter(normalizedServices);
90368
90453
  const userResources = Object.entries(cloudformationTemplate.Resources || {}).filter(
90369
90454
  ([, cloudFormationResource]) => resourceFilter(cloudFormationResource)
90370
90455
  ).reduce(
@@ -90374,37 +90459,36 @@ var runStaticAnalysis = (cloudformationTemplate, createFinding2, selectedService
90374
90459
  },
90375
90460
  {}
90376
90461
  );
90377
- for (const serviceName of servicesToAnalyze) {
90378
- const checkKeys = isAllServices ? [serviceName] : getServiceCheckKeys(serviceName);
90379
- for (const checkKey of checkKeys) {
90380
- try {
90381
- const serviceCheckFunction = serviceChecks[checkKey];
90382
- if (typeof serviceCheckFunction !== "function") {
90383
- if (checkKeys.indexOf(checkKey) === checkKeys.length - 1) {
90384
- analysisLogger.warn(
90385
- `\u26A0\uFE0F Service check function for ${serviceName} is not available`
90386
- );
90387
- }
90388
- continue;
90389
- }
90390
- const typedServiceCheckFunction = serviceCheckFunction;
90391
- const serviceAnalysisResult = typedServiceCheckFunction(
90392
- { Resources: userResources },
90393
- createFinding2
90462
+ for (const checkKey of servicesToAnalyze) {
90463
+ try {
90464
+ const serviceCheckFunction = serviceChecks[checkKey];
90465
+ if (typeof serviceCheckFunction !== "function") {
90466
+ const serviceLabel = getServiceLabelForCheckKey(checkKey) ?? checkKey;
90467
+ analysisLogger.warn(
90468
+ `\u26A0\uFE0F Service check function for ${serviceLabel} (${checkKey}) is not available`
90394
90469
  );
90395
- for (const [resourceName, resourceFindings] of Object.entries(
90396
- serviceAnalysisResult
90397
- )) {
90398
- if (!analysisFindings[resourceName]) {
90399
- analysisFindings[resourceName] = { issues: [] };
90400
- }
90401
- analysisFindings[resourceName].issues.push(...resourceFindings.issues);
90402
- }
90403
- } catch (analysisError) {
90404
- analysisLogger.warn(`\u26A0\uFE0F Error in ${serviceName} analysis (${checkKey})`, {
90405
- error: analysisError instanceof Error ? analysisError.message : String(analysisError)
90406
- });
90470
+ continue;
90407
90471
  }
90472
+ const serviceAnalysisResult = serviceCheckFunction(
90473
+ { Resources: userResources },
90474
+ createFinding2
90475
+ );
90476
+ for (const [resourceName, resourceFindings] of Object.entries(
90477
+ serviceAnalysisResult
90478
+ )) {
90479
+ if (!analysisFindings[resourceName]) {
90480
+ analysisFindings[resourceName] = { issues: [] };
90481
+ }
90482
+ analysisFindings[resourceName].issues.push(...resourceFindings.issues);
90483
+ }
90484
+ } catch (analysisError) {
90485
+ const serviceLabel = getServiceLabelForCheckKey(checkKey) ?? checkKey;
90486
+ analysisLogger.warn(
90487
+ `\u26A0\uFE0F Error in ${serviceLabel} analysis (${checkKey})`,
90488
+ {
90489
+ error: analysisError instanceof Error ? analysisError.message : String(analysisError)
90490
+ }
90491
+ );
90408
90492
  }
90409
90493
  }
90410
90494
  if (Object.keys(solutionsRegistry).length > 0) {
@@ -94079,6 +94163,12 @@ var validateServices = (services) => {
94079
94163
  }
94080
94164
  return [];
94081
94165
  };
94166
+ var validateServiceNames = (services) => {
94167
+ const parsed = validateServices(services);
94168
+ return parsed.map((service) => service.trim()).filter(Boolean).map(
94169
+ (service) => service.toLowerCase() === "all" ? "All services" : service
94170
+ ).filter((service) => isServiceName(service));
94171
+ };
94082
94172
  var validateCacheConfig = (cache3) => {
94083
94173
  if (!cache3 || typeof cache3 !== "object" || Array.isArray(cache3)) {
94084
94174
  return DEFAULT_CONFIG.cache;
@@ -94132,7 +94222,7 @@ var mergeConfigWithArgs = (config2, cliArgs) => {
94132
94222
  output: validatedOutput,
94133
94223
  format: validatedOutput,
94134
94224
  // Keep format in sync with output
94135
- services: validateServices(
94225
+ services: validateServiceNames(
94136
94226
  cliArgs.services ?? config2.services ?? DEFAULT_CONFIG.services
94137
94227
  ),
94138
94228
  withIssue,
@@ -94202,9 +94292,9 @@ var validateConfig = (config2) => {
94202
94292
  );
94203
94293
  }
94204
94294
  if (Array.isArray(raw.services)) {
94205
- validated.services = raw.services.filter(
94206
- (s3) => typeof s3 === "string"
94207
- );
94295
+ validated.services = raw.services.filter((s3) => typeof s3 === "string").map(
94296
+ (service) => service.toLowerCase() === "all" ? "All services" : service
94297
+ ).filter((service) => isServiceName(service));
94208
94298
  }
94209
94299
  if (typeof raw.withIssue === "boolean") {
94210
94300
  validated.withIssue = raw.withIssue;
@@ -94571,12 +94661,14 @@ async function runStackAnalysis(finalConfig, fingerprint, authToken, licenseInfo
94571
94661
  throw refreshError;
94572
94662
  }
94573
94663
  } : void 0;
94574
- let selectedServices = finalConfig.services && finalConfig.services.length > 0 ? finalConfig.services : ["All services"];
94575
- const hasAllServices = selectedServices.includes("All services");
94576
- const hasOtherServices = selectedServices.some((s3) => s3 !== "All services");
94577
- if (hasAllServices && hasOtherServices) {
94578
- selectedServices = selectedServices.filter((s3) => s3 !== "All services");
94579
- cliLogger.debug(`Services normalization: removed "All services", using: ${selectedServices.join(", ")}`);
94664
+ const serviceSelection = normalizeServiceSelection(finalConfig.services);
94665
+ const selectedServices = serviceSelection.services;
94666
+ if (serviceSelection.removedAllServices) {
94667
+ cliLogger.debug(
94668
+ `Services normalization: removed "All services", using: ${selectedServices.join(", ")}`
94669
+ );
94670
+ } else if (serviceSelection.defaultedToAll) {
94671
+ cliLogger.debug('Services normalization: defaulting to "All services"');
94580
94672
  }
94581
94673
  const analysisConfig = {
94582
94674
  stacks,
@@ -94719,14 +94811,6 @@ var analyzeCommand = {
94719
94811
  if (isInteractive2 && !initialConfig.yes) {
94720
94812
  const answers = await promptForConfig(initialConfig, stackChoices);
94721
94813
  finalConfig = { ...initialConfig, ...answers };
94722
- if (finalConfig.services && finalConfig.services.length > 0) {
94723
- const hasAllServices = finalConfig.services.includes("All services");
94724
- const hasOtherServices = finalConfig.services.some((s3) => s3 !== "All services");
94725
- if (hasAllServices && hasOtherServices) {
94726
- finalConfig.services = finalConfig.services.filter((s3) => s3 !== "All services");
94727
- cliLogger.debug(`Normalized services: removed "All services", using specific services: ${finalConfig.services.join(", ")}`);
94728
- }
94729
- }
94730
94814
  }
94731
94815
  if (finalConfig.all) {
94732
94816
  finalConfig.stackName = "All stacks";
@@ -95107,7 +95191,14 @@ var handleConfigSetup = async () => {
95107
95191
  `Services to scan (comma-separated, or "all") [${cfg.services?.join(",") || "all"}]: `
95108
95192
  );
95109
95193
  if (services.trim()) {
95110
- cfg.services = services.trim().toLowerCase() === "all" ? [] : services.trim().split(",").map((s3) => s3.trim());
95194
+ if (services.trim().toLowerCase() === "all") {
95195
+ cfg.services = [];
95196
+ } else {
95197
+ const parsedServices = services.trim().split(",").map((s3) => s3.trim()).map(
95198
+ (service) => service.toLowerCase() === "all" ? "All services" : service
95199
+ ).filter((service) => isServiceName(service));
95200
+ cfg.services = parsedServices;
95201
+ }
95111
95202
  }
95112
95203
  console.log("\n\u{1F4BE} Cache configuration:");
95113
95204
  const cacheEnabled = await question(
@@ -6,7 +6,7 @@ export interface AnalyzeCommandArgs {
6
6
  withIssue?: boolean;
7
7
  output?: string;
8
8
  all?: boolean;
9
- services?: string[];
9
+ services?: ServiceName[];
10
10
  format?: string;
11
11
  yes?: boolean;
12
12
  reset?: boolean;
@@ -0,0 +1,10 @@
1
+ import type { ServiceCheckKey, ServiceName, SpecificServiceName } from '../../types/analysis.types';
2
+ export declare const SPECIFIC_SERVICE_NAMES: readonly ["IAM", "S3", "Lambda", "DynamoDB", "RDS", "EC2", "SNS", "SQS", "StepFunctions", "CloudTrail", "ApiGateway", "SecretsManager", "KMS", "EventBridge"];
3
+ export declare const normalizeServiceSelection: (services?: ServiceName[]) => {
4
+ services: ServiceName[];
5
+ removedAllServices: boolean;
6
+ defaultedToAll: boolean;
7
+ };
8
+ export declare const mapServicesToCheckKeys: (services: ServiceName[], allCheckKeys: ServiceCheckKey[]) => ServiceCheckKey[];
9
+ export declare const getServiceLabelForCheckKey: (checkKey: ServiceCheckKey) => SpecificServiceName | undefined;
10
+ export declare const isServiceName: (value: string) => value is ServiceName;
package/dist/index.js CHANGED
@@ -54682,6 +54682,85 @@ var memoize = (functionToMemoize, options = {}) => {
54682
54682
  };
54683
54683
  };
54684
54684
 
54685
+ // src/helpers/serviceSelection/serviceSelection.ts
54686
+ var SERVICE_NAME_TO_CHECK_KEYS = {
54687
+ IAM: ["iamPolicies"],
54688
+ S3: ["s3Buckets", "s3IntelligentTiering"],
54689
+ Lambda: ["lambdaEnvironmentVariables", "lambdaMemory"],
54690
+ DynamoDB: ["dynamoDBAutoScaling", "dynamoDBStreams"],
54691
+ RDS: ["rdsEncryption", "rdsMultiAZ"],
54692
+ EC2: ["ec2InstanceType", "natGatewayUsage", "securityGroups", "ebsUnusedVolumes"],
54693
+ SNS: ["sns"],
54694
+ SQS: ["sqs"],
54695
+ StepFunctions: ["stepFunctions"],
54696
+ CloudTrail: ["cloudTrailLogging"],
54697
+ ApiGateway: ["apiGateway"],
54698
+ SecretsManager: ["secretsManager"],
54699
+ KMS: ["kmsKeys"],
54700
+ EventBridge: ["eventBridgeRules"]
54701
+ };
54702
+ var CHECK_KEY_TO_SERVICE_NAME = Object.entries(
54703
+ SERVICE_NAME_TO_CHECK_KEYS
54704
+ ).reduce((acc, [service, keys]) => {
54705
+ for (const key of keys) {
54706
+ acc[key] = service;
54707
+ }
54708
+ return acc;
54709
+ }, {});
54710
+ var dedupe = (items) => {
54711
+ const seen = /* @__PURE__ */ new Set();
54712
+ const result = [];
54713
+ for (const item of items) {
54714
+ if (seen.has(item)) {
54715
+ continue;
54716
+ }
54717
+ seen.add(item);
54718
+ result.push(item);
54719
+ }
54720
+ return result;
54721
+ };
54722
+ var normalizeServiceSelection = (services) => {
54723
+ if (!services || services.length === 0) {
54724
+ return {
54725
+ services: ["All services"],
54726
+ removedAllServices: false,
54727
+ defaultedToAll: true
54728
+ };
54729
+ }
54730
+ const uniqueServices = dedupe(services);
54731
+ const hasAllServices = uniqueServices.includes("All services");
54732
+ const specificServices = uniqueServices.filter(
54733
+ (service) => service !== "All services"
54734
+ );
54735
+ if (hasAllServices && specificServices.length > 0) {
54736
+ return {
54737
+ services: specificServices,
54738
+ removedAllServices: true,
54739
+ defaultedToAll: false
54740
+ };
54741
+ }
54742
+ return {
54743
+ services: hasAllServices ? ["All services"] : uniqueServices,
54744
+ removedAllServices: false,
54745
+ defaultedToAll: false
54746
+ };
54747
+ };
54748
+ var mapServicesToCheckKeys = (services, allCheckKeys) => {
54749
+ if (services.length === 0 || services.includes("All services")) {
54750
+ return dedupe(allCheckKeys);
54751
+ }
54752
+ const resolvedKeys = services.flatMap((service) => {
54753
+ if (service === "All services") {
54754
+ return allCheckKeys;
54755
+ }
54756
+ return SERVICE_NAME_TO_CHECK_KEYS[service] ?? [];
54757
+ });
54758
+ return dedupe(resolvedKeys);
54759
+ };
54760
+ var getServiceLabelForCheckKey = (checkKey) => {
54761
+ return CHECK_KEY_TO_SERVICE_NAME[checkKey];
54762
+ };
54763
+
54685
54764
  // src/shared/logger.ts
54686
54765
  var import_strogger = __toESM(require_dist());
54687
54766
  var isDevelopment = process.env.NODE_ENV === "development";
@@ -54729,25 +54808,6 @@ var memoizedServiceChecks = memoize(createAWSServiceChecks, {
54729
54808
  // 10 minutes
54730
54809
  maxSize: 10
54731
54810
  });
54732
- var getServiceCheckKeys = (serviceName) => {
54733
- const serviceMapping = {
54734
- "Lambda": ["lambdaEnvironmentVariables", "lambdaMemory"],
54735
- "S3": ["s3Buckets", "s3IntelligentTiering"],
54736
- "DynamoDB": ["dynamoDBAutoScaling", "dynamoDBStreams"],
54737
- "RDS": ["rdsEncryption", "rdsMultiAZ"],
54738
- "EC2": ["ec2InstanceType", "natGatewayUsage", "securityGroups", "ebsUnusedVolumes"],
54739
- "IAM": ["iamPolicies"],
54740
- "SNS": ["sns"],
54741
- "SQS": ["sqs"],
54742
- "StepFunctions": ["stepFunctions"],
54743
- "CloudTrail": ["cloudTrailLogging"],
54744
- "ApiGateway": ["apiGateway"],
54745
- "SecretsManager": ["secretsManager"],
54746
- "KMS": ["kmsKeys"],
54747
- "EventBridge": ["eventBridgeRules"]
54748
- };
54749
- return serviceMapping[serviceName] || [serviceName];
54750
- };
54751
54811
  var createResourceFilter = (selectedServices) => {
54752
54812
  if (selectedServices.includes("All services")) {
54753
54813
  return (cloudFormationResource) => !cloudFormationResource.Type.startsWith("AWS::CDK::");
@@ -54764,13 +54824,16 @@ var createResourceFilter = (selectedServices) => {
54764
54824
  };
54765
54825
  var runStaticAnalysis = (cloudformationTemplate, createFinding2, selectedServices = [], solutionsRegistry = {}) => {
54766
54826
  const serviceChecks = memoizedServiceChecks();
54767
- const allServiceKeys = Object.keys(serviceChecks);
54768
- const servicesToAnalyze = selectedServices.length > 0 && !selectedServices.includes("All services") ? selectedServices : allServiceKeys.filter(
54827
+ const allServiceKeys = Object.keys(serviceChecks).filter(
54769
54828
  (serviceKey) => serviceKey !== "solutionsPatterns"
54770
54829
  );
54771
- const isAllServices = selectedServices.includes("All services") || selectedServices.length === 0;
54830
+ const { services: normalizedServices } = normalizeServiceSelection(selectedServices);
54831
+ const servicesToAnalyze = mapServicesToCheckKeys(
54832
+ normalizedServices,
54833
+ allServiceKeys
54834
+ );
54772
54835
  const analysisFindings = {};
54773
- const resourceFilter = createResourceFilter(selectedServices);
54836
+ const resourceFilter = createResourceFilter(normalizedServices);
54774
54837
  const userResources = Object.entries(cloudformationTemplate.Resources || {}).filter(
54775
54838
  ([, cloudFormationResource]) => resourceFilter(cloudFormationResource)
54776
54839
  ).reduce(
@@ -54780,37 +54843,36 @@ var runStaticAnalysis = (cloudformationTemplate, createFinding2, selectedService
54780
54843
  },
54781
54844
  {}
54782
54845
  );
54783
- for (const serviceName of servicesToAnalyze) {
54784
- const checkKeys = isAllServices ? [serviceName] : getServiceCheckKeys(serviceName);
54785
- for (const checkKey of checkKeys) {
54786
- try {
54787
- const serviceCheckFunction = serviceChecks[checkKey];
54788
- if (typeof serviceCheckFunction !== "function") {
54789
- if (checkKeys.indexOf(checkKey) === checkKeys.length - 1) {
54790
- analysisLogger.warn(
54791
- `\u26A0\uFE0F Service check function for ${serviceName} is not available`
54792
- );
54793
- }
54794
- continue;
54795
- }
54796
- const typedServiceCheckFunction = serviceCheckFunction;
54797
- const serviceAnalysisResult = typedServiceCheckFunction(
54798
- { Resources: userResources },
54799
- createFinding2
54846
+ for (const checkKey of servicesToAnalyze) {
54847
+ try {
54848
+ const serviceCheckFunction = serviceChecks[checkKey];
54849
+ if (typeof serviceCheckFunction !== "function") {
54850
+ const serviceLabel = getServiceLabelForCheckKey(checkKey) ?? checkKey;
54851
+ analysisLogger.warn(
54852
+ `\u26A0\uFE0F Service check function for ${serviceLabel} (${checkKey}) is not available`
54800
54853
  );
54801
- for (const [resourceName, resourceFindings] of Object.entries(
54802
- serviceAnalysisResult
54803
- )) {
54804
- if (!analysisFindings[resourceName]) {
54805
- analysisFindings[resourceName] = { issues: [] };
54806
- }
54807
- analysisFindings[resourceName].issues.push(...resourceFindings.issues);
54808
- }
54809
- } catch (analysisError) {
54810
- analysisLogger.warn(`\u26A0\uFE0F Error in ${serviceName} analysis (${checkKey})`, {
54811
- error: analysisError instanceof Error ? analysisError.message : String(analysisError)
54812
- });
54854
+ continue;
54813
54855
  }
54856
+ const serviceAnalysisResult = serviceCheckFunction(
54857
+ { Resources: userResources },
54858
+ createFinding2
54859
+ );
54860
+ for (const [resourceName, resourceFindings] of Object.entries(
54861
+ serviceAnalysisResult
54862
+ )) {
54863
+ if (!analysisFindings[resourceName]) {
54864
+ analysisFindings[resourceName] = { issues: [] };
54865
+ }
54866
+ analysisFindings[resourceName].issues.push(...resourceFindings.issues);
54867
+ }
54868
+ } catch (analysisError) {
54869
+ const serviceLabel = getServiceLabelForCheckKey(checkKey) ?? checkKey;
54870
+ analysisLogger.warn(
54871
+ `\u26A0\uFE0F Error in ${serviceLabel} analysis (${checkKey})`,
54872
+ {
54873
+ error: analysisError instanceof Error ? analysisError.message : String(analysisError)
54874
+ }
54875
+ );
54814
54876
  }
54815
54877
  }
54816
54878
  if (Object.keys(solutionsRegistry).length > 0) {
@@ -1,6 +1,8 @@
1
1
  import type { ConstructMetadata } from '../analysis/static/solutionConstructs/loadConstructMetadata';
2
2
  import type { AWSServiceChecks } from '../functions/factories/awsServices';
3
- export type ServiceName = Exclude<keyof AWSServiceChecks, 'solutionsPatterns'> | 'All services';
3
+ export type ServiceCheckKey = Exclude<keyof AWSServiceChecks, 'solutionsPatterns'>;
4
+ export type SpecificServiceName = 'IAM' | 'S3' | 'Lambda' | 'DynamoDB' | 'RDS' | 'EC2' | 'SNS' | 'SQS' | 'StepFunctions' | 'CloudTrail' | 'ApiGateway' | 'SecretsManager' | 'KMS' | 'EventBridge';
5
+ export type ServiceName = 'All services' | SpecificServiceName;
4
6
  export type RunAnalysisTypes = {
5
7
  stacks: Record<string, CloudFormationStack>;
6
8
  inlineFindings: Issue[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cdk-insights",
3
- "version": "0.4.6",
3
+ "version": "0.4.7-beta.0",
4
4
  "description": "AWS CDK security and cost analysis tool with AI-powered insights",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",