Scancode: Fix false positive reported by scancode output analyser script

ScanCode can possibly return many licenses found for a single file scanned.
This commit ensures that the file is not reported as lacking a permissive license
if at least one license found in it is permissive.
Previously the script was reporting an issue if it found at least one license
in a file that was not permissive.

Additionally catch more errors and provide specific details about failures.
Provide unitest.
pull/13745/head
Hugues Kamba 2020-10-07 21:18:07 +01:00
parent 6fa88f4247
commit 4ce6c8ac62
7 changed files with 1277 additions and 1244 deletions

View File

@ -70,7 +70,7 @@ matrix:
| ( grep -v '^tools/test/toolchains/api_test.py' || true ) \ | ( grep -v '^tools/test/toolchains/api_test.py' || true ) \
| while read file; do cp --parents "${file}" SCANCODE; done | while read file; do cp --parents "${file}" SCANCODE; done
- scancode -l --json-pp scancode.json SCANCODE - scancode -l --json-pp scancode.json SCANCODE
- python ./tools/test/travis-ci/scancode-evaluate.py -f scancode.json || true - python ./tools/test/travis-ci/scancode-evaluate.py scancode.json || true
# run the same but for new files. All new files must have SPDX # run the same but for new files. All new files must have SPDX
- >- - >-
git diff --name-only --diff-filter=A FETCH_HEAD..HEAD \ git diff --name-only --diff-filter=A FETCH_HEAD..HEAD \
@ -78,10 +78,10 @@ matrix:
| ( grep -v '^tools/test/toolchains/api_test.py' || true ) \ | ( grep -v '^tools/test/toolchains/api_test.py' || true ) \
| while read file; do cp --parents "${file}" SCANCODE_NEW_FILES; done | while read file; do cp --parents "${file}" SCANCODE_NEW_FILES; done
- scancode -l --json-pp scancode_new_files.json SCANCODE_NEW_FILES - scancode -l --json-pp scancode_new_files.json SCANCODE_NEW_FILES
- python ./tools/test/travis-ci/scancode-evaluate.py -f scancode_new_files.json || true - python ./tools/test/travis-ci/scancode-evaluate.py scancode_new_files.json || true
- cat scancode-evaluate.log - cat scancode-evaluate.log
- COUNT=$(cat scancode-evaluate.log | grep 'File:' | wc -l) || true - COUNT=$(cat scancode-evaluate.log | grep 'File:' | wc -l) || true
- python ./tools/test/travis-ci/scancode-evaluate.py -f scancode_new_files.json - python ./tools/test/travis-ci/scancode-evaluate.py scancode_new_files.json
- cat scancode-evaluate.log - cat scancode-evaluate.log
- COUNT_NEW_FILES=$(cat scancode-evaluate.log | grep 'File:' | wc -l) || true - COUNT_NEW_FILES=$(cat scancode-evaluate.log | grep 'File:' | wc -l) || true
- | - |

View File

