cdk-insights 0.9.0 → 0.10.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/analysis/static/awsServices/CrossResource/crossResourceChecks.d.ts +11 -0
- package/dist/analysis/static/awsServices/CrossResource/crossResourceChecks.test.d.ts +1 -0
- package/dist/analysis/static/awsServices/StackArchitecture/stackArchitectureChecks.d.ts +19 -0
- package/dist/analysis/static/awsServices/StackArchitecture/stackArchitectureChecks.test.d.ts +1 -0
- package/dist/aspects/CdkInsightsAspect.js +1 -1
- package/dist/cli/analysisJob.d.ts +8 -0
- package/dist/cli/types/cli.types.d.ts +20 -0
- package/dist/entry.js +399 -220
- package/dist/functions/factories/awsServices.d.ts +2 -0
- package/dist/helpers/analyzeResource/analyzeResource.d.ts +12 -1
- package/dist/helpers/extractInlineNagFindings/nagToWAFMap.d.ts +3 -11
- package/dist/helpers/extractResourceRelationships/extractResourceRelationships.d.ts +33 -0
- package/dist/helpers/extractResourceRelationships/extractResourceRelationships.test.d.ts +1 -0
- package/dist/helpers/extractResourceRelationships/index.d.ts +1 -0
- package/dist/helpers/generatePrompt/generatePrompt.d.ts +29 -1
- package/dist/helpers/groupResourcesByType/groupResourcesByType.d.ts +49 -0
- package/dist/helpers/groupResourcesByType/groupResourcesByType.test.d.ts +1 -0
- package/dist/helpers/redactResourceForAnalysis/index.d.ts +1 -0
- package/dist/helpers/redactResourceForAnalysis/redactResourceForAnalysis.d.ts +28 -0
- package/dist/helpers/redactResourceForAnalysis/redactResourceForAnalysis.test.d.ts +1 -0
- package/dist/helpers/sensitiveDataDetection/entropy.d.ts +52 -0
- package/dist/helpers/sensitiveDataDetection/index.d.ts +15 -0
- package/dist/helpers/sensitiveDataDetection/patterns.d.ts +53 -0
- package/dist/helpers/sensitiveDataDetection/recommendations.d.ts +16 -0
- package/dist/helpers/sensitiveDataDetection/sensitiveDataDetection.d.ts +43 -0
- package/dist/helpers/sensitiveDataDetection/sensitiveDataDetection.test.d.ts +1 -0
- package/dist/helpers/sensitiveDataDetection/types.d.ts +88 -0
- package/dist/helpers/submitFeedback/submitFeedback.d.ts +84 -0
- package/dist/helpers/submitFeedback/submitFeedback.test.d.ts +1 -0
- package/dist/index.d.ts +14 -1
- package/dist/index.js +332 -170
- package/dist/shared/cdkNagConstants.d.ts +61 -0
- package/dist/shared/cdkNagConstants.test.d.ts +1 -0
- package/dist/shared/ciDetection.d.ts +8 -1
- package/dist/types/analysis.types.d.ts +4 -0
- package/package.json +1 -1
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-Resource Relationship Static Checks
|
|
3
|
+
*
|
|
4
|
+
* These checks analyze relationships between resources to find issues
|
|
5
|
+
* that can only be detected by looking at multiple resources together.
|
|
6
|
+
*/
|
|
7
|
+
import type { CloudFormationStack, CreateFindingFunction, AnalysisResults } from '../../../../types/analysis.types';
|
|
8
|
+
/**
|
|
9
|
+
* Main entry point for cross-resource relationship checks.
|
|
10
|
+
*/
|
|
11
|
+
export declare const checkCrossResourceRelationships: (cloudformationTemplate: CloudFormationStack, createFinding: CreateFindingFunction) => AnalysisResults;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stack-Level Architecture Analysis
|
|
3
|
+
*
|
|
4
|
+
* Analyzes the overall stack composition to identify architectural patterns,
|
|
5
|
+
* cross-cutting concerns, and stack-wide recommendations.
|
|
6
|
+
*/
|
|
7
|
+
import type { CloudFormationStack, CreateFindingFunction, AnalysisResults } from '../../../../types/analysis.types';
|
|
8
|
+
/**
|
|
9
|
+
* Architecture pattern detected in the stack
|
|
10
|
+
*/
|
|
11
|
+
export type ArchitecturePattern = 'serverless' | 'container-based' | 'event-driven' | 'api-gateway' | 'data-processing' | 'static-website' | 'microservices' | 'traditional';
|
|
12
|
+
/**
|
|
13
|
+
* Main entry point for stack-level architecture checks.
|
|
14
|
+
*/
|
|
15
|
+
export declare const checkStackArchitecture: (cloudformationTemplate: CloudFormationStack, createFinding: CreateFindingFunction) => AnalysisResults;
|
|
16
|
+
/**
|
|
17
|
+
* Get detected architecture patterns for a stack (for reporting/display)
|
|
18
|
+
*/
|
|
19
|
+
export declare const getStackArchitecturePatterns: (cloudformationTemplate: CloudFormationStack) => ArchitecturePattern[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -126,4 +126,4 @@ Reference: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sso.ht
|
|
|
126
126
|
`),n,s=0,o=0;for(let i=0;i<Math.min(t,r.length);i++){let a=r[i],c=a.match(/class\s+(\w+)/),d=a.match(/(?:function\s+(\w+)|(\w+)\s*[=:]\s*(?:async\s*)?\(|(\w+)\s*\([^)]*\)\s*(?:=>|\{))/);if(c)n=c[1],o=s;else if(d){let l=d[1]||d[2]||d[3];l&&n?n=`${n}.${l}`:l&&(n=l),o=s}if(s+=(a.match(/{/g)||[]).length,s-=(a.match(/}/g)||[]).length,s<=o&&n){let l=n.split(".");l.length>1&&(n=l.slice(0,-1).join("."))}}return n},AX=(e,t,r,n)=>{try{let s=Eu.get(e);s||(s=Gt.readFileSync(e,"utf-8"),Eu.set(e,s));let o=s.split(`
|
|
127
127
|
`),i=[],a=new RegExp(`new\\s+(\\w+)\\s*\\(\\s*(?:this|\\w+)\\s*,\\s*['"\`]${Su(t)}['"\`]`,"g"),c=new RegExp(`(?:const|let|var)\\s+(${Su(t.replace(/[^a-zA-Z0-9]/g,""))})\\s*=\\s*new\\s+(\\w+)`,"gi"),d=new RegExp(`\\w+\\s*[=:]\\s*new\\s+(\\w+)\\s*\\(\\s*(?:this|\\w+)\\s*,\\s*['"\`]${Su(t)}['"\`]`,"g"),l=new RegExp(`\\.\\w+\\s*\\(\\s*['"\`]${Su(t)}['"\`]`,"g");for(let u=0;u<o.length;u++){let m=o[u],p=a.exec(m);if(p){i.push({line:u+1,column:p.index+1,constructorName:p[1],confidence:"high"}),a.lastIndex=0;continue}if(p=d.exec(m),p){i.push({line:u+1,column:p.index+1,constructorName:p[1],confidence:"high"}),d.lastIndex=0;continue}if(p=c.exec(m),p){i.push({line:u+1,column:p.index+1,constructorName:p[2],confidence:"medium"}),c.lastIndex=0;continue}p=l.exec(m),p&&(i.push({line:u+1,column:p.index+1,confidence:"low"}),l.lastIndex=0)}if(i.length>0){i.sort((B,T)=>{let A={high:0,medium:1,low:2};return A[B.confidence]-A[T.confidence]});let u=i[0],m=_t.relative(n,e),p=IX(s,u.line),h=xX(s,u.line),y=u.line,_=0,w=0,E=!1;for(let B=u.line-1;B<o.length&&B<u.line+50;B++){let T=o[B];for(let A of T)if(A==="("||A==="{")A==="("?w++:_++,E=!0;else if((A===")"||A==="}")&&(A===")"?w--:_--,E&&w<=0&&_<=0)){y=B+1;break}if(y>u.line)break}return{filePath:m.startsWith(".")?m:`./${m}`,line:u.line,column:u.column,endLine:y>u.line?y:void 0,confidence:u.confidence,method:"source_analysis",enclosingScope:p,codeSnippet:h}}}catch{}},Su=e=>e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),OX=e=>{let t=e;if(t._creationStack?.length)return t._creationStack;if(t.creationStack?.length)return t.creationStack;let r=e.node.defaultChild;if(r?._creationStack?.length)return r._creationStack;if(r?.creationStack?.length)return r.creationStack;let n=e.node.scope;for(;n;){let s=n;if(s._creationStack?.length)return s._creationStack;if(s.creationStack?.length)return s.creationStack;n=n.node?.scope}},HL=(e,t)=>{try{let r=OX(e);if(r?.length){let a=r.join(`
|
|
128
128
|
`),c=jL(a,"creation_stack");if(c)return{...c,confidence:"high"}}for(let a of e.node.metadata)if(a.trace&&Array.isArray(a.trace)){let c=a.trace.join(`
|
|
129
|
-
`),d=jL(c,"metadata_trace");if(d)return d}let n=e.node.id,s=e.node.path,o=Lr.Stack.of(e),i=PX(n,s,o.stackName,t);return i||void 0}catch{}},DX=(e,t=10)=>{let r=e.node.scope,n=0;for(;r&&n<t;){let s=r.node.id,o=r.constructor.name;if(o==="Stack"||o==="App"||!s){r=r.node.scope,n++;continue}let i=HL(r,s);if(i)return{location:i,ancestorId:s,ancestorType:o};r=r.node.scope,n++}},RX=(e,t,r)=>{let n=e.constructor.name,s={CfnSubnet:"Vpc",CfnRouteTable:"Vpc or Subnet",CfnRoute:"Vpc or Subnet",CfnSubnetRouteTableAssociation:"Subnet",CfnInternetGateway:"Vpc",CfnVPCGatewayAttachment:"Vpc",CfnNatGateway:"Vpc (public subnet)",CfnEIP:"Vpc (for NAT Gateway)",CfnSecurityGroup:"Vpc or other L2 construct",CfnSecurityGroupIngress:"SecurityGroup",CfnSecurityGroupEgress:"SecurityGroup",CfnDBSubnetGroup:"DatabaseInstance or DatabaseCluster",CfnLogGroup:"Lambda Function or other service",CfnRole:"Lambda Function, ECS Task, or other service",CfnPolicy:"Role or User",CfnInstanceProfile:"Role"};if(t&&r)return`Created by ${t.replace(/\d+$/,"")} construct '${r}'`;let o=s[n];if(o){let i=e.node.scope;if(i&&i.node){let a=i.node.id,c=i.constructor.name.replace(/\d+$/,"");if(a&&c!=="Stack")return`Created by ${c} construct '${a}'`}return`Implicitly created by ${o}`}},NX=(e,t,r,n)=>{let s=[];t&&s.push(`'${t}'`);let o=e.split("/").filter(a=>a&&a!=="Resource"&&a!=="Default"&&!a.startsWith("Cfn")),i=o[o.length-1];if(i&&i!==t&&s.push(`'${i}'`),o.length>1){let a=o[o.length-2];a&&a!==t&&a!==i&&s.push(`'${a}'`)}if(r){let a=r.replace(/\d+$/,"");s.push(`new ${a}(`)}if(n){let a=n.split("::").pop();a&&!s.some(c=>c.includes(a))&&s.push(`${a}`)}return s.length===0?`Search for: ${e}`:`Search for: ${s.slice(0,3).join(" or ")}`},LX={"AWS::S3":"Storage","AWS::DynamoDB":"Database","AWS::RDS":"Database","AWS::Lambda":"Compute","AWS::EC2":"Compute","AWS::ECS":"Containers","AWS::EKS":"Containers","AWS::IAM":"Security","AWS::KMS":"Security","AWS::SecretsManager":"Security","AWS::CloudWatch":"Management","AWS::CloudTrail":"Management","AWS::SNS":"Messaging","AWS::SQS":"Messaging","AWS::EventBridge":"Messaging","AWS::ApiGateway":"Networking","AWS::CloudFront":"Networking","AWS::ELB":"Networking","AWS::ElasticLoadBalancing":"Networking","AWS::VPC":"Networking","AWS::Route53":"Networking","AWS::Cognito":"Security","AWS::WAF":"Security","AWS::StepFunctions":"Integration","AWS::Kinesis":"Analytics","AWS::Glue":"Analytics","AWS::Athena":"Analytics","AWS::Redshift":"Analytics"},kX=[{pattern:/encryption|encrypted|kmsKey|sseSpecification/i,recommendation:"Enable encryption for data at rest",checkDefault:e=>e===!1||e===void 0||e===null},{pattern:/publicAccess|publicRead|publiclyAccessible/i,recommendation:"Restrict public access unless explicitly required",checkDefault:e=>e===!0},{pattern:/logging|accessLog|trailName/i,recommendation:"Enable logging for audit and compliance",checkDefault:e=>e===!1||e===void 0},{pattern:/versioning|versioningConfiguration/i,recommendation:"Enable versioning for data protection",checkDefault:e=>e===void 0||typeof e=="object"&&e!==null&&e.status!=="Enabled"},{pattern:/backupRetention|deletionProtection|deleteProtection/i,recommendation:"Configure backup and deletion protection",checkDefault:e=>e===!1||e===0||e===void 0},{pattern:/multiAz|multiAZ/i,recommendation:"Enable Multi-AZ for high availability",checkDefault:e=>e===!1},{pattern:/securityGroup|ingressRules|egressRules/i,recommendation:"Review security group rules"},{pattern:/iamRole|assumeRolePolicy|policyDocument/i,recommendation:"Review IAM permissions for least privilege"}],MX=e=>{try{let t=e.node.scope;if(!t)return{};let r=t.constructor.name;if(r.startsWith("Cfn")){let n=t.node?.scope;if(n)return{l2Type:n.constructor.name,l2Id:n.node?.id,l2Fqn:Gh(n)}}else return{l2Type:r,l2Id:t.node?.id,l2Fqn:Gh(t)}}catch{}return{}},Gh=e=>{try{let t=e;if(t.constructor.__jsii__?.fqn)return t.constructor.__jsii__.fqn;if(typeof t.constructor.fqn=="string")return t.constructor.fqn;let r=e.constructor.name;return r.startsWith("Cfn")?`aws-cdk-lib.${r}`:r}catch{return}},FX=e=>{let t=[];try{let r=e;for(;r;)t.unshift({id:r.node.id,type:r.constructor.name,fqn:Gh(r)}),r=r.node.scope}catch{}return t},jX=e=>{for(let[t,r]of Object.entries(LX))if(e.startsWith(t))return r},UX=e=>{let t=[];try{let n=e.cfnProperties;if(!n)return t;let s=(i,a)=>{for(let{pattern:c,recommendation:d,checkDefault:l}of kX)if(c.test(i)){let u=l?l(a):void 0,m=null;typeof a=="boolean"||typeof a=="number"?m=a:a==null?m=null:typeof a=="string"&&!Lr.Token.isUnresolved(a)?m=a.length>50?`${a.substring(0,47)}...`:a:typeof a=="string"?m="[Token]":m="[Object]",t.push({path:i,value:m,isDefault:u,recommendation:u?d:void 0});break}},o=(i,a="")=>{for(let[c,d]of Object.entries(i)){let l=a?`${a}.${c}`:c;s(l,d),d&&typeof d=="object"&&!Array.isArray(d)&&!Lr.Token.isUnresolved(d)&&o(d,l)}};o(n)}catch{}return t},BX=e=>{try{let r=e.cfnProperties;if(!r)return!0;let n=0;for(let s of Object.values(r))s!==void 0&&!Lr.Token.isUnresolved(s)&&n++;return n<3}catch{return!1}},$X=(e,t={})=>{let{captureSourceLocation:r=!0,captureTags:n=!0,captureRelationships:s=!0,captureHierarchy:o=!0,captureDependencies:i=!0,captureSensitiveProperties:a=!0}=t;if(!("cfnResourceType"in e))return null;let c=Lr.Stack.of(e),d=e.node.path,l=e.constructor.name,u=e.node.id,m=e,p=m.cfnResourceType,h;try{h=c.getLogicalId(m)}catch{}let{l2Type:y,l2Id:_}=MX(e),w=_?`${_} (${y||l})`:`${u} (${l})`,E={source:"cdk_insights",version:UL,stackName:c.stackName,stackId:c.node.id,constructPath:d,constructType:l,friendlyName:w,timestamp:new Date().toISOString(),cfnResourceType:p};u&&(E.id=u),h&&(E.logicalId=h),y&&(E.l2ConstructType=y),_&&(E.l2ConstructId=_);let B=jX(p);if(B&&(E.serviceCategory=B),r){let T=HL(e,_);if(T)E.sourceLocation=T;else{let H=DX(e);H&&(E.rootSourceLocation=H.location),E.searchHint=NX(d,_,y,p)}let A=RX(e,y,_);A&&(E.createdBy=A)}if(s){let T=e.node.scope;T&&(E.parentPath=T.node.path),E.childCount=e.node.children.length}if(o){let T=FX(e);T.length>0&&(E.constructHierarchy=T)}if(i)try{let T=e.node.dependencies;if(T.length>0){let A=[];for(let H of T)if("cfnResourceType"in H)try{let Z=c.getLogicalId(H);Z&&A.push(Z)}catch{}A.length>0&&(E.dependencies=A)}}catch{}if(a){let T=UX(e);T.length>0&&(E.sensitiveProperties=T),E.usesDefaults=BX(e)}if(n)try{let T=m.tagsRaw;if(T&&Object.keys(T).length>0)E.tags=T;else{let A=m.tags;if(A&&typeof A.renderTags=="function"){let H=A.renderTags();H&&Object.keys(H).length>0&&(E.tags=H)}}}catch{}try{let T=c.cdkVersion;T&&(E.cdkVersion=T)}catch{}return E},qL=(e,t,r={})=>{if(CX(),t)try{t.visit(e)}catch(s){Pe.warn(`CDK-Nag error suppressed for ${e.node.path}: ${s.message}`)}let n=$X(e,{captureSourceLocation:r.captureSourceLocation,captureTags:r.captureTags,captureRelationships:r.captureRelationships,captureHierarchy:r.captureHierarchy,captureDependencies:r.captureDependencies,captureSensitiveProperties:r.captureSensitiveProperties});n&&Lr.Annotations.of(e).addInfo(`${BL}${JSON.stringify(n)}`)},zX=(e={})=>{let{logCompliance:t=!1,logNotApplicable:r=!1,verbose:n=!1}=e;return{onCompliance:s=>{t&&Pe.debug(`\u2713 ${s.resource.logicalId} is compliant with ${s.ruleId}`)},onNonCompliance:s=>{Pe.warn(`\u2717 ${s.resource.logicalId} is non-compliant with ${s.ruleId}: ${s.ruleInfo}`)},onSuppressed:s=>{n&&Pe.info(`\u2298 ${s.ruleId} suppressed on ${s.resource.logicalId}: ${s.suppressionReason}`)},onError:s=>{Pe.error(`\u26A0 ${s.ruleId} error during validation: ${s.errorMessage}`)},onSuppressedError:s=>{n&&Pe.warn(`\u2298 ${s.ruleId} error suppressed: ${s.errorSuppressionReason}`)},onNotApplicable:s=>{r&&n&&Pe.debug(`- ${s.ruleId} not applicable to ${s.resource.logicalId}`)}}},HX=(e={})=>{let{logCompliance:t=!0,logNotApplicable:r=!1,verbose:n=!1}=e;return{onCompliance:s=>{t&&Pe.info(`Yay! ${s.resource.logicalId} is compliant with ${s.ruleId}`)},onNonCompliance:s=>{Pe.warn(`Boo! ${s.resource.logicalId} is non-compliant with ${s.ruleId}`)},onSuppressed:s=>{n&&Pe.info(`Hmmmm... ${s.ruleId} has been suppressed on ${s.resource.logicalId} with reason: ${s.suppressionReason}`)},onError:s=>{Pe.error(`WHAT?!?! ${s.ruleId} encountered an error during validation!`)},onSuppressedError:s=>{n&&Pe.warn(`PHEW! ${s.ruleId} error was suppressed: ${s.errorSuppressionReason}`)},onNotApplicable:s=>{r&&n&&Pe.debug(`Meh. ${s.ruleId} and ${s.resource.logicalId} aren't related at all.`)}}},qX=(e={})=>{let{runNagChecks:t=!0,captureSourceLocation:r=!0,captureTags:n=!0,captureRelationships:s=!0,captureHierarchy:o=!0,captureDependencies:i=!0,captureSensitiveProperties:a=!0}=e,c=t?new xa.AwsSolutionsChecks:null;return{visit:d=>{qL(d,c,{captureSourceLocation:r,captureTags:n,captureRelationships:s,captureHierarchy:o,captureDependencies:i,captureSensitiveProperties:a})}}},Cu=class{options;constructor(t={}){this.options={logCompliance:!0,logNotApplicable:!1,verbose:!1,...t}}onCompliance(t){this.options.logCompliance&&Pe.info(`Yay! ${t.resource.logicalId} is compliant with ${t.ruleId}`)}onNonCompliance(t){Pe.warn(`Boo! ${t.resource.logicalId} is non-compliant with ${t.ruleId}`)}onSuppressed(t){this.options.verbose&&Pe.info(`Hmmmm... ${t.ruleId} has been suppressed on ${t.resource.logicalId} with reason: ${t.suppressionReason}`)}onError(t){Pe.error(`WHAT?!?! ${t.ruleId} encountered an error during validation!`)}onSuppressedError(t){this.options.verbose&&Pe.warn(`PHEW! ${t.ruleId} error was suppressed: ${t.errorSuppressionReason}`)}onNotApplicable(t){this.options.logNotApplicable&&this.options.verbose&&Pe.debug(`Meh. ${t.ruleId} and ${t.resource.logicalId} aren't related at all.`)}},Vh=class extends xa.NagPack{delegate;options;constructor(t){super(t),this.packName="CdkInsights",this.options={runNagChecks:t?.runNagChecks??!0,captureSourceLocation:t?.captureSourceLocation??!0,captureTags:t?.captureTags??!0,captureRelationships:t?.captureRelationships??!0,captureHierarchy:t?.captureHierarchy??!0,captureDependencies:t?.captureDependencies??!0,captureSensitiveProperties:t?.captureSensitiveProperties??!0,logger:t?.logger},this.loggers.push(new Cu(this.options.logger)),this.delegate=new xa.AwsSolutionsChecks}visit(t){qL(t,this.options.runNagChecks?this.delegate:null,this.options)}};var GX=()=>{Eu.clear(),Ho.clear(),Pn.clear(),qh=!1},VX=()=>({sourceFiles:Eu.size,constructLocations:Ho.size,sourceMaps:Pn.size});0&&(module.exports={CDK_INSIGHTS_ANNOTATION_PREFIX,CDK_INSIGHTS_METADATA_VERSION,CdkInsightsAspect,ExtremelyHelpfulConsoleLogger,clearCaches,createCdkInsightsAspect,createCdkInsightsLogger,createExtremelyHelpfulConsoleLogger,getCacheStats,isCdkDebugEnabled});
|
|
129
|
+
`),d=jL(c,"metadata_trace");if(d)return d}let n=e.node.id,s=e.node.path,o=Lr.Stack.of(e),i=PX(n,s,o.stackName,t);return i||void 0}catch{}},DX=(e,t=10)=>{let r=e.node.scope,n=0;for(;r&&n<t;){let s=r.node.id,o=r.constructor.name;if(o==="Stack"||o==="App"||!s){r=r.node.scope,n++;continue}let i=HL(r,s);if(i)return{location:i,ancestorId:s,ancestorType:o};r=r.node.scope,n++}},RX=(e,t,r)=>{let n=e.constructor.name,s={CfnSubnet:"Vpc",CfnRouteTable:"Vpc or Subnet",CfnRoute:"Vpc or Subnet",CfnSubnetRouteTableAssociation:"Subnet",CfnInternetGateway:"Vpc",CfnVPCGatewayAttachment:"Vpc",CfnNatGateway:"Vpc (public subnet)",CfnEIP:"Vpc (for NAT Gateway)",CfnSecurityGroup:"Vpc or other L2 construct",CfnSecurityGroupIngress:"SecurityGroup",CfnSecurityGroupEgress:"SecurityGroup",CfnDBSubnetGroup:"DatabaseInstance or DatabaseCluster",CfnLogGroup:"Lambda Function or other service",CfnRole:"Lambda Function, ECS Task, or other service",CfnPolicy:"Role or User",CfnInstanceProfile:"Role"};if(t&&r)return`Created by ${t.replace(/\d+$/,"")} construct '${r}'`;let o=s[n];if(o){let i=e.node.scope;if(i&&i.node){let a=i.node.id,c=i.constructor.name.replace(/\d+$/,"");if(a&&c!=="Stack")return`Created by ${c} construct '${a}'`}return`Implicitly created by ${o}`}},NX=(e,t,r,n)=>{let s=[];t&&s.push(`'${t}'`);let o=e.split("/").filter(a=>a&&a!=="Resource"&&a!=="Default"&&!a.startsWith("Cfn")),i=o[o.length-1];if(i&&i!==t&&s.push(`'${i}'`),o.length>1){let a=o[o.length-2];a&&a!==t&&a!==i&&s.push(`'${a}'`)}if(r){let a=r.replace(/\d+$/,"");s.push(`new ${a}(`)}if(n){let a=n.split("::").pop()??"";a&&!s.some(c=>c.includes(a))&&s.push(`${a}`)}return s.length===0?`Search for: ${e}`:`Search for: ${s.slice(0,3).join(" or ")}`},LX={"AWS::S3":"Storage","AWS::DynamoDB":"Database","AWS::RDS":"Database","AWS::Lambda":"Compute","AWS::EC2":"Compute","AWS::ECS":"Containers","AWS::EKS":"Containers","AWS::IAM":"Security","AWS::KMS":"Security","AWS::SecretsManager":"Security","AWS::CloudWatch":"Management","AWS::CloudTrail":"Management","AWS::SNS":"Messaging","AWS::SQS":"Messaging","AWS::EventBridge":"Messaging","AWS::ApiGateway":"Networking","AWS::CloudFront":"Networking","AWS::ELB":"Networking","AWS::ElasticLoadBalancing":"Networking","AWS::VPC":"Networking","AWS::Route53":"Networking","AWS::Cognito":"Security","AWS::WAF":"Security","AWS::StepFunctions":"Integration","AWS::Kinesis":"Analytics","AWS::Glue":"Analytics","AWS::Athena":"Analytics","AWS::Redshift":"Analytics"},kX=[{pattern:/encryption|encrypted|kmsKey|sseSpecification/i,recommendation:"Enable encryption for data at rest",checkDefault:e=>e===!1||e===void 0||e===null},{pattern:/publicAccess|publicRead|publiclyAccessible/i,recommendation:"Restrict public access unless explicitly required",checkDefault:e=>e===!0},{pattern:/logging|accessLog|trailName/i,recommendation:"Enable logging for audit and compliance",checkDefault:e=>e===!1||e===void 0},{pattern:/versioning|versioningConfiguration/i,recommendation:"Enable versioning for data protection",checkDefault:e=>e===void 0||typeof e=="object"&&e!==null&&e.status!=="Enabled"},{pattern:/backupRetention|deletionProtection|deleteProtection/i,recommendation:"Configure backup and deletion protection",checkDefault:e=>e===!1||e===0||e===void 0},{pattern:/multiAz|multiAZ/i,recommendation:"Enable Multi-AZ for high availability",checkDefault:e=>e===!1},{pattern:/securityGroup|ingressRules|egressRules/i,recommendation:"Review security group rules"},{pattern:/iamRole|assumeRolePolicy|policyDocument/i,recommendation:"Review IAM permissions for least privilege"}],MX=e=>{try{let t=e.node.scope;if(!t)return{};let r=t.constructor.name;if(r.startsWith("Cfn")){let n=t.node?.scope;if(n)return{l2Type:n.constructor.name,l2Id:n.node?.id,l2Fqn:Gh(n)}}else return{l2Type:r,l2Id:t.node?.id,l2Fqn:Gh(t)}}catch{}return{}},Gh=e=>{try{let t=e;if(t.constructor.__jsii__?.fqn)return t.constructor.__jsii__.fqn;if(typeof t.constructor.fqn=="string")return t.constructor.fqn;let r=e.constructor.name;return r.startsWith("Cfn")?`aws-cdk-lib.${r}`:r}catch{return}},FX=e=>{let t=[];try{let r=e;for(;r;)t.unshift({id:r.node.id,type:r.constructor.name,fqn:Gh(r)}),r=r.node.scope}catch{}return t},jX=e=>{for(let[t,r]of Object.entries(LX))if(e.startsWith(t))return r},UX=e=>{let t=[];try{let n=e.cfnProperties;if(!n)return t;let s=(i,a)=>{for(let{pattern:c,recommendation:d,checkDefault:l}of kX)if(c.test(i)){let u=l?l(a):void 0,m=null;typeof a=="boolean"||typeof a=="number"?m=a:a==null?m=null:typeof a=="string"&&!Lr.Token.isUnresolved(a)?m=a.length>50?`${a.substring(0,47)}...`:a:typeof a=="string"?m="[Token]":m="[Object]",t.push({path:i,value:m,isDefault:u,recommendation:u?d:void 0});break}},o=(i,a="")=>{for(let[c,d]of Object.entries(i)){let l=a?`${a}.${c}`:c;s(l,d),d&&typeof d=="object"&&!Array.isArray(d)&&!Lr.Token.isUnresolved(d)&&o(d,l)}};o(n)}catch{}return t},BX=e=>{try{let r=e.cfnProperties;if(!r)return!0;let n=0;for(let s of Object.values(r))s!==void 0&&!Lr.Token.isUnresolved(s)&&n++;return n<3}catch{return!1}},$X=(e,t={})=>{let{captureSourceLocation:r=!0,captureTags:n=!0,captureRelationships:s=!0,captureHierarchy:o=!0,captureDependencies:i=!0,captureSensitiveProperties:a=!0}=t;if(!("cfnResourceType"in e))return null;let c=Lr.Stack.of(e),d=e.node.path,l=e.constructor.name,u=e.node.id,m=e,p=m.cfnResourceType,h;try{h=c.getLogicalId(m)}catch{}let{l2Type:y,l2Id:_}=MX(e),w=_?`${_} (${y||l})`:`${u} (${l})`,E={source:"cdk_insights",version:UL,stackName:c.stackName,stackId:c.node.id,constructPath:d,constructType:l,friendlyName:w,timestamp:new Date().toISOString(),cfnResourceType:p};u&&(E.id=u),h&&(E.logicalId=h),y&&(E.l2ConstructType=y),_&&(E.l2ConstructId=_);let B=jX(p);if(B&&(E.serviceCategory=B),r){let T=HL(e,_);if(T)E.sourceLocation=T;else{let H=DX(e);H&&(E.rootSourceLocation=H.location),E.searchHint=NX(d,_,y,p)}let A=RX(e,y,_);A&&(E.createdBy=A)}if(s){let T=e.node.scope;T&&(E.parentPath=T.node.path),E.childCount=e.node.children.length}if(o){let T=FX(e);T.length>0&&(E.constructHierarchy=T)}if(i)try{let T=e.node.dependencies;if(T.length>0){let A=[];for(let H of T)if("cfnResourceType"in H)try{let Z=c.getLogicalId(H);Z&&A.push(Z)}catch{}A.length>0&&(E.dependencies=A)}}catch{}if(a){let T=UX(e);T.length>0&&(E.sensitiveProperties=T),E.usesDefaults=BX(e)}if(n)try{let T=m.tagsRaw;if(T&&Object.keys(T).length>0)E.tags=T;else{let A=m.tags;if(A&&typeof A.renderTags=="function"){let H=A.renderTags();H&&Object.keys(H).length>0&&(E.tags=H)}}}catch{}try{let T=c.cdkVersion;T&&(E.cdkVersion=T)}catch{}return E},qL=(e,t,r={})=>{if(CX(),t)try{t.visit(e)}catch(s){Pe.warn(`CDK-Nag error suppressed for ${e.node.path}: ${s.message}`)}let n=$X(e,{captureSourceLocation:r.captureSourceLocation,captureTags:r.captureTags,captureRelationships:r.captureRelationships,captureHierarchy:r.captureHierarchy,captureDependencies:r.captureDependencies,captureSensitiveProperties:r.captureSensitiveProperties});n&&Lr.Annotations.of(e).addInfo(`${BL}${JSON.stringify(n)}`)},zX=(e={})=>{let{logCompliance:t=!1,logNotApplicable:r=!1,verbose:n=!1}=e;return{onCompliance:s=>{t&&Pe.debug(`\u2713 ${s.resource.logicalId} is compliant with ${s.ruleId}`)},onNonCompliance:s=>{Pe.warn(`\u2717 ${s.resource.logicalId} is non-compliant with ${s.ruleId}: ${s.ruleInfo}`)},onSuppressed:s=>{n&&Pe.info(`\u2298 ${s.ruleId} suppressed on ${s.resource.logicalId}: ${s.suppressionReason}`)},onError:s=>{Pe.error(`\u26A0 ${s.ruleId} error during validation: ${s.errorMessage}`)},onSuppressedError:s=>{n&&Pe.warn(`\u2298 ${s.ruleId} error suppressed: ${s.errorSuppressionReason}`)},onNotApplicable:s=>{r&&n&&Pe.debug(`- ${s.ruleId} not applicable to ${s.resource.logicalId}`)}}},HX=(e={})=>{let{logCompliance:t=!0,logNotApplicable:r=!1,verbose:n=!1}=e;return{onCompliance:s=>{t&&Pe.info(`Yay! ${s.resource.logicalId} is compliant with ${s.ruleId}`)},onNonCompliance:s=>{Pe.warn(`Boo! ${s.resource.logicalId} is non-compliant with ${s.ruleId}`)},onSuppressed:s=>{n&&Pe.info(`Hmmmm... ${s.ruleId} has been suppressed on ${s.resource.logicalId} with reason: ${s.suppressionReason}`)},onError:s=>{Pe.error(`WHAT?!?! ${s.ruleId} encountered an error during validation!`)},onSuppressedError:s=>{n&&Pe.warn(`PHEW! ${s.ruleId} error was suppressed: ${s.errorSuppressionReason}`)},onNotApplicable:s=>{r&&n&&Pe.debug(`Meh. ${s.ruleId} and ${s.resource.logicalId} aren't related at all.`)}}},qX=(e={})=>{let{runNagChecks:t=!0,captureSourceLocation:r=!0,captureTags:n=!0,captureRelationships:s=!0,captureHierarchy:o=!0,captureDependencies:i=!0,captureSensitiveProperties:a=!0}=e,c=t?new xa.AwsSolutionsChecks:null;return{visit:d=>{qL(d,c,{captureSourceLocation:r,captureTags:n,captureRelationships:s,captureHierarchy:o,captureDependencies:i,captureSensitiveProperties:a})}}},Cu=class{options;constructor(t={}){this.options={logCompliance:!0,logNotApplicable:!1,verbose:!1,...t}}onCompliance(t){this.options.logCompliance&&Pe.info(`Yay! ${t.resource.logicalId} is compliant with ${t.ruleId}`)}onNonCompliance(t){Pe.warn(`Boo! ${t.resource.logicalId} is non-compliant with ${t.ruleId}`)}onSuppressed(t){this.options.verbose&&Pe.info(`Hmmmm... ${t.ruleId} has been suppressed on ${t.resource.logicalId} with reason: ${t.suppressionReason}`)}onError(t){Pe.error(`WHAT?!?! ${t.ruleId} encountered an error during validation!`)}onSuppressedError(t){this.options.verbose&&Pe.warn(`PHEW! ${t.ruleId} error was suppressed: ${t.errorSuppressionReason}`)}onNotApplicable(t){this.options.logNotApplicable&&this.options.verbose&&Pe.debug(`Meh. ${t.ruleId} and ${t.resource.logicalId} aren't related at all.`)}},Vh=class extends xa.NagPack{delegate;options;constructor(t){super(t),this.packName="CdkInsights",this.options={runNagChecks:t?.runNagChecks??!0,captureSourceLocation:t?.captureSourceLocation??!0,captureTags:t?.captureTags??!0,captureRelationships:t?.captureRelationships??!0,captureHierarchy:t?.captureHierarchy??!0,captureDependencies:t?.captureDependencies??!0,captureSensitiveProperties:t?.captureSensitiveProperties??!0,logger:t?.logger},this.loggers.push(new Cu(this.options.logger)),this.delegate=new xa.AwsSolutionsChecks}visit(t){qL(t,this.options.runNagChecks?this.delegate:null,this.options)}};var GX=()=>{Eu.clear(),Ho.clear(),Pn.clear(),qh=!1},VX=()=>({sourceFiles:Eu.size,constructLocations:Ho.size,sourceMaps:Pn.size});0&&(module.exports={CDK_INSIGHTS_ANNOTATION_PREFIX,CDK_INSIGHTS_METADATA_VERSION,CdkInsightsAspect,ExtremelyHelpfulConsoleLogger,clearCaches,createCdkInsightsAspect,createCdkInsightsLogger,createExtremelyHelpfulConsoleLogger,getCacheStats,isCdkDebugEnabled});
|
|
@@ -22,6 +22,14 @@ export interface CreateResourceAnalyzerParams {
|
|
|
22
22
|
fingerprint: string;
|
|
23
23
|
stackName: string;
|
|
24
24
|
analysisCache: FileBasedCache<SingleResourceAnalysis>;
|
|
25
|
+
/** Original resources (for relationship context) */
|
|
26
|
+
originalResources: Record<string, CloudFormationResource>;
|
|
27
|
+
/** Pre-computed relationships between resources */
|
|
28
|
+
relationships: Record<string, {
|
|
29
|
+
dependencies: string[];
|
|
30
|
+
dependents: string[];
|
|
31
|
+
usageDescription?: string;
|
|
32
|
+
}>;
|
|
25
33
|
}
|
|
26
34
|
export interface ResourceAnalyzerParams {
|
|
27
35
|
redactedId: string;
|
|
@@ -18,12 +18,27 @@ export interface AnalyzeCommandArgs {
|
|
|
18
18
|
synth?: boolean;
|
|
19
19
|
noCache?: boolean;
|
|
20
20
|
allowOveruse?: boolean;
|
|
21
|
+
local?: boolean;
|
|
22
|
+
warnSensitive?: boolean;
|
|
21
23
|
cache?: {
|
|
22
24
|
enabled?: boolean;
|
|
23
25
|
ttl?: number;
|
|
24
26
|
maxSize?: number;
|
|
25
27
|
};
|
|
26
28
|
}
|
|
29
|
+
/** Configuration for sensitive data detection */
|
|
30
|
+
export interface SensitiveDataDetectionConfig {
|
|
31
|
+
/** Enable/disable sensitive data detection (default: true) */
|
|
32
|
+
enabled?: boolean;
|
|
33
|
+
/** Treat as warning instead of critical - same as --warn-sensitive flag (default: false) */
|
|
34
|
+
warnOnly?: boolean;
|
|
35
|
+
/** Property name patterns to ignore (regex strings) */
|
|
36
|
+
allowPatterns?: string[];
|
|
37
|
+
/** Specific property paths to ignore (e.g., "Environment.Variables.SAFE_VALUE") */
|
|
38
|
+
ignoreProperties?: string[];
|
|
39
|
+
/** Extra strict detection - more false positives but catches more secrets (default: false) */
|
|
40
|
+
strictMode?: boolean;
|
|
41
|
+
}
|
|
27
42
|
/** Project-level user configuration */
|
|
28
43
|
export interface UserConfig {
|
|
29
44
|
failOnCritical?: boolean;
|
|
@@ -37,6 +52,11 @@ export interface UserConfig {
|
|
|
37
52
|
ruleFilter?: string[];
|
|
38
53
|
noCache?: boolean;
|
|
39
54
|
allowOveruse?: boolean;
|
|
55
|
+
local?: boolean;
|
|
56
|
+
warnSensitive?: boolean;
|
|
57
|
+
allowSensitive?: boolean;
|
|
58
|
+
/** Sensitive data detection configuration */
|
|
59
|
+
sensitiveDataDetection?: SensitiveDataDetectionConfig;
|
|
40
60
|
cache?: {
|
|
41
61
|
enabled?: boolean;
|
|
42
62
|
ttl?: number;
|