3 D\7@s0dZddlZddlZddlZddlZddlZddlmZmZddlmZddl Z ddl m Z ddl Z ddlZ ddlmZddlmZejeZGdd d eZGd d d eZGd d d eZGdddeZGdddeZGdddeZddZGddde jZGddde jZGddde jZ dS)a Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. N)deepcopycopy)datetime) ParserError) Transform)TemplateAttributeErrorc@seZdZdZdZdZdZdZgZdZ e j eZ ddZ ddZdd Zd d Zdd dZd Zd Zd ZddZeddZeddZeddZd S)CloudFormationLintRulezCloudFormation linter rulesFcCsg|_g|_i|_i|_dS)N)resource_property_typesresource_sub_property_typesconfigconfig_definition)selfrj/private/var/folders/pf/wv4htv3x0qs2c2mp0dnn0kchsvlck3/T/pip-install-emcbgzcf/cfn-lint/cfnlint/__init__.py__init__0szCloudFormationLintRule.__init__cCsd|j|jfS)Nz%s: %s)id shortdesc)rrrr__repr__6szCloudFormationLintRule.__repr__cCsd|j|j|jfS)zVerbose outputz %s: %s %s)rr description)rrrrverbose9szCloudFormationLintRule.verbosecCsdS)zInitialize the ruleNr)rcfnrrr initialize=sz!CloudFormationLintRule.initializeNcCst|jtr2x$|jjD]\}}|d|j|<qWt|trx|jD]|\}}||jkrF|j|ddkrtjj|d|j|<qF|j|ddkrt||j|<qF|j|ddkrFt ||j|<qFWdS)z Set the configuration defaulttypebooleanTstringintegerN) isinstancer dictitemsr cfnlinthelpersZ bool_comparestrint)rZconfigsZ config_nameZ config_valueskeyvaluerrr configure@s   z CloudFormationLintRule.configurecsfdd}|S)z6 Does Logging for match functions c sg}tj}tjd|j||||f||}tjd|jtjtj|tjd|j||rx~|D]v}|j|j|j} | r|jt | dd| dd| dd| dd|||j |qh|jt dddd|||j |qhW|S)ZWrapperz)Starting match function for rule %s at %sz5Complete match function for rule %s at %s. Ran in %szResults from rule %s are %s: r) rnowLOGGERdebugrget_location_yamltemplatepathappendMatchmessage) rfilenamerargskwargsmatchesstartresultsresultZ linenumbers)match_functionrrwrapper[s( z0CloudFormationLintRule.matching..wrapperr)r;r<r)r;rmatchingWs zCloudFormationLintRule.matchingcCs|js gS|j|S)zMatch the entire file)match)rr4rrrrmatchallxszCloudFormationLintRule.matchallcCs(|js gS||jkr$|j||||SgS)z$ Check for resource properties type )match_resource_propertiesr )rr4rresource_properties property_typer0rrrmatchall_resource_propertiess  z3CloudFormationLintRule.matchall_resource_propertiescCs(|js gS||jkr$|j||||SgS)z$ Check for resource properties type )match_resource_sub_propertiesr )rr4rrArBr0rrr matchall_resource_sub_propertiess  z7CloudFormationLintRule.matchall_resource_sub_properties)N)__name__ __module__ __qualname____doc__rrr source_urltags experimentallogging getLoggerloggerrrrrr'r>r@rDr=r?rCrErrrrr$s(  ! rc@sreZdZdZdddZddZdd Zd d Zd d ZddZ ddZ ddZ ddZ ddZ ddZddZdS)RulesCollectionzCollection of rulesNFcCs>g|_||_|pg|_|pg|_|p&g|_|jjddgdS)NWE)rulesinclude_experimental ignore_rules include_rulesconfigure_rulesextend)rrUrVrWrTrrrrs    zRulesCollection.__init__cCs>|j|j|jr:|jj||j|jkr:|j|j|jdS)zRegister rulesN)is_rule_enabledrrLrSr1rWr')rrulerrrregisters  zRulesCollection.registercCs t|jS)N)iterrS)rrrr__iter__szRulesCollection.__iter__cCs t|jS)N)lenrS)rrrr__len__szRulesCollection.__len__cCsLxF|D]>}|j|j|jr|jj||j|jkr|j|j|jqWdS)z Extend rulesN)rYrrLrSr1rWr')rZmorerZrrrrXs    zRulesCollection.extendcCs"djddt|jdddDS)N cSsg|] }|jqSr)r).0rZrrr sz,RulesCollection.__repr__..cSs|jS)N)r)xrrrsz*RulesCollection.__repr__..)r%)joinsortedrS)rrrrrs zRulesCollection.__repr__cCs`|r|j rdSd}x|jD]}|j|rd}qW|s:dSx |jD]}|j|rB|rBdSqBWdS)z& Cheks if an individual rule is valid FT)rTrV startswithrU)rrule_idrLZinclude_filterZ include_ruleZ ignore_rulerrrrYs    zRulesCollection.is_rule_enabledcGsy||Stk r6}ztjt|gSd}~Xnvtk r}zZ|jddrtjtjkrjt j }nt|}d}t j dddd|t j |j||gSWYdd}~XnXdS)z Run a check NE0002Fz.Unknown exception while processing rule {}: {}r()rr,r-r# ExceptionrYgetEffectiveLevelrMDEBUG traceback format_excr!r2 RuleErrorformat)rcheckr4rhr5err error_messager3rrr run_checks  zRulesCollection.run_checkc Cshg}tjjdjd}|dkr$d} n d||f} | |krdx0|jD]&} |j|j| j|| j|||| |qBW|j| ijd} | s|j| ijddkrt |t r|j| ijd}xd?Z d)S)ETemplatez#Class for a CloudFormation templatez us-east-1c Csj||_||_||_ddddddddd d g |_i|_i|_|jd |jd <|jd |jd <tjj ||_dS) NZAWSTemplateFormatVersion DescriptionMetadata ParametersMappings ConditionsrrOutputsZRulesRefzFn::Sub) r4r/regionssectionstransform_globalsZ transform_presearch_deep_keysr! conditionsr)rr4r/rrrrrs$zTemplate.__init__cCsJ|j}|j|}||t|<x(|jjD]\}}t||t||q(W|S)N) __class____new__r__dict__r rr)rmemoclsr:rrrrr __deepcopy__s   zTemplate.__deepcopy__cCstjd|jjdi}t|ts&iSt|tjr8|g}i}xJ|jD]>\}}t|trF|jdd|ks|| rF|jddk rF|||<qFW|S)zM Get Resources Filter on type when specified zGet resources from template...rrvN) r,r-r/r{rrsix string_typesr )rr resourcesr9rrrrrrs    $ zTemplate.get_resourcescCs$tjd|jjdi}|s iS|S)z Get ResourceszGet parameters from template...r)r,r-r/r{)r parametersrrrget_parameterss  zTemplate.get_parameterscCs$tjd|jjdi}|s iS|S)z Get ResourceszGet mapping from template...r)r,r-r/r{)rZmappingsrrr get_mappingss  zTemplate.get_mappingscCsJtjdg}|jjdi}t|trFx|jD]\}}|j|q0W|S)zGet all the Resource Namesz/Get the names of all resources from template...r)r,r-r/r{rrr r1)rr9rZ resourcename_rrrget_resource_namess  zTemplate.get_resource_namescCsJtjdg}|jjdi}t|trFx|jD]\}}|j|q0W|S)zGet all Parameter Namesz,Get names of all parameters from template...r)r,r-r/r{rrr r1)rr9rZ parameternamerrrrget_parameter_names s  zTemplate.get_parameter_namesc Cstjdi}|jjdi}|r^x<|jD]0\}}d|kr*i}|d|d<d|d<|||<q*W|jjdi}|rx<|jD]0\}}d|krzi}|d|d<d|d<|||<qzWdddd d d d d g}x(|D] }i}d|d<d|d<|||<qW|S)zGet all valid Refsz#Get all valid REFs from template...rrvFromrzAWS::AccountIdzAWS::NotificationARNsz AWS::NoValuezAWS::Partitionz AWS::Regionz AWS::StackIdzAWS::StackNamezAWS::URLSuffixZPseudoZPseduo)r,r-r/r{r ) rr9rnamer&elementrZ pseudoparamsZ pseudoparamrrrget_valid_refss@       zTemplate.get_valid_refsc Cstjdtjjdjd}i}|jjdi}d}x|jD]\}}d |kr<|d }|j|r|tjd |d d d ii||<q<|d |kr\} } d}t| trt | dkrx| jD]\} } | t j j krL|j | }g}x|D]B}|dd| | g|d}|j|j|dd|d|qWq| dkr~| dkr|j|dd| || g}q|j|dd| || g}qWn|j|dd| || g}t|tr| j|qt|tr| j|qW| SgS) z5Used for recursive handling of properties in the keysz#Get Sub Resource Properties from %sPathValuerNr(rz AWS::NoValue)r,r-rrpopr _get_sub_resource_propertiesr|r}r^r!r"CONDITION_FUNCTIONSget_condition_valuesrXr1)rkeysrr0r:r%Zkey_name key_valuer9r7rrsub_key sub_valueZ cond_valuesZ cond_value result_pathrrrrfsN   $        "   z%Template._get_sub_resource_propertiesc Csrtjd|g}|jd}xR|j|jD]@\}}d|dg}|jd}|r*|j|dd||}|j|q*W|S)zFilter keys of templatez"Get Properties from a resource: %srrruN)r,r-rrr r{rrX) rrr7Z resourcetyperZresource_valuer0rr9rrrget_resource_propertiess    z Template.get_resource_propertiesc Cs*g}t|trx|D]}|dd}|j|||krZ|j|||j||dd}t||tr|j|j||||qt||trxBt||D]2\}}|dd} | j||j|j||| qWqWnLt|tr&x>t|D]2\}}|dd}|j||j|j|||qW|S)z)Search deep for keys and get their valuesNr()rrr1rX_search_deep_keysr|r}) r searchTextZcfndictr0rr%ZpathproprrZ pathproparrrrrrs,           zTemplate._search_deep_keyscCs@tjd|g}|j|j||jg|j|j||jg|S)zC Search for keys in all parts of the templates z2Search for key %s as far down as the template goes)r,r-rXrr/r)rrr9rrrrs  zTemplate.search_deep_keysc Cs\tjdg}t|ts|St|dks,|Sx(t|ddD]\}}i}|dd|dg|d<t|ttfs||d<|j|q@t|dkrBt|tr.x|jD]z\}}|t j j kr|j ||d|g} t| tr|j | q|dkr|dkr(||d<|j|q||d<|j|qWn||d<|j|q@||d<|j|q@W|S) z/Evaluates conditions and brings back the valueszGet condition values...r*r(Nrrrz AWS::NoValue)r,r-rr|r^r}rr1r r!r"rrrX) rr/r0r7rrr:rrr9rrrrs<            zTemplate.get_condition_valuescCstjd||g}t|ts dS|j|}|dkr6dSt|trRt|dkr(d}d}x|jD]\}} |tjj krd}|j | |dd|g} t| t rxN| D]0} |j } | d| |<|j |j| || dqWqb|dkrb| d krbd}qbW| o| rNi} |dd| d<|| d<|j| n&i} |dd| d<|| d<|j| nt|t rxpt|D]:\} }t|trxt|dkrJd}d}xt|jD]h\}} |tjj krd}|j | |dd| |g} t| t r|j | n|dkr| d krd}qW| rv| rvi} |dd| g| d<|| d<|j| n,i} |dd| g| d<|| d<|j| n,i} |dd| g| d<|| d<|j| qjWn&i} |dd| d<|| d<|j| |S) a3 Logic for getting the value of a key Returns None if the item isn't found Returns empty list if the item is found but Ref or GetAtt Returns all the values as a list if condition Returns the value if its just a string, int, boolean, etc. zGet the value for key %s in %sNr(FTrrrz AWS::NoValue)r,r-rrr{r^r r!r"rrr|rrX get_valuesr1r})robjr%r0r7r&Z is_conditionZ is_no_valueZobj_keyZ obj_valuer9r:Z check_objZ list_indexZ list_valuerrrrs~                 zTemplate.get_valuescCs&tjd|jj|jj|jj|jjfS)zReturn location of objectzGet location of object...)r,r-Z start_marklinecolumnZend_mark)rrrrrrCs z Template._loccCs@tjd}|j|}g}x"|D]}|j|ddjqW|S)z( Gets the parameters out of a Sub Stringz \${[^!].*?}r)r(r)recompilefindallr1strip)rZ sub_stringregexZ string_paramsr9Z string_paramrrrget_sub_parametersHs    zTemplate.get_sub_parameterscCs~tjd|d}t|dkry |j||d|dd}Wn"tk r^}zWYdd}~XnX|sy(x"|D]}||dkrl|j|}qlWWn,tk r}ztj|WYdd}~XnXnt|tot|dt ry|j||d}Wn.tk r}ztj|WYdd}~XnXn\y,x&|D]}||dkr&|j|}q&WWn.tk rx}ztj|WYdd}~XnX|S)z. Get the location information zGet location of path %sNr(r) r,r-r^r.KeyErrorrAttributeErrorrr|r$)rtextr0r:rrr%rrrr.Ss4      zTemplate.get_location_yamlNc Ksxtjd||g} |j|d} xT| jD]H\} } | jdi}|r(| j|jf||d| dg||||||d | q(W| S)z Check Resource Properties zCheck property %s for %s)rrur) rr%r0 check_value check_refcheck_find_in_map check_split check_join check_sub)r,r-rr r{rXr)rrr~rrrrrrr6r7rrZresource_objectrrrrcheck_resource_propertyws  z Template.check_resource_propertyc  Kstjd||g} |j||d}|dd|g}|s:| Sx|D]~}|d}|d}t|ts|r| j|f||dd|d| qBt|dkrx|jD]\}}|tj j krhdt |j d d }|d kr |rf| j|f|j d |dd|d g|j|jd | nFtj |r| jt|f|j ||dd||gd| q|r| j|f||dd|d| qWqB|rB| j|f||dd|d| qBW| S)z% Check the value zCheck value %s for %s)rr%Nrr)r&r0r(zcheck_%szFn::r rr)r&r0rr)r,r-rrrrXr^r r!r" FUNCTIONScamel_to_snakereplacer{rrlocals)rrr%r0rrZ check_get_attrrrZcheck_import_valuerr6r7Z values_objnew_pathZ value_objr&Z child_pathZ dict_namerZ function_namerrrrsR       $"zTemplate.check_valuec Csg}|j|j|}|jjdij|ijd}|rt|}|j|st||<d|j|kr|jj|j}x\|D]T}|j|srd} x*|jD]\} } |j| | kr| d7} qW| t |krr|j |qrW|S)a Compares a path to resource to see if its available Returns scenarios that may result in the resource doesn't exist Input: Path: An array that is a Path to the object being checked Resource: The resource being compared to Output: If the resource is available the result is an empty array [] If the resource is not available you will get a an array of Condition Names and when that condition is True or False will result in the resource not being available when trying to be associated. [{'ConditionName'}: False] r ConditionTrr() get_conditions_from_pathr/r{rsetr get_scenariosrr r^r1) rr0resourcer9Zpath_conditionsZresource_conditionZtest_path_conditions scenariosscenarioZscenario_countZpath_conditionZ path_valuesrrris_resource_availables$      zTemplate.is_resource_availablecsg}|j|}t|ttfs |S|sXt|trLt|dkrL|jddkrL|Sd|dgSfddx"|D]}|j|||dqjW|S)z Get a list of object values without conditions included. Evaluates deep into the object removing any nested conditions as well r(rz AWS::NoValueN)ScenarioObjectc st|trt|dkrd|krn|jd}t|dkr|j|dd}|dk r|r^|d|S|d|Sn|jddkrdSi}x"|jD]\}}||||<qW|St|trg}x.|D]&}||} | dk r|j||qW|S|S) z7 Get the value based on the scenario resolving nesting r(zFn::Ifr*rNr)rz AWS::NoValue)rrr^r{r r|r1) r&r if_valuesif_pathZ new_objectrrnew_listr new_value) get_valuerrrs0       z@Template.get_object_without_nested_conditions..get_value)"get_condition_scenarios_below_pathrrr|r^r{r1)rrr0r9rrr)rr$get_object_without_nested_conditionss"      z-Template.get_object_without_nested_conditionscsfddi}t|trt|dkr~|jdrH||}|dk r||}qi}xd|jD]"\}}||}|dk rV|||<qVWn4i}x.|jD]"\}}||}|dk r|||<qW|S)z@ Get object values from a provided scenario cst|trt|dkrd|krn|jd}t|dkr|j|dd}|dk r|r^|d|S|d|Sn|jddkrdS|S|St|trg}x.|D]&}||}|dk r|j||qW|S|S) z7 Get the value based on the scenario resolving nesting r(zFn::Ifr*rNr)rz AWS::NoValue)rrr^r{r|r1)r&rrrrrr)rrrr/s,       z3Template.get_value_from_scenario..get_valuer(zFn::IfN)rrr^r{r )rrrr:rr%r&r)rrget_value_from_scenario*s&        z Template.get_value_from_scenariocCsg}|j|g}t|ts|S|sVt|trJt|dkrJ|jddkrJ|Sd|dgSx,|D]$}|j||}|r\|j||dq\W|S)as Gets a list of object values without conditions included Input: obj: The object/dict that makes up a set of properties Example: { "DBSnapshotIdentifier" : { "Fn::If" : [ "UseDBSnapshot", {"Ref" : "DBSnapshotName"}, {"Ref" : "AWS::NoValue"} ] } } Output: A list of objects with scenarios for the conditions played out. If Ref to AWS::NoValue remove the property Example: [ { Object: { "DBSnapshotIdentifier" : {"Ref" : "DBSnapshotName"} }, Scenario: {UseDBSnapshot: True} }, { Object: { }, Scenario: {UseDBSnapshot: False} } ] r(rz AWS::NoValueN)rr)$get_conditions_scenarios_from_objectrrr^r{rr1)rrr9rrZ result_objrrrget_object_without_conditionsbs$       z&Template.get_object_without_conditionsFc Cs|jd}i}x|D]x}t|t|kr||dt|kr|j|j|ddd|}x4|jD](\}}||kr||j|q`|||<q`WqW|jj|jS)z= get Condition Scenarios from below path zFn::Ifrr(Fr) rr^rr/r unionrrr) rr0include_if_in_functionZfn_ifsr9Zfn_ifr:Zcondition_nameZcondition_valuesrrrrs  z+Template.get_condition_scenarios_below_pathc sfddt}t|tr"|g}x|D]}t|tr(x|jD]\}}t|dkr|dkrt|dkr|j|dx^|ddD]>}t|trx.|jD]"\}}|dkr|j||i}qWqWq@|j|}q@Wq(W|jjt |S)z0 Get condition from objects cst}t|trt|dkrx|jD]X\}}|dkr&t|tr&t|dkr&|j|d|j|d}|j|d}q&Wn&t|trx|D]}|j|}qW|S)z Recursively get conditions r(zFn::Ifr*rr))rrrr^r r|addr)r&r9rr)get_conditions_from_propertyrrr s    zSTemplate.get_conditions_scenarios_from_object..get_conditions_from_propertyr(zFn::Ifr*rN) rrrr r^r rrrr|) robjsconrrrZr_cZs_kZs_vr)r rrs       z-Template.get_conditions_scenarios_from_objectTcCsx|j||||}|rtt|dkrt|ddkrt|j|dij|dijd}|rt|j|sft||<||jd|S) a Parent function to handle resources with conditions. Input: text: The object to start processing through the Path path: The path to recursively look for Output: An Object with keys being the Condition Names and the values are what if its in the True or False part of the path. {'condition': {True}} r)rrrr(rT)rr)_get_conditions_from_pathr^r{rr )rrr0Zinclude_resource_conditionsr only_lastr9 conditionrrrrs   "  z!Template.get_conditions_from_pathc s8tjd|id fdd }y|ddkr|t|dkr<|sB| r||jd}t|dkrt|dd kr||||dn||t|dkr |dtjjkr|ddkr| rS|j||d|dd||}x:|jD].\}} j|st |<|j | |<qWWn$t k r2} zWYdd} ~ XnXS) a Get the conditions and their True/False value for the path provided Input: text: The object to start processing through the Path path: The path to recursively look for Output: An Object with keys being the Condition Names and the values are what if its in the True or False part of the path. {'condition': {True}} zGet conditions for path %sNcst}|dkr|jdn|dkr.|jdn |jd}|rt|trt|dkrj|dsnt|d<|dj||d<dS) z6Test conditions for validity before providing the namer(Tr)Fr*rN)TF)rr rrr|r^r{)r&numZcon_path)r9rrget_condition_names     z>Template._get_conditions_from_path..get_condition_namerzFn::Ifr(r))N)r(r)) r,r-r^r{r!r"rr r rrr) rrr0rrrrZ child_resultsZc_r_kZc_r_vrr)r9rr s* "   "   z"Template._get_conditions_from_path)NNNNNN)NNNNNNNN)F)TTF)TF)!rFrGrHrIrrrrrrrrrrrrrrrrrrr.rrrrrrrrrr rrrrrsD     &- + O %  8':89 * rc@s*eZdZdZd ddZddZddZd S) RunnerzRun all the rulesrcCs$||_||_||_t||||_dS)N)rSr4 verbosityrr)rrSr4r/rrrrrr+szRunner.__init__cCsjtjdg}|jjjd}|dkrf|jjjdi|j_t|j|jj|jjd}|j }|j|j_|S)zTransform logiczTransform templates if neededrzAWS::Serverless-2016-10-31ZGlobalsr) r,r-rr/r{rrr4rZtransform_template)rr7Ztransform_type transformrrrr3s  zRunner.transformcstjdg}|jjdk r2|j|jj|j|j|jj}g}x|D]t fdd|DsFj j |krx|j qFd}x@|j j j D].}|j djko|j dknrd}qW|sF|j qFW|S) z Run ruleszRun scan of template...Nc3s|]}|kVqdS)Nr)rau)r>rr SszRunner.run..Fr8rT)r,r-rr/rXrSrr4ranyrZrr1r{r)rr7Z directivesZreturn_matches exception directiver)r>rrFs&      &z Runner.runN)r)rFrGrHrIrrrrrrrr(s rcCs0tjd}tjd}|jd|}|jd|jS)zl Is it ironic that this function is written in camel case, yet it converts to snake case? hmm.. z(.)([A-Z][a-z]+)z([a-z0-9])([A-Z])z\1_\2)rrsublower)sZ _underscorer1Z _underscorer2Zsubbedrrrr`s   rc@s&eZdZdZdZdZdZdZdgZdS) ParseErrorzParse Lint RuleZE0000z-Parsing error found when parsing the templatez8Checks for Null values and Duplicate values in resourcesz5https://github.com/aws-cloudformation/cfn-python-lintbaseN) rFrGrHrIrrrrJrKrrrrrks rc@s(eZdZdZdZdZdZdZddgZdS) TransformErrorzTransform Lint RuleZE0001z*Error found when transforming the templatez;Errors found when performing transformation on the templatez5https://github.com/aws-cloudformation/cfn-python-lintrrN) rFrGrHrIrrrrJrKrrrrrss rc@s(eZdZdZdZdZdZdZddgZdS) rozRule processing Errorriz%Error processing rule on the templatez3Errors found when processing a rule on the templatez5https://github.com/aws-cloudformation/cfn-python-lintrrZN) rFrGrHrIrrrrJrKrrrrro{s ro)!rIrMsysrrrmrrrrZ yaml.parserrZcfnlint.helpersr!Zcfnlint.conditionsZcfnlint.transformrZcfnlint.decode.noderrNrFr,objectrrPrr2rrrrrrorrrrs>     ve$x8