@ -16,134 +16,149 @@ See the License for the specific language governing permissions and
limitations limitations
""" """
# Asumptions for this script:
# 1. directory_name is scanned directory.
# Files are copied to this directory with full tree. As result, if we find
# license offender, we can have full path (just scrape directory_name). We do this
# magic because scancode allows to scan directories/one file.
# 2. SPDX and license text is a must for all code files
import json
import argparse import argparse
import sys import json
import os.path
import logging import logging
import os.path
import re import re
import sys
userlog = logging.getLogger("scancode-evaluate") from enum import Enum
userlog.setLevel(logging.INFO)
logfile = os.path.join(os.getcwd(), 'scancode-evaluate.log')
log_file_handler = logging.FileHandler(logfile, mode='w')
userlog.addHandler(log_file_handler)
MISSING_LICENSE_TEXT = "Missing license header" MISSING_LICENSE_TEXT = "Missing license header"
MISSING_PERMISIVE_LICENSE_TEXT = "Non-permissive license" MISSING_PERMISSIVE_LICENSE_TEXT = "Non-permissive license"
MISSING_SPDX_TEXT = "Missing SPDX license identifier" MISSING_SPDX_TEXT = "Missing SPDX license identifier"
def license_check(directory_name, file): userlog = logging.getLogger("scancode-evaluate")
""" Check licenses in the scancode json file for specified directory
class ReturnCode(Enum):
"""Return codes."""
SUCCESS = 0
ERROR = -1
def init_logger():
"""Initialise the logger."""
userlog.setLevel(logging.INFO)
userlog.addHandler(
logging.FileHandler(
os.path.join(os.getcwd(), 'scancode-evaluate.log'), mode='w'
)
)
def path_leaf(path):
"""Return the leaf of a path."""
head, tail = os.path.split(path)
# Ensure the correct file name is returned if the file ends with a slash
return tail or os.path.basename(head)
def has_permissive_text_in_scancode_output(scancode_output_data_file_licenses):
"""Returns true if at list one license in the scancode output is permissive."""
return any(
scancode_output_data_file_license['category'] == 'Permissive'
for scancode_output_data_file_license in scancode_output_data_file_licenses
)
def has_spdx_text_in_scancode_output(scancode_output_data_file_licenses):
"""Returns true if at least one license in the scancode output has the spdx identifier."""
return any(
'spdx' in scancode_output_data_file_license['matched_rule']['identifier']
for scancode_output_data_file_license in scancode_output_data_file_licenses
)
def has_spdx_text_in_analysed_file(scanned_file_content):
"""Returns true if the file analysed by ScanCode contains SPDX identifier."""
return bool(re.findall("SPDX-License-Identifier:?", scanned_file_content))
def license_check(scancode_output_path):
"""Check licenses in the scancode json file for specified directory.
This function does not verify if file exists, should be done prior the call. This function does not verify if file exists, should be done prior the call.
Args: Args:
directory_name - where scancode was run, used to scrape this from paths scancode_output_path: path to the scancode json output file (output from scancode --license --json-pp)
file - scancode json output file (output from scancode --license --json-pp)
Returns: Returns:
0 if nothing found 0 if nothing found
>0 - count how many license isses found >0 - count how many license isses found
-1 if any error in file licenses found ReturnCode.ERROR.value if any error in file licenses found
""" """
offenders = [] offenders = []
try: try:
# find all licenses in the files, must be licensed and permissive with open(scancode_output_path, 'r') as read_file:
with open(file, 'r') as scancode_output: scancode_output_data = json.load(read_file)
results = json.load(scancode_output) except json.JSONDecodeError as jex:
except ValueError: userlog.warning("JSON could not be decoded, Invalid JSON in body: %s", jex)
userlog.warning("JSON could not be decoded") return ReturnCode.ERROR.value
return -1
try: if 'files' not in scancode_output_data:
for file in results['files']: userlog.warning("Missing `files` attribute in %s" % (scancode_output_path))
license_offender = {} return ReturnCode.ERROR.value
license_offender['file'] = file
# ignore directory, not relevant here for scancode_output_data_file in scancode_output_data['files']:
if license_offender['file']['type'] == 'directory': if scancode_output_data_file['type'] != 'file':
continue continue
if not license_offender['file']['licenses']:
license_offender['reason'] = MISSING_LICENSE_TEXT if not scancode_output_data_file['licenses']:
offenders.append(license_offender.copy()) scancode_output_data_file['fail_reason'] = MISSING_LICENSE_TEXT
offenders.append(scancode_output_data_file)
# check the next file in the scancode output
continue
if not has_permissive_text_in_scancode_output(scancode_output_data_file['licenses']):
scancode_output_data_file['fail_reason'] = MISSING_PERMISSIVE_LICENSE_TEXT
offenders.append(scancode_output_data_file)
if not has_spdx_text_in_scancode_output(scancode_output_data_file['licenses']):
# Scancode does not recognize license notice in Python file headers.
# Issue: https://github.com/nexB/scancode-toolkit/issues/1913
# Therefore check if the file tested by ScanCode actually has a licence notice.
file_path = os.path.abspath(scancode_output_data_file['path'])
try:
with open(file_path, 'r') as read_file:
scanned_file_content = read_file.read()
except UnicodeDecodeError:
userlog.warning("Unable to look for SPDX text in `{}`:".format(file_path))
# Ignore files that cannot be decoded
# check the next file in the scancode output
continue continue
found_spdx = spdx_check(offenders, license_offender) if not has_spdx_text_in_analysed_file(scanned_file_content):
scancode_output_data_file['fail_reason'] = MISSING_SPDX_TEXT
if not found_spdx: offenders.append(scancode_output_data_file)
try:
# Issue reported here https://github.com/nexB/scancode-toolkit/issues/1913
# We verify here if SPDX is not really there as SDPX is part of the license text
# scancode has some problems detecting it properly
with open(os.path.join(os.path.abspath(license_offender['file']['path'])), 'r') as spdx_file_check:
filetext = spdx_file_check.read()
matches = re.findall("SPDX-License-Identifier:?", filetext)
if matches:
continue
license_offender['reason'] = MISSING_SPDX_TEXT
offenders.append(license_offender.copy())
except UnicodeDecodeError:
# not valid file for license check
continue
except KeyError:
userlog.warning("Invalid scancode json file")
return -1
if offenders: if offenders:
userlog.warning("Found files with missing license details, please review and fix") userlog.warning("Found files with missing license details, please review and fix")
for offender in offenders: for offender in offenders:
userlog.warning("File: " + offender['file']['path'][len(directory_name):] + " " + "reason: " + offender['reason']) userlog.warning("File: %s reason: %s" % (path_leaf(offender['path']), offender['fail_reason']))
return len(offenders) return len(offenders)
def spdx_check(offenders, license_offender):
""" Parse through list of licenses to determine whether licenses are permissive
@input list of offender, individual offender dict
@output none
"""
found_spdx = False
# iterate through licenses, stop once permissive license has been found
for i in range(len(license_offender['file']['licenses'])):
# is any of the licenses permissive ?
if license_offender['file']['licenses'][i]['category'] == 'Permissive':
# confirm that it has spdx license key
if license_offender['file']['licenses'][i]['matched_rule']['identifier'].find("spdx") != -1:
found_spdx = True
# if no spdx found return anyway
return found_spdx
# otherwise file is missing permissive license
license_offender['reason'] = MISSING_PERMISIVE_LICENSE_TEXT
offenders.append(license_offender.copy())
# missing spdx and permissive license
return found_spdx
def parse_args(): def parse_args():
parser = argparse.ArgumentParser( """Parse command line arguments."""
description="License check.") parser = argparse.ArgumentParser(description="License check.")
parser.add_argument('-f', '--file', parser.add_argument(
help="scancode-toolkit output json file") 'scancode_output_path',
parser.add_argument('-d', '--directory_name', default="SCANCODE", help="scancode-toolkit output json file"
help='Directory name where are files being checked') )
return parser.parse_args() return parser.parse_args()
if __name__ == "__main__": if __name__ == "__main__":
init_logger()
args = parse_args() args = parse_args()
if args.file and os.path.isfile(args.file): if os.path.isfile(args.scancode_output_path):
count = license_check(args.directory_name, args.file) sys.exit(
if count == 0: ReturnCode.SUCCESS.value
sys.exit(0) if license_check(args.scancode_output_path) == 0
else: else ReturnCode.ERROR.value
sys.exit(-1) )
else: else:
userlog.warning("Could not find the scancode json file") userlog.warning("Could not find the scancode json file")
sys.exit(-1) sys.exit(ReturnCode.ERROR.value)

