Skip to content

Commit a6523fc

Browse files
authored
Merge pull request #114 from nasa/develop
Release v3.0
2 parents 0f6dd63 + 1b9cc9f commit a6523fc

32 files changed

+1053
-663
lines changed

docs/configuration-inputs.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ Each table below represents a portion of the complete `scrub.cfg` file.
9797
| COVERITY_COVBUILD_FLAGS | String | Optional | Flags to be passed into 'cov-build' command | '' |
9898
| COVERITY_COVANALYZE_FLAGS | String | Optional | Flags to be passed into the 'cov-analyze' command | '' |
9999
| COVERITY_COVFORMATERRORS_FLAGS | String | Optional | Flags to be passed into the 'cov-format-errors' command | '' |
100+
| COVERITY_CC_THRESHOLD | Integer | Optional | Set threshold for high cyclomatic complexity warnings | -1 |
100101

101102

102103
### CodeSonar Variables

docs/output.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ An example of a set of two warnings that adhere to this format:
5555

5656
## List of Output Files
5757

58-
The following section provides a description of the structure of the .scrub output directory located at `SOURCE_DIR` as specified in the `scrub.cfg` configuration file:
58+
The following section provides a description of the structure of the `.scrub` and `scrub_results` output directories located at `SOURCE_DIR` as specified in the `scrub.cfg` configuration file:
5959

6060
.scrub
6161
| VERSION (Version of SCRUB that generated results)
@@ -65,6 +65,8 @@ The following section provides a description of the structure of the .scrub outp
6565
| compiler.scrub (Filtered, aggregate results from all compilers)
6666
| p10.scrub (Filtered, aggregate results from all P10 analysis engines)
6767
| [tool].scrub (Filtered results file for each tool)
68+
| [tool]_metrics.csv (Metrics data file for each tool)
69+
| ...
6870
|
6971
|--raw_results (Directory containing unfiltered, SCRUB-formatted results)
7072
| [tool]_p10_raw.scrub (Unfiltered, SCRUB-formatted P10 results for each tool)
@@ -82,4 +84,13 @@ The following section provides a description of the structure of the .scrub outp
8284
|
8385
|--analysis_scripts (Directory containing parsed tool analysis scripts)
8486
| [tool].sh
87+
|
88+
|--sarif_files (Directory containing SARIF-formatted results files)
89+
| [tool].sarif (Output file for analysis tool)
90+
91+
scrub_results
92+
| [tool].scrub (Symbolic link to tool results file from .scrub directory)
93+
| [tool].sarif (Symbolic link to tool results file from .scrub directory)
94+
| [tool]_metrics.csv (Symbolic link to tool metrics file from .scrub directory)
95+
| ...
8596

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
sarif-tools

scrub/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
__author__ = """Lyle Barner"""
44
__email__ = '[email protected]'
5-
__version__ = '2.8.5'
5+
__version__ = '3.0'
66

77

88
# Check the Python version for compatibility

scrub/scrub.cfg

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
# Please refer to the SCRUB documentation for more detailed configuration information
1+
# Please refer to the SCRUB documentation for more detailed configuration information:
2+
# https://nasa.github.io/scrub/configuration.html
23

34
###############################################################################
45
###############################################################################
@@ -106,6 +107,7 @@ CODEQL_DATABASEANALYZE_FLAGS:
106107
# COVERITY_COVBUILD_FLAGS No String
107108
# COVERITY_COVANALYZE_FLAGS No String
108109
# COVERITY_COVFORMATERRORS_FLAGS No String
110+
# COVERITY_CC_THRESHOLD No Integer
109111
#
110112
[Coverity Variables]
111113
COVERITY_WARNINGS: False
@@ -116,6 +118,7 @@ COVERITY_CLEAN_CMD:
116118
COVERITY_COVBUILD_FLAGS:
117119
COVERITY_COVANALYZE_FLAGS:
118120
COVERITY_COVFORMATERRORS_FLAGS:
121+
COVERITY_CC_THRESHOLD:
119122

120123
# CodeSonar analysis variables
121124
# VARIABLE REQUIRED? FORMAT
@@ -177,7 +180,11 @@ SONARQUBE_CLEAN_CMD:
177180
SONARQUBE_SCANNER_FLAGS:
178181
SONARQUBE_CURL_FLAGS:
179182

