Skip to content

Commit

Permalink
Merge branch 'master' into allowed_values
Browse files Browse the repository at this point in the history
  • Loading branch information
kddejong authored Feb 11, 2019
2 parents 6f5dd55 + 29950a5 commit 55764bd
Show file tree
Hide file tree
Showing 42 changed files with 12,001 additions and 79 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@
- Test Ref resources to IAM Roles have good assume role documents. Example: Lambda Function Ref refers to an IAM Role that can be assume by Lambda.
- More Warnings around hard coded values (Regions, AccountIds) to help with the practice of reusability


### 0.13.2
###### Features
- Introducing the cfn-lint logo!
- Update SAM dependency version
###### Fixes
- Fix CloudWatchAlarmComparisonOperator allowed values.
- Fix typo resoruce_type_spec in several files
- Better support for nested And, Or, and Not when processing Conditions

### 0.13.1
###### CloudFormation Specifications
- Add allowed values for AWS::CloudTrail::Trail resources
Expand Down
33 changes: 26 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# CloudFormation Linter

<img alt="[cfn-lint logo]" src="https://github.com/awslabs/cfn-python-lint/blob/master/logo.png?raw=true" width="150" align="right">

[![Build Status](https://travis-ci.com/awslabs/cfn-python-lint.svg?branch=master)](https://travis-ci.com/awslabs/cfn-python-lint)
[![PyPI version](https://badge.fury.io/py/cfn-lint.svg)](https://badge.fury.io/py/cfn-lint)
[![codecov](https://codecov.io/gh/awslabs/cfn-python-lint/branch/master/graph/badge.svg)](https://codecov.io/gh/awslabs/cfn-python-lint)
Expand All @@ -8,18 +10,19 @@ Validate CloudFormation yaml/json templates against the CloudFormation spec and
checks. Includes checking valid values for resource properties and best practices.

### Warning

This is an attempt to provide validation for CloudFormation templates properties and
their values. For values things can get pretty complicated (mappings, joins, splits,
conditions, and nesting those functions inside each other) so its a best effort to
validate those values but the promise is to not fail if we can't understand or translate
all the things that could be going on.

#### Serverless Application Model

The Serverless Application Model (SAM) is supported by the linter. The template is
transformed using AWS SAM (https://github.com/awslabs/serverless-application-model)
transformed using AWS SAM [https://github.com/awslabs/serverless-application-model](https://github.com/awslabs/serverless-application-model)
before the linter processes the template.


## Install

Python 2.7+ and 3.4+ are supported.
Expand All @@ -30,6 +33,7 @@ Python 2.7+ and 3.4+ are supported.
`python setup.py clean --all` then `python setup.py install`.

### Editor Plugins

There are IDE plugins available to get direct linter feedback from you favorite editor:

* [Atom](https://atom.io/packages/atom-cfn-lint)
Expand All @@ -41,10 +45,12 @@ There are IDE plugins available to get direct linter feedback from you favorite
* [IntelliJ IDEA](https://plugins.jetbrains.com/plugin/10973-cfn-lint/update/48247)

## Basic Usage

- `cfn-lint template.yaml`
- `cfn-lint -t template.yaml`

##### Lint multiple files

Multiple files can be linted by either specifying multiple specific files:

- `cfn-lint template1.yaml template2.yaml`
Expand All @@ -53,33 +59,39 @@ Multiple files can be linted by either specifying multiple specific files:
Multiple files can also be specified using wildcards (globbing):

Lint all `yaml` files in `path`:

- `cfn-lint path/*.yaml`

Lint all `yaml` files in `path` and all subdirectories (recursive):

- `cfn-lint path/to/templates/**/*.yaml`

*Note*: Glob in Python 3.5 supports recursive searching `**/*.yaml`. If you are using an earlier version of Python you will have to handle this manually (`folder1/*.yaml`, `folder2/*.yaml`, etc).

##### Specifying the template as an input stream

The template to be linted can also be passed using standard input:

- `cat path/template.yaml | cfn-lint -`


##### Specifying the template with other parameters

- `cfn-lint -r us-east-1 ap-south-1 -- template.yaml`
- `cfn-lint -r us-east-1 ap-south-1 -t template.yaml`

## Configuration

### Command Line

From a command prompt run `cfn-lint <path to yaml template>` to run standard linting of the template.

### Config File

You can define a yaml file in your project or home folder called `.cfnlintrc`. In that file you can specify settings from the parameter section below.

Example:
```

```yaml
templates:
- test/fixtures/templates/good/**/*.yaml
include_checks:
Expand Down Expand Up @@ -107,11 +119,14 @@ Optional parameters:
| -v, --version | | | Version of cfn-lint |

### Info Rules

To maintain backwards compatibility `info` rules are not included by default. To include these rules you will need to include `-c I` or `--include-checks I`

### Metadata

Inside the root level Metadata key you can configure cfn-lint using the supported parameters.
```

```yaml
Metadata:
cfn-lint:
config:
Expand All @@ -123,33 +138,37 @@ Metadata:
```

### Precedence

cfn-lint applies the configuration from the CloudFormation Metadata first and then overrides those values with anything specified in the CLI.

### Getting Started Guides

There are [getting started guides](/docs/getting_started) available in the documentation section to help with integrating `cfn-lint` or creating rules.

## Rules

This linter checks the CloudFormation by processing a collection of Rules, where every rules handles a specific function check or validation of the template.

This collection of rules can be extended with custom rules using the `--append-rules` argument.

More information describing how rules are set up and an overview of all the Rules that are applied by this linter are documented [here](docs/rules.md)


## Customize specifications

The linter follows the [CloudFormation specifications](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-resource-specification.html) by default. However, for your use case specific requirements might exist. For example, within your organisation it might be mandatory to use [Tagging](https://aws.amazon.com/answers/account-management/aws-tagging-strategies/).

The linter provides the possibility to implement these customized specifications using the `--override-spec` argument.

More information about how this feature works is documented [here](docs/customize_specifications.md)

## pre-commit

If you'd like cfn-lint to be run automatically when making changes to files in your Git repository, you can install [pre-commit](https://pre-commit.com/) and add the following text to your repositories' `.pre-commit-config.yaml`:

```yaml
repos:
- repo: https://github.com/awslabs/cfn-python-lint
rev: v0.13.1 # The version of cfn-lint to use
rev: v0.13.2 # The version of cfn-lint to use
hooks:
- id: cfn-python-lint
files: path/to/cfn/dir/.*\.(json|yml|yaml)$
Expand Down
3 changes: 2 additions & 1 deletion docs/rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Rule `E3012` is used to check the types for value of a resource property. A num


## Rules
The following **100** rules are applied by this linter:
The following **101** rules are applied by this linter:

| Rule ID | Title | Description | Source | Tags |
| -------- | ----- | ----------- | ------ | ---- |
Expand Down Expand Up @@ -64,6 +64,7 @@ The following **100** rules are applied by this linter:
| E2010 <a name="E2010"></a> | Parameter limit not exceeded | Check the number of Parameters in the template is lessthan the upper limit | [Source](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cloudformation-limits.html) | `parameters`,`limits` |
| E2011 <a name="E2011"></a> | Parameter name limit not exceeded | Check the size of Parameter names in the template is less than the upper limit | [Source](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cloudformation-limits.html) | `parameters`,`limits` |
| E2012 <a name="E2012"></a> | Parameter value limit not exceeded | Check if the size of Parameter values in the template is less than the upper limit | [Source](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cloudformation-limits.html) | `parameters`,`limits` |
| E2014 <a name="E2014"></a> | Default value cannot use Refs | Check if Refs are not used in Parameter Defaults | [Source](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html) | `parameters` |
| E2015 <a name="E2015"></a> | Default value is within parameter constraints | Making sure the parameters have a default value inside AllowedValues, MinValue, MaxValue, AllowedPattern | [Source](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html) | `parameters` |
| E2503 <a name="E2503"></a> | Resource ELB Properties | See if Elb Resource Properties are set correctly HTTPS has certificate HTTP has no certificate | [Source](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-elb-listener.html) | `properties`,`elb` |
| E2504 <a name="E2504"></a> | Check Ec2 Ebs Properties | See if Ec2 Eb2 Properties are valid | [Source](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-blockdev-template.html) | `properties`,`ec2`,`ebs` |
Expand Down
Binary file added logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 27 additions & 13 deletions src/cfnlint/conditions.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,17 +96,24 @@ class Condition(object):
Equals = None
Influenced_Equals = None

def __init__(self, template, name):
def __init__(self, template, name=None, sub_condition=None):
self.And = []
self.Or = []
self.Not = []
self.Influenced_Equals = {}
value = template.get('Conditions', {}).get(name, {})
try:
self.process_condition(template, value)
except ConditionParseError:
LOGGER.debug('Error parsing condition: %s', name)
self.Equal = None
if name is not None:
value = template.get('Conditions', {}).get(name, {})
try:
self.process_condition(template, value)
except ConditionParseError:
LOGGER.debug('Error parsing condition: %s', name)
self.Equals = None
elif sub_condition is not None:
try:
self.process_condition(template, sub_condition)
except ConditionParseError:
LOGGER.debug('Error parsing condition: %s', name)
self.Equals = None

def test(self, scenarios):
""" Test a condition based on a scenario """
Expand All @@ -123,7 +130,6 @@ def test(self, scenarios):
if self.Not:
for n in self.Not:
return not n.test(scenarios)

return self.Equals.test(scenarios)

def process_influenced_equal(self, equal):
Expand Down Expand Up @@ -172,18 +178,26 @@ def process_function(self, template, values):
if isinstance(value, dict):
if len(value) == 1:
for k, v in value.items():
if k == 'Condition':
if k == cfnlint.helpers.FUNCTION_EQUALS:
equal = Equals(v)
self.process_influenced_equal(equal)
results.append(equal)
elif k == 'Condition':
condition = Condition(template, v)
results.append(condition)
for i_e_k, i_e_v in condition.Influenced_Equals.items():
if not self.Influenced_Equals.get(i_e_k):
self.Influenced_Equals[i_e_k] = set()
for s_v in i_e_v:
self.Influenced_Equals[i_e_k].add(s_v)
elif k == cfnlint.helpers.FUNCTION_EQUALS:
equal = Equals(v)
self.process_influenced_equal(equal)
results.append(equal)
else:
condition = Condition(template, None, value)
results.append(condition)
for i_e_k, i_e_v in condition.Influenced_Equals.items():
if not self.Influenced_Equals.get(i_e_k):
self.Influenced_Equals[i_e_k] = set()
for s_v in i_e_v:
self.Influenced_Equals[i_e_k].add(s_v)

return results

Expand Down
4 changes: 3 additions & 1 deletion src/cfnlint/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,9 @@ def get_args_filenames(cli_args):
rules = cfnlint.core.get_rules(config.append_rules, config.ignore_checks, config.include_checks)

if config.update_documentation:
cfnlint.maintenance.update_documentation(rules)
# Get ALL rules (ignore the CLI))
documentation_rules = cfnlint.core.get_rules([], [], ['I', 'E', 'W'])
cfnlint.maintenance.update_documentation(documentation_rules)
exit(0)

if config.listrules:
Expand Down
Loading

0 comments on commit 55764bd

Please sign in to comment.