from __future__ import annotations from depaudit.checks import LicenseInfo SPDX_LICENSES = { "MIT": "mit", "Apache-2.0": "apache-2.0", "Apache-2": "apache-2.0", "BSD-2-Clause": "bsd-2-clause", "BSD-3-Clause": "bsd-3-clause", "BSD": "bsd", "ISC": "isc", "GPL-2.0": "gpl-2.0", "GPL-3.0": "gpl-3.0", "GPL-3": "gpl-3.0", "LGPL-2.1": "lgpl-2.1", "LGPL-3.0": "lgpl-3.0", "MPL-2.0": "mpl-2.0", "MPL-2": "mpl-2.0", "AGPL-3.0": "agpl-3.0", "AGPL-3": "agpl-3.0", "OSL-3.0": "osl-3.0", "CC0": "cc0-1.0", "CC-BY-4.0": "cc-by-4.0", "CC-BY-SA-4.0": "cc-by-sa-4.0", } RESTRICTIVE_LICENSES = { "GPL-1.0", "GPL-2.0", "GPL-3.0", "AGPL-1.0", "AGPL-3.0", "SSPL", "OSL-1.0", "OSL-2.0", "OSL-3.0", "QPL-1.0", "CPOL-1.02", } PERMISSIVE_LICENSES = { "MIT", "Apache-2.0", "BSD-2-Clause", "BSD-3-Clause", "ISC", "MPL-2.0", "CC0", "Unlicense", } def normalize_license(license_str: str) -> str: license_str = license_str.strip() if "OR" in license_str or "AND" in license_str: licenses = [] for lic in license_str.replace("(", "").replace(")", "").split(): if lic in SPDX_LICENSES: licenses.append(SPDX_LICENSES[lic]) elif lic.upper() in SPDX_LICENSES: licenses.append(SPDX_LICENSES[lic.upper()]) return " AND ".join(licenses) if licenses else license_str if license_str.upper() in SPDX_LICENSES: return SPDX_LICENSES[license_str.upper()] for spdx_name, alias in SPDX_LICENSES.items(): if license_str.lower() == spdx_name.lower() or license_str.lower() == alias.lower(): return alias return license_str def check_license( package_name: str, license_str: str | None, source: str = "unknown", allowlist: list[str] | None = None, blocklist: list[str] | None = None, ) -> LicenseInfo: allowlist = allowlist or [] blocklist = blocklist or [] normalized = None if license_str: normalized = normalize_license(license_str) is_spdx = normalized in SPDX_LICENSES.values() if normalized else False license_info = LicenseInfo( package_name=package_name, license_type=normalized or license_str, license_expression=None, source=source, is_spdx_compliant=is_spdx, ) if normalized in RESTRICTIVE_LICENSES: license_info.license_expression = "restricted" return license_info def validate_license_compliance( license_info: LicenseInfo, allowlist: list[str], blocklist: list[str], ) -> tuple[bool, str]: license_type = license_info.license_type if license_type is None: return False, "Unknown license" normalized = normalize_license(license_type) normalized_blocklist = {normalize_license(lic) for lic in blocklist} normalized_allowlist = {normalize_license(lic) for lic in allowlist} if normalized in normalized_blocklist: return False, f"License {normalized} is in blocklist" if normalized in normalized_allowlist: return True, "License is allowed" if normalized in SPDX_LICENSES.values(): return True, "SPDX compliant license" return False, f"License {license_type} is not in allowlist"