Skip to content

Commit

Permalink
Merge pull request grantmcconnaughey#22 from 23andMe/SEC-1443-write-t…
Browse files Browse the repository at this point in the history
…fsec-parser-for-Lintly

Adding tfsec parser for lintly
  • Loading branch information
nandusekarv10 authored Apr 13, 2021
2 parents e44a392 + b976fa6 commit 5c56563
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 5 deletions.
14 changes: 10 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,16 +63,21 @@ Now you will see a review with linting errors...
```
- [hadolint](https://github.com/hadolint/hadolint)
```
$ hadolint path/to/Dockerfile --format json |lintly --format=hadolint
$ hadolint path/to/Dockerfile --format json | lintly --format=hadolint
```
- [terrascan](https://github.com/accurics/terrascan)
```
$ terrascan scan -d path/to/terraform/file -o json |lintly --format=terrascan
$ terrascan scan -d path/to/terraform/file -o json | lintly --format=terrascan
```

- [trivy](https://github.com/aquasecurity/trivy)
```
$ trivy --quiet fs -f json path/to/directory/ |lintly --format=trivy
$ trivy --quiet fs -f json path/to/directory/ | lintly --format=trivy
```

- [tfsec](https://github.com/tfsec/tfsec)
```
$ tfsec path/to/directory/ -f json | lintly --format=tfsec
```

- [cfn-lint](https://github.com/aws-cloudformation/cfn-python-lint)
Expand Down Expand Up @@ -128,7 +133,8 @@ Options:
(required)
--commit-sha TEXT The commit Lintly is running against
(required)
--format [unix|flake8|pylint-json|eslint|eslint-unix|stylelint|black|cfn-lint|cfn-nag|bandit-json|gitleaks|hadolint|terrascan|trivy]
--format [unix|flake8|pylint-json|eslint|eslint-unix|stylelint|black|cfn-lint|
cfn-nag|bandit-json|gitleaks|hadolint|terrascan|trivy|tfsec]
The linting output format Lintly should
expect to receive. Default "flake8"
--context TEXT Override the commit status context
Expand Down
51 changes: 51 additions & 0 deletions lintly/parsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,54 @@ def parse_violations(self, output):
return violations


class TfsecParser(BaseLintParser):
"""
Tfsec JSON format
{
"results": [
{
"rule_id": "AWS025",
"rule_description": "API Gateway domain name uses outdated SSL/TLS protocols.",
"rule_provider": "aws",
"link": "See https://tfsec.dev/docs/aws/AWS025/ for more information.",
"location": {
"filename": "path/to/file",
"start_line": 29,
"end_line": 29
},
"description": "aws_api_gateway_domain_name.empty_security_policy defines outdated SSL/TLS).",
"severity": "ERROR",
"passed": false
}
]
}
"""

def parse_violations(self, output):
if not output:
return dict()

json_data = json.loads(output)

violations = collections.defaultdict(list)

for violation_json in json_data["results"]:
violation = Violation(
line=violation_json["location"]["start_line"],
column=0,
code="{} ({})".format(
violation_json["rule_id"], violation_json["rule_description"]
),
message=violation_json["description"],
)

path = self._normalize_path(violation_json["location"]["filename"])
violations[path].append(violation)

return violations


DEFAULT_PARSER = LineRegexParser(r'^(?P<path>.*):(?P<line>\d+):(?P<column>\d+): (?P<code>\w\d+) (?P<message>.*)$')


Expand Down Expand Up @@ -587,4 +635,7 @@ def parse_violations(self, output):

# trivy JSON output
"trivy": TrivyParser(),

# tfsec JSON output
"tfsec": TfsecParser(),
}
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def read(*parts):

setup(
name='ttam-lintly',
version='0.6.12',
version='0.6.13',
url='https://github.com/23andMe/Lintly',
license='MIT',
author='Veda Nandusekar',
Expand Down
38 changes: 38 additions & 0 deletions test.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
resource "aws_security_group_rule" "my-rule" {
type = "ingress"
cidr_blocks = ["0.0.0.0/0"]
}

resource "aws_alb_listener" "my-alb-listener"{
port = "80"
protocol = "HTTP"
}

resource "aws_db_security_group" "my-group" {

}

variable "enableEncryption" {
default = false
}

resource "azurerm_managed_disk" "source" {
encryption_settings {
enabled = var.enableEncryption
}
}

resource "aws_api_gateway_domain_name" "missing_security_policy" {
}

resource "aws_api_gateway_domain_name" "empty_security_policy" {
security_policy = ""
}

resource "aws_api_gateway_domain_name" "outdated_security_policy" {
security_policy = "TLS_1_0"
}

resource "aws_api_gateway_domain_name" "valid_security_policy" {
security_policy = "TLS_1_2"
}
32 changes: 32 additions & 0 deletions tests/linters_output/tfsec.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"results": [
{
"rule_id": "AWS004",
"rule_description": "Use of plain HTTP.",
"rule_provider": "aws",
"link": "See https://tfsec.dev/docs/aws/AWS004/ for more information.",
"location": {
"filename": "relative/path/to/file1",
"start_line": 8,
"end_line": 8
},
"description": "Resource aws_alb_listener.my-alb-listener uses plain HTTP instead of HTTPS.",
"severity": "ERROR",
"passed": false
},
{
"rule_id": "AZU003",
"rule_description": "Unencrypted managed disk.",
"rule_provider": "azure",
"link": "See https://tfsec.dev/docs/azure/AZU003/ for more information.",
"location": {
"filename": "relative/path/to/file2",
"start_line": 21,
"end_line": 21
},
"description": "Resource azurerm_managed_disk.source defines an unencrypted managed disk.",
"severity": "ERROR",
"passed": false
}
]
}
15 changes: 15 additions & 0 deletions tests/test_parsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,21 @@ class TrivyParserTestCase(ParserTestCaseMixin, unittest.TestCase):
}


class TfsecParserTestCase(ParserTestCaseMixin, unittest.TestCase):
parser = PARSERS['tfsec']
linter_output_file_name = 'tfsec.json'
expected_violations = {
'relative/path/to/file1': [
{'line': 8, 'column': 0, 'code': 'AWS004 (Use of plain HTTP.)',
'message': 'Resource aws_alb_listener.my-alb-listener uses plain HTTP instead of HTTPS.'}
],
'relative/path/to/file2': [
{'line': 21, 'column': 0, 'code': 'AZU003 (Unencrypted managed disk.)',
'message': 'Resource azurerm_managed_disk.source defines an unencrypted managed disk.'}
]
}


class PylintJSONParserTestCase(ParserTestCaseMixin, unittest.TestCase):
parser = PARSERS['pylint-json']
linter_output_file_name = 'pylint-json.txt'
Expand Down

0 comments on commit 5c56563

Please sign in to comment.