From b5eb54d5c1aeae79c8b07a516bdf3e380ad0bba7 Mon Sep 17 00:00:00 2001 From: Jordan Date: Mon, 18 Nov 2024 01:15:11 +0000 Subject: [PATCH] Updating presubmit to check license is a valid spdx identifier. Further details are available in https://docs.google.com/document/d/1x4GLly7KJ2xmlJRvsswJlmVSLLjBjk5NOxWZ-Dryg_A Bug: 358504615 Change-Id: I76997454140ee63aea6b6f492669800efce271be Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/6021876 Reviewed-by: Joey Scarr Commit-Queue: Jordan Brown Reviewed-by: Andrew Grieve Reviewed-by: Rick Byers Reviewed-by: Rachael Newitt --- metadata/LICENSE_OWNERS | 7 ++++ metadata/OWNERS | 11 +++--- metadata/SECURITY_TEAM_OWNERS | 11 ++++++ metadata/fields/custom/license.py | 31 +-------------- metadata/fields/custom/license_allowlist.py | 38 +++++++++++++++++++ .../data/README.chromium.test.multi-invalid | 2 +- .../data/README.chromium.test.multi-valid | 6 +-- metadata/tests/dependency_metadata_test.py | 30 +++++++-------- metadata/tests/fields_test.py | 13 +++---- metadata/tests/parse_test.py | 2 +- 10 files changed, 89 insertions(+), 62 deletions(-) create mode 100644 metadata/LICENSE_OWNERS create mode 100644 metadata/SECURITY_TEAM_OWNERS create mode 100644 metadata/fields/custom/license_allowlist.py diff --git a/metadata/LICENSE_OWNERS b/metadata/LICENSE_OWNERS new file mode 100644 index 000000000..17dbeeab9 --- /dev/null +++ b/metadata/LICENSE_OWNERS @@ -0,0 +1,7 @@ +# ATLs are responsible for approving new licenses. +# TODO(b/379562012) Replace with file:/ATL_OWNERS. +rbyers@chromium.org +thakis@chromium.org + +# TODO(b/379223095) Remove security team once transition to spdx allow list is complete. +file:SECURITY_TEAM_OWNERS \ No newline at end of file diff --git a/metadata/OWNERS b/metadata/OWNERS index 6ef81e888..e33a7b8ab 100644 --- a/metadata/OWNERS +++ b/metadata/OWNERS @@ -1,6 +1,5 @@ -# Software Supply Chain Integrity/SBOM -aredulla@google.com -dlf@google.com -jsca@google.com -renewitt@google.com -sumakasa@google.com +# Software Supply Chain Integrity/SBOM. + +file:SECURITY_TEAM_OWNERS + +per-file fields/custom/license_allowlist.py=file:LICENSE_OWNERS diff --git a/metadata/SECURITY_TEAM_OWNERS b/metadata/SECURITY_TEAM_OWNERS new file mode 100644 index 000000000..573951457 --- /dev/null +++ b/metadata/SECURITY_TEAM_OWNERS @@ -0,0 +1,11 @@ +# Chops security team. + +aredulla@google.com +ayatane@chromium.org +dlf@google.com +heidichan@google.com +jsca@google.com +mitchella@google.com +qjw@chromium.org +renewitt@google.com +rop@google.com diff --git a/metadata/fields/custom/license.py b/metadata/fields/custom/license.py index 507f60fe8..cb58f0c50 100644 --- a/metadata/fields/custom/license.py +++ b/metadata/fields/custom/license.py @@ -18,34 +18,7 @@ sys.path.insert(0, _ROOT_DIR) import metadata.fields.field_types as field_types import metadata.fields.util as util import metadata.validation_result as vr - -# Copied from ANDROID_ALLOWED_LICENSES in -# https://chromium.googlesource.com/chromium/src/+/refs/heads/main/third_party/PRESUBMIT.py -_ANDROID_ALLOWED_LICENSES = [ - "A(pple )?PSL 2(\.0)?", - "Android Software Development Kit License", - "Apache( License)?,?( Version)? 2(\.0)?", - "(New )?([23]-Clause )?BSD( [23]-Clause)?( with advertising clause)?", - "GNU Lesser Public License", - "L?GPL ?v?2(\.[01])?( or later)?( with the classpath exception)?", - "(The )?MIT(/X11)?(-like)?( License)?", - "MPL 1\.1 ?/ ?GPL 2(\.0)? ?/ ?LGPL 2\.1", - "MPL 2(\.0)?", - "Microsoft Limited Public License", - "Microsoft Permissive License", - "Public Domain", - "Python", - "SIL Open Font License, Version 1.1", - "SGI Free Software License B", - "Unicode, Inc. License", - "University of Illinois\/NCSA Open Source", - "X11", - "Zlib", -] -_PATTERN_LICENSE_ALLOWED = re.compile( - "^({})$".format("|".join(_ANDROID_ALLOWED_LICENSES)), - re.IGNORECASE, -) +from metadata.fields.custom.license_allowlist import ALLOWED_SPDX_LICENSES _PATTERN_VERBOSE_DELIMITER = re.compile(r" and | or | / ") @@ -97,7 +70,7 @@ def is_license_allowlisted(value: str) -> bool: """Returns whether the value is in the allowlist for license types. """ - return util.matches(_PATTERN_LICENSE_ALLOWED, value) + return value in ALLOWED_SPDX_LICENSES class LicenseField(field_types.SingleLineTextField): diff --git a/metadata/fields/custom/license_allowlist.py b/metadata/fields/custom/license_allowlist.py new file mode 100644 index 000000000..82f12af54 --- /dev/null +++ b/metadata/fields/custom/license_allowlist.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +# Copyright 2024 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# These licenses are used to verify that code imported to Android complies with +# their licensing requirements. Do not add entries to this list without approval. +# Any licenses added should be a valid SPDX Identifier. For the full list of +# identifiers; see https://spdx.org/licenses/ +ALLOWED_SPDX_LICENSES = frozenset([ + "APSL-2.0", + "Apache-2.0", + "BSD-2-Clause", + "BSD-2-Clause-FreeBSD", + "BSD-3-Clause", + "BSD-4-Clause", + "BSD-4-Clause-UC", + "BSD-Source-Code", + "GPL-2.0-with-classpath-exception", + "MIT", + "MIT-0", + "MIT-Modern-Variant", + "MPL-1.1", + "MPL-2.0", + "NCSA", + "OFL-1.1", + "SGI-B-2.0", + "Unicode-3.0", + "Unicode-DFS-2015", + "Unicode-DFS-2016", + "X11", + "Zlib", + # Public Domain variants. + "ISC", + "ICU", + "SunPro", + "BSL-1.0", +]) diff --git a/metadata/tests/data/README.chromium.test.multi-invalid b/metadata/tests/data/README.chromium.test.multi-invalid index 5264e3119..5983054f8 100644 --- a/metadata/tests/data/README.chromium.test.multi-invalid +++ b/metadata/tests/data/README.chromium.test.multi-invalid @@ -4,7 +4,7 @@ URL: https://www.example.com/metadata, https://www.example.com/parser Version: 1.0.12 Date: 2020-12-03 -License: Apache, 2.0 and MIT +License: Apache-2.0 and MIT License File: LICENSE Security Critical: yes Shipped: yes diff --git a/metadata/tests/data/README.chromium.test.multi-valid b/metadata/tests/data/README.chromium.test.multi-valid index 18db89113..6eb8a1710 100644 --- a/metadata/tests/data/README.chromium.test.multi-valid +++ b/metadata/tests/data/README.chromium.test.multi-valid @@ -4,7 +4,7 @@ URL: https://www.example.com/metadata, https://www.example.com/parser Version: 1.0.12 Date: 2020-12-03 -License: Apache, 2.0 and MIT +License: Apache-2.0 and MIT License File: LICENSE Security Critical: yes Shipped: yes @@ -26,7 +26,7 @@ Short Name: metadata-test-valid-again URL: https://www.example.com/metadata Version: 1.0.12 Date: 2020-12-03 -License: Apache, 2.0 and MIT +License: MIT License File: LICENSE Security Critical: yes Shipped: yes @@ -38,7 +38,7 @@ Short Name: metadata-test-valid-again URL: https://www.example.com/metadata Version: 1.0.12 Date: 2020-12-03 -License: Apache, 2.0 and MIT +License: Apache-2.0 License File: LICENSE Security Critical: yes Shipped in Chromium: yes diff --git a/metadata/tests/dependency_metadata_test.py b/metadata/tests/dependency_metadata_test.py index 41db8167e..87acdc470 100644 --- a/metadata/tests/dependency_metadata_test.py +++ b/metadata/tests/dependency_metadata_test.py @@ -30,7 +30,7 @@ class DependencyValidationTest(unittest.TestCase): dependency.add_entry(known_fields.URL.get_name(), "https://www.example.com") dependency.add_entry(known_fields.VERSION.get_name(), "1.0.0") - dependency.add_entry(known_fields.LICENSE.get_name(), "Public Domain") + dependency.add_entry(known_fields.LICENSE.get_name(), "MIT") dependency.add_entry(known_fields.LICENSE_FILE.get_name(), "LICENSE") dependency.add_entry(known_fields.SECURITY_CRITICAL.get_name(), "no") dependency.add_entry(known_fields.SHIPPED.get_name(), "no") @@ -53,7 +53,7 @@ class DependencyValidationTest(unittest.TestCase): "Test alias field used") dependency.add_entry(known_fields.VERSION.get_name(), "1.0.0") dependency.add_entry(known_fields.LICENSE_FILE.get_name(), "LICENSE") - dependency.add_entry(known_fields.LICENSE.get_name(), "Public domain") + dependency.add_entry(known_fields.LICENSE.get_name(), "MIT") # Use Shipped in Chromium instead of Shipped. dependency.add_entry(known_fields.SHIPPED_IN_CHROMIUM.get_name(), "no") dependency.add_entry(known_fields.SECURITY_CRITICAL.get_name(), "no") @@ -75,7 +75,7 @@ class DependencyValidationTest(unittest.TestCase): "Test alias field overwrite") dependency.add_entry(known_fields.VERSION.get_name(), "1.0.0") dependency.add_entry(known_fields.LICENSE_FILE.get_name(), "LICENSE") - dependency.add_entry(known_fields.LICENSE.get_name(), "Public domain") + dependency.add_entry(known_fields.LICENSE.get_name(), "MIT") dependency.add_entry(known_fields.SHIPPED_IN_CHROMIUM.get_name(), "no") dependency.add_entry(known_fields.SHIPPED.get_name(), "test") dependency.add_entry(known_fields.SECURITY_CRITICAL.get_name(), "no") @@ -98,7 +98,7 @@ class DependencyValidationTest(unittest.TestCase): "Test alias field error attributed") dependency.add_entry(known_fields.VERSION.get_name(), "1.0.0") dependency.add_entry(known_fields.LICENSE_FILE.get_name(), "LICENSE") - dependency.add_entry(known_fields.LICENSE.get_name(), "Public domain") + dependency.add_entry(known_fields.LICENSE.get_name(), "MIT") dependency.add_entry(known_fields.SHIPPED_IN_CHROMIUM.get_name(), "test") dependency.add_entry(known_fields.SHIPPED.get_name(), "yes") @@ -121,7 +121,7 @@ class DependencyValidationTest(unittest.TestCase): dependency.add_entry(known_fields.URL.get_name(), "https://www.example.com") dependency.add_entry(known_fields.VERSION.get_name(), "N/A") - dependency.add_entry(known_fields.LICENSE.get_name(), "Public Domain") + dependency.add_entry(known_fields.LICENSE.get_name(), "MIT") dependency.add_entry(known_fields.LICENSE_FILE.get_name(), "LICENSE") dependency.add_entry(known_fields.SECURITY_CRITICAL.get_name(), "no") dependency.add_entry(known_fields.SHIPPED.get_name(), "no") @@ -145,7 +145,7 @@ class DependencyValidationTest(unittest.TestCase): "https://www.example.com") dependency.add_entry(known_fields.VERSION.get_name(), "N/A") dependency.add_entry(known_fields.REVISION.get_name(), "N/A") - dependency.add_entry(known_fields.LICENSE.get_name(), "Public Domain") + dependency.add_entry(known_fields.LICENSE.get_name(), "MIT") dependency.add_entry(known_fields.LICENSE_FILE.get_name(), "LICENSE") dependency.add_entry(known_fields.SECURITY_CRITICAL.get_name(), "no") dependency.add_entry(known_fields.SHIPPED.get_name(), "no") @@ -173,7 +173,7 @@ class DependencyValidationTest(unittest.TestCase): dependency.add_entry(known_fields.VERSION.get_name(), "1.0.0") dependency.add_entry(known_fields.REVISION.get_name(), "invalid_revision") - dependency.add_entry(known_fields.LICENSE.get_name(), "Public Domain") + dependency.add_entry(known_fields.LICENSE.get_name(), "MIT") dependency.add_entry(known_fields.LICENSE_FILE.get_name(), "LICENSE") dependency.add_entry(known_fields.SECURITY_CRITICAL.get_name(), "no") dependency.add_entry(known_fields.SHIPPED.get_name(), "no") @@ -197,7 +197,7 @@ class DependencyValidationTest(unittest.TestCase): dependency.add_entry(known_fields.URL.get_name(), "https://www.example.com") dependency.add_entry(known_fields.VERSION.get_name(), "1.0.0") - dependency.add_entry(known_fields.LICENSE.get_name(), "Public Domain") + dependency.add_entry(known_fields.LICENSE.get_name(), "MIT") dependency.add_entry(known_fields.LICENSE_FILE.get_name(), "LICENSE") dependency.add_entry(known_fields.SECURITY_CRITICAL.get_name(), "no") dependency.add_entry(known_fields.SHIPPED.get_name(), "no") @@ -227,7 +227,7 @@ class DependencyValidationTest(unittest.TestCase): "https://www.example.com") dependency.add_entry(known_fields.VERSION.get_name(), "N/A") dependency.add_entry(known_fields.REVISION.get_name(), "DEPS") - dependency.add_entry(known_fields.LICENSE.get_name(), "Public Domain") + dependency.add_entry(known_fields.LICENSE.get_name(), "MIT") dependency.add_entry(known_fields.LICENSE_FILE.get_name(), "LICENSE") dependency.add_entry(known_fields.SECURITY_CRITICAL.get_name(), "no") dependency.add_entry(known_fields.SHIPPED.get_name(), "no") @@ -245,7 +245,7 @@ class DependencyValidationTest(unittest.TestCase): dependency.add_entry(known_fields.SHIPPED.get_name(), "no") dependency.add_entry(known_fields.SECURITY_CRITICAL.get_name(), "no") dependency.add_entry(known_fields.LICENSE_FILE.get_name(), "LICENSE") - dependency.add_entry(known_fields.LICENSE.get_name(), "Public Domain") + dependency.add_entry(known_fields.LICENSE.get_name(), "MIT") dependency.add_entry(known_fields.VERSION.get_name(), "1.0.0") dependency.add_entry(known_fields.NAME.get_name(), "Test missing field") # Leave URL field unspecified. @@ -267,7 +267,7 @@ class DependencyValidationTest(unittest.TestCase): dependency.add_entry(known_fields.NAME.get_name(), "Test invalid field") dependency.add_entry(known_fields.VERSION.get_name(), "1.0.0") dependency.add_entry(known_fields.LICENSE_FILE.get_name(), "LICENSE") - dependency.add_entry(known_fields.LICENSE.get_name(), "Public domain") + dependency.add_entry(known_fields.LICENSE.get_name(), "MIT") dependency.add_entry(known_fields.SHIPPED.get_name(), "no") dependency.add_entry(known_fields.SECURITY_CRITICAL.get_name(), "test") @@ -288,7 +288,7 @@ class DependencyValidationTest(unittest.TestCase): dependency.add_entry(known_fields.URL.get_name(), "https://www.example.com") dependency.add_entry(known_fields.VERSION.get_name(), "1.0.0") - dependency.add_entry(known_fields.LICENSE.get_name(), "Public domain") + dependency.add_entry(known_fields.LICENSE.get_name(), "MIT") dependency.add_entry(known_fields.LICENSE_FILE.get_name(), "MISSING-LICENSE") dependency.add_entry(known_fields.SECURITY_CRITICAL.get_name(), "no") @@ -309,7 +309,7 @@ class DependencyValidationTest(unittest.TestCase): "Test multiple errors") # Leave URL field unspecified. dependency.add_entry(known_fields.VERSION.get_name(), "1.0.0") - dependency.add_entry(known_fields.LICENSE.get_name(), "Public domain") + dependency.add_entry(known_fields.LICENSE.get_name(), "MIT") dependency.add_entry(known_fields.LICENSE_FILE.get_name(), "MISSING-LICENSE") dependency.add_entry(known_fields.SECURITY_CRITICAL.get_name(), "test") @@ -335,7 +335,7 @@ class DependencyValidationTest(unittest.TestCase): dependency.add_entry(known_fields.URL.get_name(), "https://www.example.com") dependency.add_entry(known_fields.VERSION.get_name(), "1.0.0") - dependency.add_entry(known_fields.LICENSE.get_name(), "Public Domain") + dependency.add_entry(known_fields.LICENSE.get_name(), "MIT") dependency.add_entry(known_fields.LICENSE_FILE.get_name(), "LICENSE") dependency.add_entry(known_fields.SECURITY_CRITICAL.get_name(), "no") dependency.add_entry(known_fields.SHIPPED.get_name(), "no") @@ -357,7 +357,7 @@ class DependencyValidationTest(unittest.TestCase): dependency.add_entry(known_fields.URL.get_name(), "This is the canonical repository") dependency.add_entry(known_fields.VERSION.get_name(), "N/A") - dependency.add_entry(known_fields.LICENSE.get_name(), "Public Domain") + dependency.add_entry(known_fields.LICENSE.get_name(), "MIT") dependency.add_entry(known_fields.LICENSE_FILE.get_name(), "LICENSE") dependency.add_entry(known_fields.SECURITY_CRITICAL.get_name(), "yes") dependency.add_entry(known_fields.SHIPPED.get_name(), "yes") diff --git a/metadata/tests/fields_test.py b/metadata/tests/fields_test.py index 148233327..1cf8cc566 100644 --- a/metadata/tests/fields_test.py +++ b/metadata/tests/fields_test.py @@ -115,13 +115,12 @@ class FieldValidationTest(unittest.TestCase): self._run_field_validation( field=known_fields.LICENSE, valid_values=[ - "Apache, 2.0 / MIT / MPL 2", - "LGPL 2.1", - "GPL v2 or later", - "LGPL2 with the classpath exception", - "Apache, Version 2 and Public domain", - "Public domain or MPL 2", - "APSL 2 and the MIT license", + "Apache-2.0 / MIT", + "Apache-2.0", + "BSD-2-Clause", + "BSD-2-Clause-FreeBSD", + "MIT", + "APSL-2.0 and MIT", ], error_values=["", "\n", ",", "Apache 2.0 / MIT / "], warning_values=[ diff --git a/metadata/tests/parse_test.py b/metadata/tests/parse_test.py index e32d1c83b..169d716ec 100644 --- a/metadata/tests/parse_test.py +++ b/metadata/tests/parse_test.py @@ -77,7 +77,7 @@ class ParseTest(unittest.TestCase): " https://www.example.com/parser"), ("Version", "1.0.12"), ("Date", "2020-12-03"), - ("License", "Apache, 2.0 and MIT"), + ("License", "Apache-2.0 and MIT"), ("License File", "LICENSE"), ("Security Critical", "yes"), ("Shipped", "yes"),