diff --git a/.github/workflows/ort.yml b/.github/workflows/ort.yml new file mode 100644 index 00000000..3c46c65e --- /dev/null +++ b/.github/workflows/ort.yml @@ -0,0 +1,40 @@ +name: ORT licensing + +on: + push: + branches: + - master + - '[0-9]+.[0-9]+.x' + tags: + - '**' + pull_request: + branches: + - master + - '[0-9]+.[0-9]+.x' + +jobs: + ort: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v1 + with: + java-version: '11.0.1' + + - name: Analyze licensing + id: ort-action + uses: edulix/ort-action@develop + with: + fail-on: hints + package-curations-dir: .ort-data/curations-dir/ + rules-file: .ort-data/rules.kts + license-classifications-file: .ort-data/license-classifications.yml + reporters: AdocTemplate,PdfTemplate,Excel,StaticHtml,WebApp + report-extra-args: > + --report-option + ADocTemplate=template.path=/project/.ort-data/disclosure_document.ftl + + - uses: actions/upload-artifact@v2 + with: + name: licenses + path: ${{ steps.ort-action.outputs.results-dir }} diff --git a/.ort-data/curations-dir/agora-gui-booth.yml b/.ort-data/curations-dir/agora-gui-booth.yml new file mode 100644 index 00000000..45f62ba7 --- /dev/null +++ b/.ort-data/curations-dir/agora-gui-booth.yml @@ -0,0 +1,7 @@ +- id: "Yarn::agora-gui-booth" + curations: + comment: "This package needs to be downloaded from git" + vcs: + type: "git" + url: "https://github.com/Bernardo-Castilho/dragdroptouch.git" + revision: "058f0eca96e57ad695f0d5dd2d7bd492ef1c4e47" diff --git a/.ort-data/curations-dir/bsd_license.yml b/.ort-data/curations-dir/bsd_license.yml new file mode 100644 index 00000000..88a11d4d --- /dev/null +++ b/.ort-data/curations-dir/bsd_license.yml @@ -0,0 +1,228 @@ +--- +- id: "PyPI::babel" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "PyPI::ipdb" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "PyPI::enum34" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "PyPI::flask" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "PyPI::flask-sqlalchemy" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "PyPI::itsdangerous" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "PyPI::jinja2" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "PyPI::prettytable" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "PyPI::werkzeug" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "PyPI::amqp" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "PyPI::anyjson" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "PyPI::backcall" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "PyPI::beaker" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "PyPI::billiard" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "PyPI::celery" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "PyPI::click" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "PyPI::click-didyoumean" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "PyPI::click-plugins" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "PyPI::cryptography" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "PyPI::decorator" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "PyPI::django" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "PyPI::django-celery-results" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "PyPI::django-nose" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "PyPI::idna" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "PyPI::ipython" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "PyPI::ipython-genutils" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "PyPI::kombu" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "PyPI::markupsafe" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "PyPI::nodeenv" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "PyPI::prompt-toolkit" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "PyPI::pycparser" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "PyPI::pygments" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "PyPI::python-dateutil" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "PyPI::reportlab" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "PyPI::sqlparse" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "PyPI::traitlets" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "PyPI::vine" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + +- id: "Maven:org.webbitserver:webbit" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" diff --git a/.ort-data/curations-dir/distlib.yml b/.ort-data/curations-dir/distlib.yml new file mode 100644 index 00000000..cb17c1e5 --- /dev/null +++ b/.ort-data/curations-dir/distlib.yml @@ -0,0 +1,6 @@ +- id: "PyPI::distlib" + curations: + comment: "Invalid license with a space." + declared_license_mapping: + "BSD License": "BSD-3-Clause" + "Python license": "PSF-2.0" \ No newline at end of file diff --git a/.ort-data/curations-dir/drangandroptouch.yml b/.ort-data/curations-dir/drangandroptouch.yml new file mode 100644 index 00000000..5d663799 --- /dev/null +++ b/.ort-data/curations-dir/drangandroptouch.yml @@ -0,0 +1,7 @@ +- id: "dragandroptouch" + curations: + comment: "This package needs to be downloaded from git" + vcs: + type: "git" + url: "https://github.com/Bernardo-Castilho/dragdroptouch.git" + revision: "058f0eca96e57ad695f0d5dd2d7bd492ef1c4e47" diff --git a/.ort-data/curations-dir/fractionjs.yml b/.ort-data/curations-dir/fractionjs.yml new file mode 100644 index 00000000..a319b118 --- /dev/null +++ b/.ort-data/curations-dir/fractionjs.yml @@ -0,0 +1,4 @@ +- id: "NPM::fraction.js" + curations: + comment: "The package is detected as GPL because it's double licensed with GPL and MIT, so we use the MIT" + concluded_license: "MIT" diff --git a/.ort-data/curations-dir/java.yml b/.ort-data/curations-dir/java.yml new file mode 100644 index 00000000..ceb2cfdc --- /dev/null +++ b/.ort-data/curations-dir/java.yml @@ -0,0 +1,17 @@ +- id: "Maven:javax.cache:cache-api" + curations: + comment: "Incorrectly matched license, see https://search.maven.org/artifact/javax.cache/cache-api" + declared_license_mapping: + "JSR-000107 JCACHE 2.9 Public Review - Updated Specification\n License": "Apache-2.0" + +- id: "Maven:org.json:json" + curations: + comment: "It's basically MIT with a do not do evil clause." + declared_license_mapping: + "provided without support or warranty": "MIT" + +- id: "Maven:com.h2database:h2" + curations: + comment: "H2 is dual licensed and available under the MPL 2.0 (Mozilla Public License Version 2.0) or under the EPL 1.0 (Eclipse Public License). http://h2database.com/html/license.html" + declared_license_mapping: + "The H2 License, Version 1.0": "EPL-1.0" \ No newline at end of file diff --git a/.ort-data/curations-dir/jszip.yml b/.ort-data/curations-dir/jszip.yml new file mode 100644 index 00000000..a2245f9a --- /dev/null +++ b/.ort-data/curations-dir/jszip.yml @@ -0,0 +1,4 @@ +- id: "NPM::jszip" + curations: + comment: "The package is detected as GPL-3.0-only because it's double licensed with GPL-3.0-only and MIT, so we use the MIT" + concluded_license: "MIT" diff --git a/.ort-data/curations-dir/psycopg2-binary.yml b/.ort-data/curations-dir/psycopg2-binary.yml new file mode 100644 index 00000000..ce43049a --- /dev/null +++ b/.ort-data/curations-dir/psycopg2-binary.yml @@ -0,0 +1,5 @@ +- id: "PyPI::psycopg2-binary" + curations: + comment: "Incorrectly matched license." + declared_license_mapping: + "LGPL with exceptions": "LGPL-2.0-only" \ No newline at end of file diff --git a/.ort-data/curations-dir/pycryptodomex.yml b/.ort-data/curations-dir/pycryptodomex.yml new file mode 100644 index 00000000..50a59896 --- /dev/null +++ b/.ort-data/curations-dir/pycryptodomex.yml @@ -0,0 +1,6 @@ +- id: "PyPI::pycryptodomex" + curations: + comment: "Incorrectly matched license." + declared_license_mapping: + "BSD, Public Domain": "BSD-3-Clause" + "BSD License": "BSD-3-Clause" \ No newline at end of file diff --git a/.ort-data/curations-dir/reportlab.yml b/.ort-data/curations-dir/reportlab.yml new file mode 100644 index 00000000..8c1bb786 --- /dev/null +++ b/.ort-data/curations-dir/reportlab.yml @@ -0,0 +1,6 @@ +- id: "PyPI::reportlab" + curations: + comment: "Incorrectly matched license." + declared_license_mapping: + "BSD license (see license.txt for details), Copyright (c) 2000-2018, ReportLab Inc.": "BSD-3-Clause" + "BSD license (see license.txt for details), Copyright (c) 2000-2015, ReportLab Inc.": "BSD-3-Clause" diff --git a/.ort-data/curations-dir/rng-js.yml b/.ort-data/curations-dir/rng-js.yml new file mode 100644 index 00000000..e4fddac7 --- /dev/null +++ b/.ort-data/curations-dir/rng-js.yml @@ -0,0 +1,5 @@ +- id: "NPM::rng-js" + curations: + comment: "Declared license is misspelled with a 'c' - UK vs. US English." + declared_license_mapping: + Unlicence: "Unlicense" \ No newline at end of file diff --git a/.ort-data/disclosure_document.ftl b/.ort-data/disclosure_document.ftl new file mode 100644 index 00000000..b46310a9 --- /dev/null +++ b/.ort-data/disclosure_document.ftl @@ -0,0 +1,302 @@ +[#-- +Copyright (C) 2020 HERE Europe B.V. +Copyright (C) 2020-2021 Bosch.IO GmbH +Copyright (C) 2021 Agora Voting SL + +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. + +SPDX-License-Identifier: Apache-2.0 +License-Filename: LICENSE +--] + +[#-- +The AsciiDoc file generated by this template consists of the following sections: + +* The licenses and associated copyrights for all projects merged into a single list. +* The archived license files, licenses and associated copyrights for dependencies listed by package. +* An Appendix of license texts of all above licenses + +Excluded projects and packages are ignored. +--] + +[#assign ModelExtensions = statics['org.ossreviewtoolkit.model.utils.ExtensionsKt']] + +[#-- Add the licenses of the projects. --] +:title-page: +:sectnums: +:toc: preamble + +[#assign errorTitle = "DISCLAIMER! THERE ARE UNRESOLVED ISSUES OR UNRESOLVED RULE VIOLATIONS. + THIS DOCUMENT SHOULD NOT BE DISTRIBUTED UNTIL THESE PROBLEMS ARE RESOLVED."?replace("\n", " ")] + +[#-- +The alert role needs to be defined in the pdf-theme file, where the color can be customized. +If not present, the text is displayed normally. +--] += [#if helper.hasUnresolvedIssues() || helper.hasUnresolvedRuleViolations()][.alert]#${errorTitle}#[#else] Disclosure Document[/#if] + +:author-name: OSS Review Toolkit +[#assign now = .now] +:revdate: ${now?date?iso_local} +:revnumber: 1.0.0 + + +[#if projects?has_content] +[#--Merge the licenses and copyrights of all projects into a single list. The default LicenseView.ALL is used because--] +[#--projects cannot have a concluded license (compare with the handling of packages below). --] + +== Projects Licenses + +[#list projects as project] + +=== ${project.id.name} + +[#assign mergedLicenses = helper.mergeLicenses([project])] + + +[#list mergedLicenses as resolvedLicense] + +* License: <<${resolvedLicense.license}, ${resolvedLicense.license}>> + +[#assign copyrights = resolvedLicense.getCopyrights(true)] +[#list copyrights as copyright] +** +${copyright}+ +[#else] +** No copyright found. +[/#list] + +[/#list] +[/#list] +[/#if] +<<< + +[#-- List all rule violations and their status --] +== Rule Violation Summary + +[#assign +ruleViolationErrors = tabularScanRecord + .ruleViolations + ?filter( it -> !it.isResolved() && it.violation.severity.name() == "ERROR" ) + ?size +] + +[#assign +ruleViolationWarns = tabularScanRecord + .ruleViolations + ?filter( it -> !it.isResolved() && it.violation.severity.name() == "WARNING" ) + ?size +] + +[#assign +ruleViolationHint = tabularScanRecord + .ruleViolations + ?filter( it -> !it.isResolved() && it.violation.severity.name() == "HINT" ) + ?size +] +${ruleViolationErrors} errors, ${ruleViolationWarns} warnings, ${ruleViolationHint} hints to resolve + +[#if tabularScanRecord.ruleViolations?size == 0] +No rule violations found. +[#else] + +[#list tabularScanRecord.ruleViolations as ruleViolation] + +|==== +| **Rule:** | ${ruleViolation.violation.rule} +| **Severity:** | [#if ruleViolation.isResolved()]**Resolved**[#else]**${ruleViolation.violation.severity.name()}**[/#if] +| **Package:** | ${ruleViolation.violation.pkg.toCoordinates()} +| **License:** | [#if ruleViolation.violation.license?has_content]${ruleViolation.violation.licenseSource}: ${ruleViolation.violation.license}[#else]-[/#if] +| **Message:** | ${ruleViolation.violation.message} +[#if ruleViolation.isResolved()] +| **Resolution:** | ${ruleViolation.resolutionDescription} +[#else] +| **How to fix:** | ${ruleViolation.violation.howToFix} +[/#if] +|==== +[/#list] + +[/#if] + +[#-- List all issues and their status --] +[#if tabularScanRecord.issueSummary.rows?size > 0] +== Issue Summary + +[#assign +issueErrors = tabularScanRecord + .issueSummary + .errorCount +] + +[#assign +issueWarns = tabularScanRecord + .issueSummary + .warningCount +] + +[#assign +issueHint = tabularScanRecord + .issueSummary + .hintCount +] +${issueErrors} errors, ${issueWarns} warnings, ${issueHint} hints to resolve + +[/#if] + +[#-- Add the licenses of all dependencies. --] +== Dependencies + +[#if packages?has_content] +This software depends on external packages and source code. +The applicable license information is listed below: +[/#if] + +[#list packages as package] +[#if !package.excluded] + +**Dependency: ${package.id.name}** + +[#if package.description?has_content] +Description: ${package.description} +[/#if] + +Package URL: _${ModelExtensions.toPurl(package.id)}_ + +[#-- List the content of archived license files and associated copyrights. --] +[#list package.licenseFiles.files as licenseFile] + +License File: <<${ModelExtensions.toPurl(package.id)} ${licenseFile.path}, ${licenseFile.path}>> + +[#assign copyrights = licenseFile.getCopyrights()] +[#list copyrights as copyright] +** +${copyright}+ +[#else] +** No copyright found. +[/#list] + +[/#list] +[#-- +Filter the licenses of the package using LicenseView.CONCLUDED_OR_DECLARED_AND_DETECTED. This is the default view which +ignores declared and detected licenses if a license conclusion for the package was made. If copyrights were detected +for a concluded license those statements are kept. +--] +[#assign +resolvedLicenses = + LicenseView.CONCLUDED_OR_DECLARED_AND_DETECTED + .filter( + package.licensesNotInLicenseFiles( + LicenseView.CONCLUDED_OR_DECLARED_AND_DETECTED + .filter(package.license, package.licenseChoices).licenses + ) + ) +] +[#if resolvedLicenses?has_content] + +The following licenses and copyrights were found in the source code of this package: +[/#if] + +[#list resolvedLicenses as resolvedLicense] + +[#-- In case of a NOASSERTION license, there is no license text; so do not add a link. --] +[#if helper.isLicensePresent(resolvedLicense)] +* License: <<${resolvedLicense.license}, ${resolvedLicense.license}>> +[#else] +* License: ${resolvedLicense.license} +[/#if] + +[#assign copyrights = resolvedLicense.getCopyrights(true)] +[#list copyrights as copyright] +** +${copyright}+ +[#else] +** No copyright found. +[/#list] + +[/#list] +[/#if] +[/#list] +<<< + +[#assign +packagesWithLicenseFiles = + packages?filter( + it -> !it.excluded && it.licenseFiles.files?size > 0 + ) +] +[#if packagesWithLicenseFiles?has_content] + +== License Files for Packages + +[#list packagesWithLicenseFiles as package] +[#if !package.excluded] + +*Dependency* + +Package URL: _${ModelExtensions.toPurl(package.id)}_ + +[#list package.licenseFiles.files as licenseFile] +=== ${ModelExtensions.toPurl(package.id)} ${licenseFile.path} + +++++ +[#assign copyrights = licenseFile.getCopyrights()] +[#if copyrights?has_content] +[#list copyrights as copyright] +${copyright} +[#else] +No copyright +[/#list] +[/#if] + +${licenseFile.readFile()} +++++ +<<< +[#else] +No license file +[/#list] +[/#if] +[#else] +No package +[/#list] + +[/#if] + + +[#-- +Append the text of all licenses that have been listed in the above lists for licenses and coppyrights +--] +[appendix] +== License Texts + +[#assign mergedLicenses = helper.mergeLicenses(projects + packages, LicenseView.CONCLUDED_OR_DECLARED_AND_DETECTED, true)] +[#list mergedLicenses as resolvedLicense] +=== ${resolvedLicense.license} + +++++ +[#assign licenseText = licenseTextProvider.getLicenseText(resolvedLicense.license.simpleLicense())!""] +[#if licenseText?has_content] + +[#assign copyrights = resolvedLicense.getCopyrights(true)] +[#list copyrights as copyright] +${copyright} +[/#list] + +${licenseText} + +[#assign exceptionText = licenseTextProvider.getLicenseText(resolvedLicense.license.exception()!"")!""] +[#if exceptionText?has_content] + +${exceptionText} + +[/#if] +[/#if] +++++ +<<< +[/#list] \ No newline at end of file diff --git a/.ort-data/license-classifications.yml b/.ort-data/license-classifications.yml new file mode 100644 index 00000000..e93c47c4 --- /dev/null +++ b/.ort-data/license-classifications.yml @@ -0,0 +1,376 @@ +--- +# Example license-classifications.yml based on categorization from +# https://github.com/nexB/scancode-toolkit/commit/ed644e4 +# +# To demonstrate how one can insert a custom written offer +# include-source-code-offer-in-notice-file has been set to +# true for all licenses of the GPL family. +categories: +- name: "copyleft" +- name: "strong-copyleft" +- name: "copyleft-limited" +- name: "permissive" + description: "Licenses with permissive obligations." +- name: "public-domain" +- name: "include-in-notice-file" + description: >- + This category is checked by templates used by the ORT report generator. The licenses associated with this + category are included into NOTICE files. +- name: "include-source-code-offer-in-notice-file" + description: >- + A marker category that indicates that the licenses assigned to it require that the source code of the packages + needs to be provided. + +categorizations: +- id: "AFL-2.1" + categories: + - "permissive" + - "include-in-notice-file" +- id: "0BSD" + categories: + - "permissive" + - "include-in-notice-file" +- id: "ISC" + categories: + - "permissive" + - "include-in-notice-file" +- id: "zlib-acknowledgement" + categories: + - "permissive" + - "include-in-notice-file" +- id: "AGPL-1.0" + categories: + - "copyleft" + - "include-in-notice-file" + - "include-source-code-offer-in-notice-file" +- id: "AGPL-1.0-only" + categories: + - "copyleft" + - "include-in-notice-file" + - "include-source-code-offer-in-notice-file" +- id: "AGPL-1.0-or-later" + categories: + - "copyleft" + - "include-in-notice-file" + - "include-source-code-offer-in-notice-file" +- id: "AGPL-3.0" + categories: + - "copyleft" + - "include-in-notice-file" + - "include-source-code-offer-in-notice-file" +- id: "AGPL-3.0-only" + categories: + - "copyleft" + - "include-in-notice-file" + - "include-source-code-offer-in-notice-file" +- id: "AGPL-3.0-or-later" + categories: + - "copyleft" + - "include-in-notice-file" + - "include-source-code-offer-in-notice-file" +- id: "Apache-2.0" + categories: + - "permissive" + - "include-in-notice-file" +- id: "Artistic-1.0" + categories: + - "copyleft-limited" + - "include-in-notice-file" +- id: "Artistic-2.0" + categories: + - "copyleft-limited" + - "include-in-notice-file" +- id: "BSD-1-Clause" + categories: + - "permissive" + - "include-in-notice-file" +- id: "BSD-2-Clause" + categories: + - "permissive" + - "include-in-notice-file" +- id: "BSD-2-Clause-FreeBSD" + categories: + - "permissive" + - "include-in-notice-file" +- id: "BSD-2-Clause-NetBSD" + categories: + - "permissive" + - "include-in-notice-file" +- id: "BSD-3-Clause" + categories: + - "permissive" + - "include-in-notice-file" +- id: "BSD-4-Clause" + categories: + - "permissive" + - "include-in-notice-file" +- id: "BSD-4-Clause-UC" + categories: + - "permissive" + - "include-in-notice-file" +- id: "CC-BY-1.0" + categories: + - "permissive" + - "include-in-notice-file" +- id: "CC-BY-2.0" + categories: + - "permissive" + - "include-in-notice-file" +- id: "CC-BY-2.5" + categories: + - "permissive" + - "include-in-notice-file" +- id: "CC-BY-3.0" + categories: + - "permissive" + - "include-in-notice-file" +- id: "CC-BY-4.0" + categories: + - "permissive" + - "include-in-notice-file" +- id: "CC0-1.0" + categories: + - "public-domain" + - "include-in-notice-file" +- id: "CDDL-1.0" + categories: + - "copyleft-limited" + - "include-in-notice-file" +- id: "CDDL-1.1" + categories: + - "copyleft-limited" + - "include-in-notice-file" +- id: "CPL-1.0" + categories: + - "copyleft-limited" + - "include-in-notice-file" +- id: "EPL-1.0" + categories: + - "copyleft-limited" + - "include-in-notice-file" +- id: "EPL-2.0" + categories: + - "copyleft-limited" + - "include-in-notice-file" +- id: "EUPL-1.1" + categories: + - "copyleft-limited" + - "include-in-notice-file" +- id: "EUPL-1.2" + categories: + - "copyleft-limited" + - "include-in-notice-file" +- id: "GPL-1.0+" + categories: + - "copyleft" + - "include-in-notice-file" + - "include-source-code-offer-in-notice-file" +- id: "GPL-1.0-only" + categories: + - "copyleft" + - "include-in-notice-file" + - "include-source-code-offer-in-notice-file" +- id: "GPL-1.0-or-later" + categories: + - "copyleft" + - "include-in-notice-file" + - "include-source-code-offer-in-notice-file" +- id: "GPL-2.0" + categories: + - "copyleft" + - "include-in-notice-file" + - "include-source-code-offer-in-notice-file" +- id: "GPL-2.0+" + categories: + - "copyleft" + - "include-in-notice-file" + - "include-source-code-offer-in-notice-file" +- id: "GPL-2.0-only" + categories: + - "copyleft" + - "include-in-notice-file" + - "include-source-code-offer-in-notice-file" +- id: "GPL-2.0-only WITH Classpath-exception-2.0" + categories: + - "copyleft-limited" + - "include-in-notice-file" + - "include-source-code-offer-in-notice-file" +- id: "GPL-2.0-only WITH Font-exception-2.0" + categories: + - "copyleft-limited" + - "include-in-notice-file" + - "include-source-code-offer-in-notice-file" +- id: "GPL-2.0-or-later" + categories: + - "copyleft" + - "include-in-notice-file" + - "include-source-code-offer-in-notice-file" +- id: "GPL-3.0" + categories: + - "copyleft" + - "include-in-notice-file" + - "include-source-code-offer-in-notice-file" +- id: "GPL-3.0+" + categories: + - "copyleft" + - "include-in-notice-file" + - "include-source-code-offer-in-notice-file" +- id: "GPL-3.0-only" + categories: + - "copyleft" + - "include-in-notice-file" + - "include-source-code-offer-in-notice-file" +- id: "GPL-3.0-or-later" + categories: + - "copyleft" + - "include-in-notice-file" + - "include-source-code-offer-in-notice-file" +- id: "JSON" + categories: + - "permissive" + - "include-in-notice-file" +- id: "LGPL-2.0-only" + categories: + - "copyleft-limited" + - "include-in-notice-file" +- id: "LGPL-2.0-or-later" + categories: + - "copyleft-limited" + - "include-in-notice-file" + - "include-source-code-offer-in-notice-file" +- id: "LGPL-2.1-only" + categories: + - "copyleft-limited" + - "include-in-notice-file" + - "include-source-code-offer-in-notice-file" +- id: "LGPL-2.1-or-later" + categories: + - "copyleft-limited" + - "include-in-notice-file" + - "include-source-code-offer-in-notice-file" +- id: "LGPL-3.0-only" + categories: + - "copyleft-limited" + - "include-in-notice-file" + - "include-source-code-offer-in-notice-file" +- id: "LGPL-3.0-or-later" + categories: + - "copyleft-limited" + - "include-in-notice-file" + - "include-source-code-offer-in-notice-file" +- id: "Libpng" + categories: + - "permissive" + - "include-in-notice-file" +- id: "MIT" + categories: + - "permissive" + - "include-in-notice-file" +- id: "MIT-0" + categories: + - "permissive" + - "include-in-notice-file" +- id: "MIT-feh" + categories: + - "permissive" + - "include-in-notice-file" +- id: "MPL-1.0" + categories: + - "copyleft-limited" + - "include-in-notice-file" +- id: "MPL-1.1" + categories: + - "copyleft-limited" + - "include-in-notice-file" +- id: "MPL-2.0" + categories: + - "copyleft-limited" + - "include-in-notice-file" +- id: "MS-PL" + categories: + - "permissive" + - "include-in-notice-file" +- id: "MS-RL" + categories: + - "copyleft-limited" + - "include-in-notice-file" +- id: "ODbL-1.0" + categories: + - "copyleft" + - "include-in-notice-file" +- id: "OFL-1.0" + categories: + - "permissive" + - "include-in-notice-file" +- id: "OFL-1.1" + categories: + - "permissive" + - "include-in-notice-file" +- id: "OpenSSL" + categories: + - "permissive" + - "include-in-notice-file" +- id: "PSF" + categories: + - "strong-copyleft" + - "include-in-notice-file" +- id: "HPND" + categories: + - "permissive" + - "include-in-notice-file" +- id: "PSF-2.0" + categories: + - "permissive" + - "include-in-notice-file" +- id: "Python-2.0" + categories: + - "permissive" + - "include-in-notice-file" +- id: "Ruby" + categories: + - "copyleft-limited" + - "include-in-notice-file" +- id: "SAX-PD" + categories: + - "public-domain" + - "include-in-notice-file" +- id: "LicenseRef-scancode-public-domain-disclaimer" + categories: + - "public-domain" + - "include-in-notice-file" +- id: "Unlicense" + categories: + - "public-domain" + - "include-in-notice-file" +- id: "ZPL-2.1" + categories: + - "permissive" + - "include-in-notice-file" +- id: "W3C" + categories: + - "permissive" + - "include-in-notice-file" +- id: "WTFPL" + categories: + - "permissive" + - "include-in-notice-file" +- id: "X11" + categories: + - "permissive" + - "include-in-notice-file" +- id: "Zlib" + categories: + - "permissive" + - "include-in-notice-file" +- id: "bzip2-1.0.5" + categories: + - "permissive" + - "include-in-notice-file" +- id: "bzip2-1.0.6" + categories: + - "permissive" + - "include-in-notice-file" +- id: "curl" + categories: + - "permissive" + - "include-in-notice-file" diff --git a/.ort-data/rules.kts b/.ort-data/rules.kts new file mode 100644 index 00000000..4128fa1c --- /dev/null +++ b/.ort-data/rules.kts @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2019 HERE Europe B.V. + * + * 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 + * + * https://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. + * + * SPDX-License-Identifier: Apache-2.0 + * License-Filename: LICENSE + */ + +/******************************************************* + * Example OSS Review Toolkit (ORT) rules.kts file * + * * + * Note this file only contains example how to write * + * rules. It's recommended you consult your own legal * + * when writing your own rules. * + *******************************************************/ + +/** + * Import the license classifications from license-classifications.yml. + */ + +val permissiveLicenses = licenseClassifications.licensesByCategory["permissive"].orEmpty() + +val copyleftLicenses = licenseClassifications.licensesByCategory["copyleft"].orEmpty() + +val copyleftLimitedLicenses = licenseClassifications.licensesByCategory["copyleft-limited"].orEmpty() + +val publicDomainLicenses = licenseClassifications.licensesByCategory["public-domain"].orEmpty() + +// The complete set of licenses covered by policy rules. +val handledLicenses = listOf( + permissiveLicenses, + publicDomainLicenses, + copyleftLicenses, + copyleftLimitedLicenses +).flatten().let { + it.getDuplicates().let { duplicates -> + require(duplicates.isEmpty()) { + "The classifications for the following licenses overlap: $duplicates" + } + } + + it.toSet() +} + +/** + * Function to return Markdown-formatted text to aid users with resolving violations. + */ + +fun PackageRule.howToFixDefault() = """ + A text written in MarkDown to help users resolve policy violations + which may link to additional resources. + """.trimIndent() + +/** + * Set of matchers to help keep policy rules easy to understand + */ + +fun PackageRule.LicenseRule.isHandled() = + object : RuleMatcher { + override val description = "isHandled($license)" + + override fun matches() = + license in handledLicenses + && !(license.toString().contains("-exception") + && !license.toString().contains(" WITH ")) + } + +fun PackageRule.LicenseRule.isCopyleft() = + object : RuleMatcher { + override val description = "isCopyleft($license)" + + override fun matches() = license in copyleftLicenses + } + +fun PackageRule.LicenseRule.isCopyleftLimited() = + object : RuleMatcher { + override val description = "isCopyleftLimited($license)" + + override fun matches() = license in copyleftLimitedLicenses + } + +/** + * Example policy rules + */ + +// Define the set of policy rules. +val ruleSet = ruleSet(ortResult, licenseInfoResolver) { + // Define a rule that is executed for each package. + packageRule("UNHANDLED_LICENSE") { + // Do not trigger this rule on packages that have been excluded in the .ort.yml. + require { + -isExcluded() + } + + // Define a rule that is executed for each license of the package. + licenseRule("UNHANDLED_LICENSE", LicenseView.CONCLUDED_OR_DECLARED_AND_DETECTED) { + require { + -isExcluded() + -isHandled() + } + + // Throw an error message including guidance how to fix the issue. + error( + "The license $license is currently not covered by policy rules. " + + "The license was ${licenseSource.name.lowercase()} in package " + + "${pkg.id.toCoordinates()}", + howToFixDefault() + ) + } + } + + packageRule("UNMAPPED_DECLARED_LICENSE") { + require { + -isExcluded() + } + + resolvedLicenseInfo.licenseInfo.declaredLicenseInfo.processed.unmapped.forEach { unmappedLicense -> + warning( + "The declared license '$unmappedLicense' could not be mapped to a valid license or parsed as an SPDX " + + "expression. The license was found in package ${pkg.id.toCoordinates()}.", + howToFixDefault() + ) + } + } + + packageRule("COPYLEFT_IN_SOURCE") { + require { + -isExcluded() + } + + licenseRule("COPYLEFT_IN_SOURCE", LicenseView.CONCLUDED_OR_DECLARED_AND_DETECTED) { + require { + -isExcluded() + +isCopyleft() + } + + val message = if (licenseSource == LicenseSource.DETECTED) { + "The ScanCode copyleft categorized license $license was ${licenseSource.name.lowercase()} " + + "in package ${pkg.id.toCoordinates()}." + } else { + "The package ${pkg.id.toCoordinates()} has the ${licenseSource.name.lowercase()} ScanCode copyleft " + + "catalogized license $license." + } + + error(message, howToFixDefault()) + } + + licenseRule("COPYLEFT_LIMITED_IN_SOURCE", LicenseView.CONCLUDED_OR_DECLARED_OR_DETECTED) { + require { + -isExcluded() + +isCopyleftLimited() + } + + val message = if (licenseSource == LicenseSource.DETECTED) { + if (pkg.id.type == "Unmanaged") { + "The ScanCode copyleft-limited categorized license $license was ${licenseSource.name.lowercase()} " + + "in package ${pkg.id.toCoordinates()}." + } else { + "The ScanCode copyleft-limited categorized license $license was ${licenseSource.name.lowercase()} " + + "in package ${pkg.id.toCoordinates()}." + } + } else { + "The package ${pkg.id.toCoordinates()} has the ${licenseSource.name.lowercase()} ScanCode " + + "copyleft-limited categorized license $license." + } + + error(message, howToFixDefault()) + } + } + + packageRule("VULNERABILITY_IN_PACKAGE") { + require { + -isExcluded() + +hasVulnerability() + } + + issue( + Severity.WARNING, + "The package ${pkg.id.toCoordinates()} has a vulnerability", + howToFixDefault() + ) + } + + packageRule("HIGH_SEVERITY_VULNERABILITY_IN_PACKAGE") { + val maxAcceptedSeverity = "5.0" + val scoringSystem = "CVSS2" + + require { + -isExcluded() + +hasVulnerability(maxAcceptedSeverity, scoringSystem) { value, threshold -> + value.toFloat().compareTo(threshold.toFloat()) + } + } + + issue( + Severity.ERROR, + "The package ${pkg.id.toCoordinates()} has a vulnerability with $scoringSystem severity > " + + "$maxAcceptedSeverity", + howToFixDefault() + ) + } + + // Define a rule that is executed for each dependency of a project. + dependencyRule("COPYLEFT_IN_DEPENDENCY") { + licenseRule("COPYLEFT_IN_DEPENDENCY", LicenseView.CONCLUDED_OR_DECLARED_OR_DETECTED) { + require { + +isCopyleft() + } + + issue( + Severity.ERROR, + "The project ${project.id.toCoordinates()} has a dependency licensed under the ScanCode " + + "copyleft categorized license $license.", + howToFixDefault() + ) + } + } + + dependencyRule("COPYLEFT_LIMITED_STATIC_LINK_IN_DIRECT_DEPENDENCY") { + require { + +isAtTreeLevel(0) + +isStaticallyLinked() + } + + licenseRule("LINKED_WEAK_COPYLEFT", LicenseView.CONCLUDED_OR_DECLARED_OR_DETECTED) { + require { + +isCopyleftLimited() + } + + // Use issue() instead of error() if you want to set the severity. + issue( + Severity.WARNING, + "The project ${project.id.toCoordinates()} has a statically linked direct dependency licensed " + + "under the ScanCode copyleft-left categorized license $license.", + howToFixDefault() + ) + } + } +} + +// Populate the list of policy rule violations to return. +ruleViolations += ruleSet.violations