blob: 989197fd07262fc6d68a4430e3f4c7d344aac109 [file] [log] [blame]
#!/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())