180-
183+
################################################################################
184+
################################################################################
185+
## REVIEW VARIABLES
186+
################################################################################
187+
################################################################################
181188
# Collaborator upload variables
182189
# VARIABLE REQUIRED? FORMAT
183190
# COLLABORATOR_UPLOAD Yes True/False
@@ -212,7 +219,16 @@ COLLABORATOR_SRC_FILES:
212219
[SCRUB GUI Variables]
213220
SCRUB_GUI_EXPORT: False
214221

215-
###############################################################################
222+
# SARIF Import Variables
223+
# VARIABLE REQUIRED? FORMAT
224+
# SONARQUBE_IMPORT No True/False
225+
# CODESONAR_IMPORT No True/False
226+
[SARIF Import Variables]
227+
SONARQUBE_IMPORT: False
228+
CODESONAR_IMPORT: False
229+
230+
231+
################################################################################
216232
################################################################################
217233
## FILTERING VARIABLES
218234
################################################################################

scrub/scrubme.py

Lines changed: 60 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from scrub.utils.filtering import do_filtering
1212
from scrub.utils import do_clean
1313
from scrub.utils import scrub_utilities
14+
from scrub.tools.parsers import translate_results
1415

1516

1617
def parse_arguments():
@@ -40,7 +41,8 @@ def parse_arguments():
4041
logging_level = logging.INFO
4142

4243
# Run analysis
43-
main(pathlib.Path(args['config']).resolve(), args['clean'], logging_level, args['tools'], args['targets'], args['define'])
44+
main(pathlib.Path(args['config']).resolve(), args['clean'], logging_level, args['tools'], args['targets'],
45+
args['define'])
4446

4547