View File

@ -4,29 +4,23 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
import importlib import importlib
import os import os
import sys import pytest
from unittest import TestCase
# TODO: fix scancode to match python naming conventROOTi license_check = importlib.import_module("scancode-evaluate").license_check
SCANCODE_EVALUATE = importlib.import_module("scancode-evaluate")
license_check = SCANCODE_EVALUATE.license_check
ROOT = os.path.abspath( STUBS_PATH = os.path.join(
os.path.join(os.path.dirname(__file__)) os.path.abspath(os.path.join(os.path.dirname(__file__))), "scancode_test"
) )
# path to stub files HEADER_WITHOUT_SPDX = "/* Copyright (C) Arm Limited, Inc - All Rights Reserved\
stub_path = ROOT + "/scancode_test/"
# template copyright notices
invalid_header_1 = "/* Copyright (C) Arm Limited, Inc - All Rights Reserved\
* Unauthorized copying of this. file, via any medium is strictly prohibited\ * Unauthorized copying of this. file, via any medium is strictly prohibited\
* Proprietary and confidential\ * Proprietary and confidential\
*/" */"
invalid_header_2 = "/* mbed Microcontroller Library\ HEADER_WITH_SPDX = "/* mbed Microcontroller Library\
* Copyright (c) 2006-2013 ARM Limited\ * Copyright (c) 2006-2013 ARM Limited\
*\ *\
* SPDX-License-Identifier: Apache-2.0\
* Licensed under the Apache License, Version 2.0 (the \"License\");\ * Licensed under the Apache License, Version 2.0 (the \"License\");\
* you may not use this file except in compliance with the License.\ * you may not use this file except in compliance with the License.\
* You may obtain a copy of the License at\ * You may obtain a copy of the License at\
@ -40,67 +34,62 @@ invalid_header_2 = "/* mbed Microcontroller Library\
* limitations under the License.\ * limitations under the License.\
*/" */"
@pytest.fixture()
def create_scanned_files():
"""Create stub files.
test3.h missing license notice
test4.h with license notice
test5.h with license notice
"""
file_paths = [
os.path.join(STUBS_PATH, "test3.h"),
os.path.join(STUBS_PATH, "test4.h"),
os.path.join(STUBS_PATH, "test5.h")
]
for file_path in file_paths:
with open(file_path, "w") as new_file:
if file_path in [os.path.join(STUBS_PATH, "test3.h")]:
new_file.write(HEADER_WITHOUT_SPDX)
else:
new_file.write(HEADER_WITH_SPDX)
yield
for file_path in file_paths:
os.remove(file_path)
# implement test class
class TestScancodeEvaluate(TestCase):
""" Test scancode evaluation script """
def test_scancode_case_1(self): class TestScancodeEvaluate:
""" Test Case 1 -- faulty json file
@inputs scancode_test_1.json
@outputs -1 if any error in file licenses found
"""
expected_result = -1
test_json = ROOT + "/scancode_test/scancode_test_1.json"
# pass json path to test function def test_missing_files_attribute(self):
result = license_check(ROOT, test_json) """ Missing `files` attribute in JSON.
@inputs scancode_test/scancode_test_1.json
@outputs -1
"""
assert license_check(os.path.join(STUBS_PATH, "scancode_test_1.json")) == -1
self.assertEqual(expected_result, result) def test_various_combinations_permissive_license_with_spdx(self):
""" Various combinations where at least one license in
a file is permissive and has spdx in the match.identifier
attribute.
@inputs scancode_test/scancode_test_2.json
@outputs 0
"""
assert license_check(os.path.join(STUBS_PATH, "scancode_test_2.json")) == 0
def test_scancode_case_2(self): def test_missing_license_permissive_license_and_spdx(self, create_scanned_files):
""" Test Case 2 -- no errors in license headers, try multiple types i.e Apache-2.0, BSD3 """ Test four files scanned with various issues.
@inputs scancode_test_2.json [4 Apache-2.0, 4 BSD-3.0] test.h: Missing license text (error count += 1)
@outputs 0 test3.h: Missing `Permissive` license text and `spdx` in match.identifier and not in file tested by ScanCode (error count += 2)
""" test4.h: Missing `Permissive` license text and `spdx` in match.identifier but found in file tested by ScanCode (error count += 1)
expected_result = 0 test5.h: Missing `spdx` in match.identifier but found in file tested by ScanCode. (error count += 0)
test_json = ROOT + "/scancode_test/scancode_test_2.json" @inputs scancode_test/scancode_test_2.json
@output 4
"""
assert license_check(os.path.join(STUBS_PATH, "scancode_test_3.json")) == 4
result = license_check(ROOT, test_json) def test_permissive_license_no_spdx(self, create_scanned_files):
self.assertEqual(expected_result, result, "False Negative(s)") """ Multiple `Permissive` licenses in one file but none with `spdx` in
match.identifier and not in file tested by ScanCode (error count += 1)
def test_scancode_case_3(self): @inputs scancode_test/scancode_test_2.json
""" Test Case 3 -- all files containing errors @outputs 1
@inputs scancode_test_3.json [2 no header, 2 non-permissive + spdx, 1 missing SPDX] """
@output 5 assert license_check(os.path.join(STUBS_PATH, "scancode_test_4.json")) == 1
"""
# create stub files with a non-permissive license and missing spdx
for i in range(3, 6):
with open(stub_path + "test" + str(i) + ".h", "w") as file:
if i == 5:
file.write(invalid_header_2)
else:
file.write(invalid_header_1)
expected_result = 7
test_json = ROOT + "/scancode_test/scancode_test_3.json"
result = license_check(ROOT, test_json)
self.assertEqual(expected_result, result, "False Positive(s)")
# delete stub files
os.remove(stub_path + "test3.h")
os.remove(stub_path + "test4.h")
os.remove(stub_path + "test5.h")
def test_scancode_case_4(self):
""" Test Case 4 -- license header permissive and non-permissive 'license' [FP]
@inputs scancode_test_4.json
@outputs 0
"""
expected_result = 0
test_json = ROOT + "/scancode_test/scancode_test_4.json"
result = license_check(ROOT, test_json)
self.assertEqual(expected_result, result, "Non-Permissive Header False Positive")

