dusty/scanners/sast/ptai/scanner.py (84 lines of code) (raw):
#!/usr/bin/python3
# coding=utf-8
# pylint: disable=I0011,E0401,W0702,W0703
# Copyright 2019 getcarrier.io
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Scanner: PT AI
"""
import os
import traceback
from dusty.tools import log
from dusty.models.module import DependentModuleModel
from dusty.models.scanner import ScannerModel
from dusty.models.error import Error
from .parser import parse_findings
class Scanner(DependentModuleModel, ScannerModel):
""" Scanner class """
def __init__(self, context):
""" Initialize scanner instance """
super().__init__()
self.context = context
self.config = \
self.context.config["scanners"][__name__.split(".")[-3]][__name__.split(".")[-2]]
def execute(self):
""" Run the scanner """
path = self.config.get("code")
# Collect reports to parse
reports = list()
if os.path.isdir(path):
for root, _, files in os.walk(path):
for name in files:
reports.append(os.path.join(root, name))
else:
reports.append(path)
if self.config.get("mail_report", True):
if self.config.get("rename_mail_attachment", True):
filename = self.config.get(
"rename_pattern",
"PTAI_{project_name}_{testing_type}_{scan_type}_{build_id}.html"
).format(**self.context.meta)
attachment = (path, filename)
self.set_meta("report_file", attachment)
else:
self.set_meta("report_file", path)
# Parse reports
for report in reports:
try:
parse_findings(report, self)
except:
error = f"Failed to parse PT AI report {report}"
log.exception(error)
self.errors.append(Error(
tool=self.get_name(),
error=error,
details=f"```\n{traceback.format_exc()}\n```"
))
@staticmethod
def fill_config(data_obj):
""" Make sample config """
data_obj.insert(
len(data_obj),
"code", "/path/to/code",
comment="PT AI report HTML file or folder with PT AI HTML reports"
)
data_obj.insert(
len(data_obj),
"filtered_statuses", "discarded, suspected",
comment="(optional) finding statuses to filter-out"
)
data_obj.insert(
len(data_obj),
"mail_report", True,
comment="(optional) attach report to email (if email reporter is enabled)"
)
data_obj.insert(
len(data_obj),
"rename_mail_attachment", True,
comment="(optional) rename email attachment"
)
data_obj.insert(
len(data_obj),
"rename_pattern", "{project_name}_{testing_type}_{scan_type}_{build_id}.html",
comment="(optional) pattern to rename email attachment to"
)
@staticmethod
def validate_config(config):
""" Validate config """
required = ["code"]
not_set = [item for item in required if item not in config]
if not_set:
error = f"Required configuration options not set: {', '.join(not_set)}"
log.error(error)
raise ValueError(error)
@staticmethod
def get_name():
""" Module name """
return "PT AI"
@staticmethod
def get_description():
""" Module description or help message """
return "PT AI scanner report parser"