4648
def main(conf_file=pathlib.Path('./scrub.cfg').resolve(), clean=False, console_logging=logging.INFO, tools=None,
@@ -90,14 +92,23 @@ def main(conf_file=pathlib.Path('./scrub.cfg').resolve(), clean=False, console_l
9092
try:
9193
shutil.copyfile(conf_file, str(scrub_conf_data.get('scrub_analysis_dir').joinpath('scrub.cfg')))
9294
except PermissionError:
93-
print("WARNING: Could not create copy of configuration file {}".format(scrub_conf_data.get('scrub_analysis_dir').joinpath('scrub.cfg')))
95+
print("WARNING: Could not create copy of configuration file {}"
96+
.format(scrub_conf_data.get('scrub_analysis_dir').joinpath('scrub.cfg')))
9497

9598
# Create a VERSION file
9699
try:
97100
with open(str(scrub_conf_data.get('scrub_analysis_dir').joinpath('VERSION')), 'w') as output_fh:
98101
output_fh.write(__version__)
99102
except PermissionError:
100-
logging.warning('Could not create VERSION file {}'.format(str(scrub_conf_data.get('scrub_analysis_dir').joinpath('VERSION'))))
103+
logging.warning('Could not create VERSION file {}'
104+
.format(str(scrub_conf_data.get('scrub_analysis_dir').joinpath('VERSION'))))
105+
106+
# Check for SARIF import conflicts
107+
if scrub_conf_data.get("sonarqube_import") and scrub_conf_data.get("codesonar_import"):
108+
print("ERROR: Conflict in SARIF import instructions. "
109+
"SARIF results can only be imported into one tool at a time.")
110+
print(" Please select SONARQUBE_IMPORT or CODESONAR_IMPORT, but not both.")
111+
sys.exit(10)
101112

102113
try:
103114
# Get the templates
@@ -108,6 +119,14 @@ def main(conf_file=pathlib.Path('./scrub.cfg').resolve(), clean=False, console_l
108119
available_analysis_templates = (available_analysis_templates +
109120
scrub_conf_data.get('custom_templates').replace('\"', '').split(','))
110121

122+
# If we're doing SARIF import, we need to move that tool to the end
123+
if scrub_conf_data.get('sonarqube_import'):
124+
available_analysis_templates.remove(scrub_path.joinpath('tools/templates/sonarqube.template'))
125+
available_analysis_templates.append(scrub_path.joinpath('tools/templates/sonarqube.template'))
126+
elif scrub_conf_data.get('codesonar_import'):
127+
available_analysis_templates.remove(scrub_path.joinpath('tools/templates/codesonar.template'))
128+
available_analysis_templates.append(scrub_path.joinpath('tools/templates/codesonar.template'))
129+
111130
# Check to make sure at least one possible template has been identified
112131
if len(available_analysis_templates) == 0:
113132
print('WARNING: No analysis templates have been found.')
@@ -123,17 +142,14 @@ def main(conf_file=pathlib.Path('./scrub.cfg').resolve(), clean=False, console_l
123142
analysis_templates = []
124143
for template in available_analysis_templates:
125144
for tool in tools:
126-
if template.name == tool + '.template':
145+
if template.name == tool + '.template':
127146
analysis_templates.append(template)
128147
scrub_conf_data.update({tool.lower() + '_warnings': True})
129148
else:
130149
analysis_templates = available_analysis_templates
131150

132151
# Perform analysis using the template
133152
for analysis_template in analysis_templates:
134-
# Initialize variables
135-
execution_time = 0
136-
137153
# Get the tool name
138154
tool_name = analysis_template.stem
139155

@@ -145,6 +161,8 @@ def main(conf_file=pathlib.Path('./scrub.cfg').resolve(), clean=False, console_l
145161
analysis_scripts_dir = scrub_conf_data.get('scrub_analysis_dir').joinpath('analysis_scripts')
146162
analysis_script = analysis_scripts_dir.joinpath(tool_name + '.sh')
147163
tool_analysis_dir = scrub_conf_data.get('scrub_working_dir').joinpath(tool_name + '_analysis')
164+
sarif_import_dir = tool_analysis_dir.joinpath('sarif_imports')
165+
parser = importlib.import_module('scrub.tools.parsers.get_' + tool_name.lower() + '_warnings')
148166

149167
# Add derived values to configuration values
150168
scrub_conf_data.update({'tool_analysis_dir': tool_analysis_dir})
@@ -155,6 +173,18 @@ def main(conf_file=pathlib.Path('./scrub.cfg').resolve(), clean=False, console_l
155173
# Create the tool analysis directory
156174
scrub_utilities.create_dir(tool_analysis_dir, True, True)
157175

176+
# Is SARIF import being performed?
177+
if scrub_conf_data.get(tool_name + '_import'):
178+
scrub_utilities.create_dir(sarif_import_dir, True, True)
179+
180+
# Iterate through the existing SARIF files, process them, and drop them into the expected directory
181+
for sarif_file in list(scrub_conf_data.get('sarif_results_dir').glob('*.sarif')):
182+
if sarif_file.stem != tool_name:
183+
translate_results.format_sarif_for_upload(sarif_file,
184+
sarif_import_dir.joinpath(sarif_file.name),
185+
scrub_conf_data.get('source_dir'),
186+
tool_name)
187+
158188
# Create the log file
159189
analysis_log_file = scrub_conf_data.get('scrub_log_dir').joinpath(tool_name + '.log')
160190
scrub_utilities.create_logger(analysis_log_file, console_logging)
@@ -198,6 +228,9 @@ def main(conf_file=pathlib.Path('./scrub.cfg').resolve(), clean=False, console_l
198228
# Check the tool analysis directory
199229
scrub_utilities.check_artifact(tool_analysis_dir, True)
200230

231+
# Parse the results files
232+
parser.parse_warnings(tool_analysis_dir, scrub_conf_data)
233+
201234
# Check the raw results files
202235
for raw_results_file in scrub_conf_data.get('raw_results_dir').glob(tool_name + '_*.scrub'):
203236
scrub_utilities.check_artifact(raw_results_file, False)
@@ -226,17 +259,17 @@ def main(conf_file=pathlib.Path('./scrub.cfg').resolve(), clean=False, console_l
226259
# Calculate the execution time
227260
execution_time = time.time() - start_time
228261

229-
# Update the execution status
230-
execution_status.append([tool_name, tool_execution_status, execution_time])
262+
# Update the execution status
263+
execution_status.append([tool_name, tool_execution_status, execution_time])
231264

232-
# Perform filtering and track execution time, if necessary
233-
if perform_filtering:
234-
start_time = time.time()
235-
filtering_status = do_filtering.run_analysis(scrub_conf_data, console_logging)
236-
execution_time = time.time() - start_time
265+
# Perform filtering and track execution time, if necessary
266+
if perform_filtering:
267+
start_time = time.time()
268+
filtering_status = do_filtering.run_analysis(scrub_conf_data, console_logging)
269+
execution_time = time.time() - start_time
237270

238-
# Update the execution status
239-
execution_status.append(['filtering', filtering_status, execution_time])
271+
# Update the execution status
272+
execution_status.append(['filtering', filtering_status, execution_time])
240273

241274
finally:
242275
# Move the results back with the source code if necessary
@@ -255,15 +288,16 @@ def main(conf_file=pathlib.Path('./scrub.cfg').resolve(), clean=False, console_l
255288
shutil.rmtree(scrub_conf_data.get('scrub_working_dir'))
256289

257290
except PermissionError:
258-
print("\tWARNING: Could not move results from {} to {}".format(scrub_conf_data.get('scrub_working_dir'), scrub_conf_data.get('scrub_analysis_dir')))
291+
print("\tWARNING: Could not move results from {} to {}".format(scrub_conf_data.get('scrub_working_dir'),
292+
scrub_conf_data.get('scrub_analysis_dir')))
259293
print("\t\tResults will remain at {}".format(scrub_conf_data.get('scrub_working_dir')))
260294

261295
# Create a visible directory of results, if it doesn't already exist
262296
viewable_results_dir = scrub_conf_data.get('source_dir').joinpath('scrub_results')
263297
scrub_utilities.create_dir(viewable_results_dir, False)
264298

265299
# Create symbolic links for the output files
266-
file_extensions = ['*.scrub', 'sarif_results/*.sarif']
300+
file_extensions = ['*.scrub', 'sarif_results/*.sarif', '*_metrics.csv']
267301
for extension in file_extensions:
268302
for scrub_file in scrub_conf_data.get('scrub_analysis_dir').glob(extension):
269303
symlink_path = viewable_results_dir.joinpath(scrub_file.name)
@@ -272,8 +306,8 @@ def main(conf_file=pathlib.Path('./scrub.cfg').resolve(), clean=False, console_l
272306
os.symlink(os.path.relpath(str(scrub_file), str(viewable_results_dir)), symlink_path)
273307

274308
except PermissionError:
275-
logging.warning('Could not create symbolic link {}'.format(viewable_results_dir.joinpath(scrub_file.name)))
276-
309+
logging.warning('Could not create symbolic link {}'
310+
.format(viewable_results_dir.joinpath(scrub_file.name)))
277311

278312
# Print a status message
279313
tool_failure_count = 0
@@ -299,8 +333,11 @@ def main(conf_file=pathlib.Path('./scrub.cfg').resolve(), clean=False, console_l
299333
exit_code = 'Unknown error'
300334

301335
# Print the status message
302-
print('\t%s | %s: %s' % (time.strftime("%H:%M:%S", time.gmtime(status[2])), status[0], exit_code))
303-
print('\t--------------------------------------------------')
336+
if status[0] == 'filtering':
337+
print('\t%s | %s: %s' % (time.strftime("%H:%M:%S", time.gmtime(status[2])), status[0], exit_code))
338+
else:
339+
print('\t--------------------------------------------------')
340+
print('\t%s | %s: %s' % (time.strftime("%H:%M:%S", time.gmtime(status[2])), status[0], exit_code))
304341

305342
# Print the execution time
306343
print('\n\tTotal Execution Time: %s\n' % time.strftime("%H:%M:%S", time.gmtime(total_execution_time)))
@@ -338,4 +375,4 @@ def main(conf_file=pathlib.Path('./scrub.cfg').resolve(), clean=False, console_l
338375
getattr(module_object, "run_analysis")(scrub_conf_data, console_logging)
339376

340377
# Set the exit code
341-
sys.exit(tool_failure_count)
378+
sys.exit(tool_failure_count)

0 commit comments

Comments
 (0)