View File

@ -1,7 +1,7 @@
{ {
"headers": [ "headers": [
{ {
"tool_name": "scancode test fail" "tool_name": "scancode test fail"
} }
] ]
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,169 +1,176 @@
{ {
"headers": [ "headers":[
{ {
"tool_name": "scancode-toolkit", "tool_name":"scancode-toolkit",
"tool_version": "3.1.1", "tool_version":"3.1.1",
"options": { "options":{
"input": [ "input":[
"tools/test/travis-ci/scancode_test/test.h", "tools/test/travis-ci/scancode_test/test.h",
"tools/test/travis-ci/scancode_test/test2.h", "tools/test/travis-ci/scancode_test/test2.h",
"tools/test/travis-ci/scancode_test/test3.h", "tools/test/travis-ci/scancode_test/test3.h",
"tools/test/travis-ci/scancode_test/test4.h", "tools/test/travis-ci/scancode_test/test4.h",
"tools/test/travis-ci/scancode_test/test5.h" "tools/test/travis-ci/scancode_test/test5.h"
],
"--json-pp":"scancode.json",
"--license":true
},
"notice":"Generated with ScanCode and provided on an \"AS IS\" BASIS, WITHOUT WARRANTIES\nOR CONDITIONS OF ANY KIND, either express or implied. No content created from\nScanCode should be considered or used as legal advice. Consult an Attorney\nfor any legal advice.\nScanCode is a free software code scanning tool from nexB Inc. and others.\nVisit https://github.com/nexB/scancode-toolkit/ for support and download.",
"start_timestamp":"2020-10-01T135040.106260",
"end_timestamp":"2020-10-01T135047.793497",
"message":null,
"errors":[
], ],
"--json-pp": "scancode.json", "extra_data":{
"--license": true "files_count":5
}, }
"notice": "Generated with ScanCode and provided on an \"AS IS\" BASIS, WITHOUT WARRANTIES\nOR CONDITIONS OF ANY KIND, either express or implied. No content created from\nScanCode should be considered or used as legal advice. Consult an Attorney\nfor any legal advice.\nScanCode is a free software code scanning tool from nexB Inc. and others.\nVisit https://github.com/nexB/scancode-toolkit/ for support and download.", }
"start_timestamp": "2020-10-01T135040.106260",
"end_timestamp": "2020-10-01T135047.793497",
"message": null,
"errors": [],
"extra_data": {
"files_count": 5
}
}
], ],
"files": [ "files":[
{ {
"path": "tools/test/travis-ci/scancode_test/test.h", "path":"tools/test/travis-ci/scancode_test/test.h",
"type": "file", "type":"file",
"licenses": [], "licenses":[
"license_expressions": [],
"scan_errors": [] ],
}, "license_expressions":[
{
"path": "tools/test/travis-ci/scancode_test/test2.h", ],
"type": "file", "scan_errors":[
"licenses": [],
"license_expressions": [], ]
"scan_errors": [] },
}, {
{ "path":"tools/test/travis-ci/scancode_test/test3.h",
"path": "tools/test/travis-ci/scancode_test/test3.h", "type":"file",
"type": "file", "licenses":[
"licenses": [ {
{ "key":"proprietary-license",
"key": "proprietary-license", "score":77.0,
"score": 77.0, "name":"Proprietary License",
"name": "Proprietary License", "short_name":"Proprietary License",
"short_name": "Proprietary License", "category":"Proprietary Free",
"category": "Proprietary Free", "is_exception":false,
"is_exception": false, "owner":"Unspecified",
"owner": "Unspecified", "homepage_url":null,
"homepage_url": null, "text_url":"",
"text_url": "", "reference_url":"https://enterprise.dejacode.com/urn/urn:dje:license:proprietary-license",
"reference_url": "https://enterprise.dejacode.com/urn/urn:dje:license:proprietary-license", "spdx_license_key":null,
"spdx_license_key": null, "spdx_url":"",
"spdx_url": "", "start_line":2,
"start_line": 2, "end_line":3,
"end_line": 3, "matched_rule":{
"matched_rule": { "identifier":"proprietary_12.RULE",
"identifier": "proprietary_12.RULE", "license_expression":"proprietary-license",
"license_expression": "proprietary-license", "licenses":[
"licenses": [ "proprietary-license"
"proprietary-license" ],
], "is_license_text":false,
"is_license_text": false, "is_license_notice":true,
"is_license_notice": true, "is_license_reference":false,
"is_license_reference": false, "is_license_tag":false,
"is_license_tag": false, "matcher":"2-aho",
"matcher": "2-aho", "rule_length":14,
"rule_length": 14, "matched_length":14,
"matched_length": 14, "match_coverage":100.0,
"match_coverage": 100.0, "rule_relevance":77
"rule_relevance": 77 }
} }
} ],
], "license_expressions":[
"license_expressions": [ "proprietary-license"
"proprietary-license" ],
], "scan_errors":[
"scan_errors": []
}, ]
{ },
"path": "tools/test/travis-ci/scancode_test/test4.h", {
"type": "file", "path":"tools/test/travis-ci/scancode_test/test4.h",
"licenses": [ "type":"file",
{ "licenses":[
"key": "proprietary-license", {
"score": 77.0, "key":"proprietary-license",
"name": "Proprietary License", "score":77.0,
"short_name": "Proprietary License", "name":"Proprietary License",
"category": "Proprietary Free", "short_name":"Proprietary License",
"is_exception": false, "category":"Proprietary Free",
"owner": "Unspecified", "is_exception":false,
"homepage_url": null, "owner":"Unspecified",
"text_url": "", "homepage_url":null,
"reference_url": "https://enterprise.dejacode.com/urn/urn:dje:license:proprietary-license", "text_url":"",
"spdx_license_key": null, "reference_url":"https://enterprise.dejacode.com/urn/urn:dje:license:proprietary-license",
"spdx_url": "", "spdx_license_key":null,
"start_line": 2, "spdx_url":"",
"end_line": 3, "start_line":2,
"matched_rule": { "end_line":3,
"identifier": "proprietary_12.RULE", "matched_rule":{
"license_expression": "proprietary-license", "identifier":"proprietary_12.RULE",
"licenses": [ "license_expression":"proprietary-license",
"proprietary-license" "licenses":[
], "proprietary-license"
"is_license_text": false, ],
"is_license_notice": true, "is_license_text":false,
"is_license_reference": false, "is_license_notice":true,
"is_license_tag": false, "is_license_reference":false,
"matcher": "2-aho", "is_license_tag":false,
"rule_length": 14, "matcher":"2-aho",
"matched_length": 14, "rule_length":14,
"match_coverage": 100.0, "matched_length":14,
"rule_relevance": 77 "match_coverage":100.0,
} "rule_relevance":77
} }
], }
"license_expressions": [ ],
"proprietary-license" "license_expressions":[
], "proprietary-license"
"scan_errors": [] ],
}, "scan_errors":[
{
"path": "tools/test/travis-ci/scancode_test/test5.h", ]
"type": "file", },
"licenses": [ {
{ "path":"tools/test/travis-ci/scancode_test/test5.h",
"key": "apache-2.0", "type":"file",
"score": 100.0, "licenses":[
"name": "Apache License 2.0", {
"short_name": "Apache 2.0", "key":"apache-2.0",
"category": "Permissive", "score":100.0,
"is_exception": false, "name":"Apache License 2.0",
"owner": "Apache Software Foundation", "short_name":"Apache 2.0",
"homepage_url": "http://www.apache.org/licenses/", "category":"Permissive",
"text_url": "http://www.apache.org/licenses/LICENSE-2.0", "is_exception":false,
"reference_url": "https://enterprise.dejacode.com/urn/urn:dje:license:apache-2.0", "owner":"Apache Software Foundation",
"spdx_license_key": "Apache-2.0", "homepage_url":"http://www.apache.org/licenses/",
"spdx_url": "https://spdx.org/licenses/Apache-2.0", "text_url":"http://www.apache.org/licenses/LICENSE-2.0",
"start_line": 4, "reference_url":"https://enterprise.dejacode.com/urn/urn:dje:license:apache-2.0",
"end_line": 14, "spdx_license_key":"Apache-2.0",
"matched_rule": { "spdx_url":"https://spdx.org/licenses/Apache-2.0",
"identifier": "apache-2.0_7.RULE", "start_line":4,
"license_expression": "apache-2.0", "end_line":14,
"licenses": [ "matched_rule":{
"apache-2.0" "identifier":"apache-2.0_7.RULE",
], "license_expression":"apache-2.0",
"is_license_text": false, "licenses":[
"is_license_notice": true, "apache-2.0"
"is_license_reference": false, ],
"is_license_tag": false, "is_license_text":false,
"matcher": "2-aho", "is_license_notice":true,
"rule_length": 85, "is_license_reference":false,
"matched_length": 85, "is_license_tag":false,
"match_coverage": 100.0, "matcher":"2-aho",
"rule_relevance": 100 "rule_length":85,
"matched_length":85,
"match_coverage":100.0,
"rule_relevance":100
} }
} }
], ],
"license_expressions": [ "license_expressions":[
"apache-2.0" "apache-2.0"
], ],
"scan_errors": [] "scan_errors":[
}
]
}
] ]
} }

View File

@ -1,166 +1,170 @@
{ {
"headers": [ "headers":[
{ {
"tool_name": "scancode-toolkit", "tool_name":"scancode-toolkit",
"tool_version": "3.1.1", "tool_version":"3.1.1",
"options": { "options":{
"input": [ "input":[
"test.h" "test4.h"
], ],
"--json-pp": "scancode.json", "--json-pp":"scancode.json",
"--license": true "--license":true
}, },
"notice": "Generated with ScanCode and provided on an \"AS IS\" BASIS, WITHOUT WARRANTIES\nOR CONDITIONS OF ANY KIND, either express or implied. No content created from\nScanCode should be considered or used as legal advice. Consult an Attorney\nfor any legal advice.\nScanCode is a free software code scanning tool from nexB Inc. and others.\nVisit https://github.com/nexB/scancode-toolkit/ for support and download.", "notice":"Generated with ScanCode and provided on an \"AS IS\" BASIS, WITHOUT WARRANTIES\nOR CONDITIONS OF ANY KIND, either express or implied. No content created from\nScanCode should be considered or used as legal advice. Consult an Attorney\nfor any legal advice.\nScanCode is a free software code scanning tool from nexB Inc. and others.\nVisit https://github.com/nexB/scancode-toolkit/ for support and download.",
"start_timestamp": "2020-10-01T135040.106260", "start_timestamp":"2020-10-01T135040.106260",
"end_timestamp": "2020-10-01T135047.793497", "end_timestamp":"2020-10-01T135047.793497",
"message": null, "message":null,
"errors": [], "errors":[
"extra_data": {
"files_count": 1 ],
"extra_data":{
"files_count":1
} }
} }
], ],
"files": [ "files":[
{ {
"path": "tools/test/travis-ci/scancode_test/test.h", "path":"tools/test/travis-ci/scancode_test/test3.h",
"type": "file", "type":"file",
"licenses": [ "licenses":[
{ {
"key": "bsd-new", "key":"bsd-new",
"score": 100.0, "score":100.0,
"name": "BSD-3-Clause", "name":"BSD-3-Clause",
"short_name": "BSD-3-Clause", "short_name":"BSD-3-Clause",
"category": "Permissive", "category":"Permissive",
"is_exception": false, "is_exception":false,
"owner": "Regents of the University of California", "owner":"Regents of the University of California",
"homepage_url": "http://www.opensource.org/licenses/BSD-3-Clause", "homepage_url":"http://www.opensource.org/licenses/BSD-3-Clause",
"text_url": "http://www.opensource.org/licenses/BSD-3-Clause", "text_url":"http://www.opensource.org/licenses/BSD-3-Clause",
"reference_url": "https://enterprise.dejacode.com/urn/urn:dje:license:bsd-new", "reference_url":"https://enterprise.dejacode.com/urn/urn:dje:license:bsd-new",
"spdx_license_key": "BSD-3-Clause", "spdx_license_key":"BSD-3-Clause",
"spdx_url": "https://spdx.org/licenses/BSD-3-Clause", "spdx_url":"https://spdx.org/licenses/BSD-3-Clause",
"start_line": 2, "start_line":2,
"end_line": 2, "end_line":2,
"matched_rule": { "matched_rule":{
"identifier": "spdx-license-identifier: bsd-new", "identifier":"sprdx-license-identifier: bsd-new",
"license_expression": "bsd-new", "license_expression":"bsd-new",
"licenses": [ "licenses":[
"bsd-new" "bsd-new"
], ],
"is_license_text": false, "is_license_text":false,
"is_license_notice": false, "is_license_notice":false,
"is_license_reference": false, "is_license_reference":false,
"is_license_tag": true, "is_license_tag":true,
"matcher": "1-spdx-id", "matcher":"1-spdx-id",
"rule_length": 3, "rule_length":3,
"matched_length": 3, "matched_length":3,
"match_coverage": 100.0, "match_coverage":100.0,
"rule_relevance": 100 "rule_relevance":100
} }
}, },
{ {
"key": "bsd-new", "key":"bsd-new",
"score": 100.0, "score":100.0,
"name": "BSD-3-Clause", "name":"BSD-3-Clause",
"short_name": "BSD-3-Clause", "short_name":"BSD-3-Clause",
"category": "Permissive", "category":"Permissive",
"is_exception": false, "is_exception":false,
"owner": "Regents of the University of California", "owner":"Regents of the University of California",
"homepage_url": "http://www.opensource.org/licenses/BSD-3-Clause", "homepage_url":"http://www.opensource.org/licenses/BSD-3-Clause",
"text_url": "http://www.opensource.org/licenses/BSD-3-Clause", "text_url":"http://www.opensource.org/licenses/BSD-3-Clause",
"reference_url": "https://enterprise.dejacode.com/urn/urn:dje:license:bsd-new", "reference_url":"https://enterprise.dejacode.com/urn/urn:dje:license:bsd-new",
"spdx_license_key": "BSD-3-Clause", "spdx_license_key":"BSD-3-Clause",
"spdx_url": "https://spdx.org/licenses/BSD-3-Clause", "spdx_url":"https://spdx.org/licenses/BSD-3-Clause",
"start_line": 8, "start_line":8,
"end_line": 8, "end_line":8,
"matched_rule": { "matched_rule":{
"identifier": "bsd-new_360.RULE", "identifier":"bsd-new_360.RULE",
"license_expression": "bsd-new", "license_expression":"bsd-new",
"licenses": [ "licenses":[
"bsd-new" "bsd-new"
], ],
"is_license_text": false, "is_license_text":false,
"is_license_notice": false, "is_license_notice":false,
"is_license_reference": true, "is_license_reference":true,
"is_license_tag": false, "is_license_tag":false,
"matcher": "2-aho", "matcher":"2-aho",
"rule_length": 4, "rule_length":4,
"matched_length": 4, "matched_length":4,
"match_coverage": 100.0, "match_coverage":100.0,
"rule_relevance": 100.0 "rule_relevance":100.0
} }
}, },
{ {
"key": "elastic-license-2018", "key":"elastic-license-2018",
"score": 72.22, "score":72.22,
"name": "Elastic License Agreement 2018", "name":"Elastic License Agreement 2018",
"short_name": "Elastic License 2018", "short_name":"Elastic License 2018",
"category": "Source-available", "category":"Source-available",
"is_exception": false, "is_exception":false,
"owner": "Elastic", "owner":"Elastic",
"homepage_url": "https://github.com/elastic/elasticsearch/blob/0d8aa7527e242fbda9d84867ab8bc955758eebce/licenses/ELASTIC-LICENSE.txt", "homepage_url":"https://github.com/elastic/elasticsearch/blob/0d8aa7527e242fbda9d84867ab8bc955758eebce/licenses/ELASTIC-LICENSE.txt",
"text_url": "https://github.com/elastic/elasticsearch/blob/0d8aa7527e242fbda9d84867ab8bc955758eebce/licenses/ELASTIC-LICENSE.txt", "text_url":"https://github.com/elastic/elasticsearch/blob/0d8aa7527e242fbda9d84867ab8bc955758eebce/licenses/ELASTIC-LICENSE.txt",
"reference_url": "https://enterprise.dejacode.com/urn/urn:dje:license:elastic-license-2018", "reference_url":"https://enterprise.dejacode.com/urn/urn:dje:license:elastic-license-2018",
"spdx_license_key": null, "spdx_license_key":null,
"spdx_url": "", "spdx_url":"",
"start_line": 9, "start_line":9,
"end_line": 10, "end_line":10,
"matched_rule": { "matched_rule":{
"identifier": "elastic_1.RULE", "identifier":"elastic_1.RULE",
"license_expression": "elastic-license-2018", "license_expression":"elastic-license-2018",
"licenses": [ "licenses":[
"elastic-license-2018" "elastic-license-2018"
], ],
"is_license_text": false, "is_license_text":false,
"is_license_notice": true, "is_license_notice":true,
"is_license_reference": false, "is_license_reference":false,
"is_license_tag": false, "is_license_tag":false,
"matcher": "3-seq", "matcher":"3-seq",
"rule_length": 18, "rule_length":18,
"matched_length": 13, "matched_length":13,
"match_coverage": 72.22, "match_coverage":72.22,
"rule_relevance": 100.0 "rule_relevance":100.0
} }
}, },
{ {
"key": "bsd-new", "key":"bsd-new",
"score": 100.0, "score":100.0,
"name": "BSD-3-Clause", "name":"BSD-3-Clause",
"short_name": "BSD-3-Clause", "short_name":"BSD-3-Clause",
"category": "Permissive", "category":"Permissive",
"is_exception": false, "is_exception":false,
"owner": "Regents of the University of California", "owner":"Regents of the University of California",
"homepage_url": "http://www.opensource.org/licenses/BSD-3-Clause", "homepage_url":"http://www.opensource.org/licenses/BSD-3-Clause",
"text_url": "http://www.opensource.org/licenses/BSD-3-Clause", "text_url":"http://www.opensource.org/licenses/BSD-3-Clause",
"reference_url": "https://enterprise.dejacode.com/urn/urn:dje:license:bsd-new", "reference_url":"https://enterprise.dejacode.com/urn/urn:dje:license:bsd-new",
"spdx_license_key": "BSD-3-Clause", "spdx_license_key":"BSD-3-Clause",
"spdx_url": "https://spdx.org/licenses/BSD-3-Clause", "spdx_url":"https://spdx.org/licenses/BSD-3-Clause",
"start_line": 11, "start_line":11,
"end_line": 11, "end_line":11,
"matched_rule": { "matched_rule":{
"identifier": "bsd-new_10.RULE", "identifier":"bsd-new_10.RULE",
"license_expression": "bsd-new", "license_expression":"bsd-new",
"licenses": [ "licenses":[
"bsd-new" "bsd-new"
], ],
"is_license_text": false, "is_license_text":false,
"is_license_notice": false, "is_license_notice":false,
"is_license_reference": true, "is_license_reference":true,
"is_license_tag": false, "is_license_tag":false,
"matcher": "2-aho", "matcher":"2-aho",
"rule_length": 3, "rule_length":3,
"matched_length": 3, "matched_length":3,
"match_coverage": 100.0, "match_coverage":100.0,
"rule_relevance": 100.0 "rule_relevance":100.0
} }
} }
], ],
"license_expressions": [ "license_expressions":[
"bsd-new", "bsd-new",
"bsd-new", "bsd-new",
"elastic-license-2018", "elastic-license-2018",
"bsd-new" "bsd-new"
], ],
"scan_errors": [] "scan_errors":[
}
] ]
}
]
} }