| #!/usr/bin/env python3 |
| # |
| # Copyright 2022 Google LLC |
| # |
| # This program is free software; you can redistribute it and/or |
| # modify it under the terms of the GNU General Public License |
| # version 2 as published by the Free Software Foundation. |
| # |
| # This program is distributed in the hope that it will be useful, |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| # GNU General Public License for more details. |
| # |
| |
| # This script is used to automatically generate package |
| # information for SBOM of COS image bundled dependencies. |
| |
| import json |
| import os |
| import sys |
| from sbom_info_lib import download_url |
| from sbom_info_lib import go_dep |
| from sbom_info_lib import licenses |
| from chromite.lib import osutils |
| from chromite.lib import portage_util |
| |
| |
| SBOM_INFO_FILE_NAME = "sbom-pkg-info.json" |
| SPDX_NOASSERTION = "NOASSERTION" |
| |
| |
| class SbomPackageInfo: |
| def __init__(self): |
| self.download_url = "" |
| self.licenses = "" |
| self.go_dep = [] |
| # Format: [{ |
| # "license_name": <license_name>, |
| # "file_names": [file_name], |
| # "license_txt": <license_txt> |
| # },{......}] |
| self.other_license_list = [] |
| self.private = False |
| self.err = "" |
| |
| def write_to_build_info(self, build_info_dir): |
| content = { |
| "download-url": self.download_url, |
| "licenses": self.licenses, |
| "go-dep": self.go_dep, |
| "other_licenses": self.other_license_list, |
| "private": self.private, |
| "err": self.err, |
| } |
| json_content = json.dumps(content, indent=4) |
| osutils.WriteFile( |
| f"{build_info_dir}/{SBOM_INFO_FILE_NAME}", json_content, makedirs=True |
| ) |
| |
| |
| class SBOMPkgInfoError(Exception): |
| def __init__(self, msg): |
| super().__init__(msg) |
| |
| |
| def read_build_info(build_info_dir): |
| with open(os.path.join(build_info_dir, "repository"), "r") as f: |
| repository = f.read().strip() |
| with open(os.path.join(build_info_dir, "CATEGORY"), "r") as f: |
| category = f.read().strip() |
| with open(os.path.join(build_info_dir, "PF"), "r") as f: |
| pf = f.read().strip() |
| license_path = os.path.join(build_info_dir, "LICENSE") |
| license = "" |
| if os.path.exists(license_path): |
| with open(license_path, "r") as f: |
| license = f.read().strip() |
| return repository, category, pf, license |
| |
| |
| def get_src_path(sysroot, fullname): |
| # Package source code has been fetched by gen-package-licenses.sh. |
| tmpdir = portage_util.PortageqEnvvar("PORTAGE_TMPDIR", sysroot=sysroot) |
| src_dir = os.path.join(tmpdir, "portage", fullname, "work") |
| |
| if not os.path.exists(src_dir): |
| raise AssertionError( |
| "Unpack of %s didn't create %s. Version mismatch" % (fullname, src_dir) |
| ) |
| return src_dir |
| |
| |
| def main(): |
| sbom_pkg_info = SbomPackageInfo() |
| package_dir = os.getenv("PORTAGE_BUILDDIR") |
| sysroot = "/".join(package_dir.split("/")[:3]) |
| build_info_dir = os.path.join(package_dir, "build-info") |
| try: |
| package_name = os.path.basename(package_dir) |
| ebuild = os.path.join(build_info_dir, package_name + ".ebuild") |
| repository, category, pf, license = read_build_info(build_info_dir) |
| if "private" in repository: |
| sbom_pkg_info.private = True |
| sbom_pkg_info.download_url = download_url.get_download_url( |
| ebuild, repository, category, pf, license |
| ) |
| src_path = get_src_path(sysroot, os.path.join(category, pf)) |
| ( |
| sbom_pkg_info.licenses, |
| sbom_pkg_info.other_license_list, |
| ) = licenses.get_licenses(build_info_dir, src_path, package_name) |
| sbom_pkg_info.go_dep = go_dep.get_go_dep(src_path) |
| |
| # Since download location is not required by the EO, failure to |
| # find download location shouldn't be fatal. |
| if not sbom_pkg_info.download_url and not sbom_pkg_info.private: |
| sbom_pkg_info.download_url = SPDX_NOASSERTION |
| if not sbom_pkg_info.licenses: |
| sbom_pkg_info.licenses = "NONE" |
| except Exception as e: |
| sbom_pkg_info.err = repr(e) |
| finally: |
| sbom_pkg_info.write_to_build_info(build_info_dir) |
| |
| |
| if __name__ == "__main__": |
| sys.exit(main()) |