Improve the SPDX with the current values: - URL: extracted from `git remote`. If more than one remote, URL is not set. - Version: extracted from `git rev-parse` (commit id). - PURL and CPE for Zephyr: generated from URL and version. For zephyr, the tag is extracted, if present, and replace the commit id for the version field. Since official modules does not have tags, tags are not yet extracted for modules. To track vulnerabilities from modules dependencies, a new SBOM, `modules-deps.spdx` was created. It contains the `external-references` provided by the modules. It allows to easily track vulnerabilities from these external dependencies. Signed-off-by: Thomas Gagneret <thomas.gagneret@hexploy.com>
131 lines
4.3 KiB
Python
131 lines
4.3 KiB
Python
# Copyright (c) 2020, 2021 The Linux Foundation
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
import os
|
|
|
|
from west import log
|
|
|
|
from zspdx.walker import WalkerConfig, Walker
|
|
from zspdx.scanner import ScannerConfig, scanDocument
|
|
from zspdx.writer import writeSPDX
|
|
|
|
# SBOMConfig contains settings that will be passed along to the various
|
|
# SBOM maker subcomponents.
|
|
class SBOMConfig:
|
|
def __init__(self):
|
|
super(SBOMConfig, self).__init__()
|
|
|
|
# prefix for Document namespaces; should not end with "/"
|
|
self.namespacePrefix = ""
|
|
|
|
# location of build directory
|
|
self.buildDir = ""
|
|
|
|
# location of SPDX document output directory
|
|
self.spdxDir = ""
|
|
|
|
# should also analyze for included header files?
|
|
self.analyzeIncludes = False
|
|
|
|
# should also add an SPDX document for the SDK?
|
|
self.includeSDK = False
|
|
|
|
# create Cmake file-based API directories and query file
|
|
# Arguments:
|
|
# 1) build_dir: build directory
|
|
def setupCmakeQuery(build_dir):
|
|
# check that query dir exists as a directory, or else create it
|
|
cmakeApiDirPath = os.path.join(build_dir, ".cmake", "api", "v1", "query")
|
|
if os.path.exists(cmakeApiDirPath):
|
|
if not os.path.isdir(cmakeApiDirPath):
|
|
log.err(f'cmake api query directory {cmakeApiDirPath} exists and is not a directory')
|
|
return False
|
|
# directory exists, we're good
|
|
else:
|
|
# create the directory
|
|
os.makedirs(cmakeApiDirPath, exist_ok=False)
|
|
|
|
# check that codemodel-v2 exists as a file, or else create it
|
|
queryFilePath = os.path.join(cmakeApiDirPath, "codemodel-v2")
|
|
if os.path.exists(queryFilePath):
|
|
if not os.path.isfile(queryFilePath):
|
|
log.err(f'cmake api query file {queryFilePath} exists and is not a directory')
|
|
return False
|
|
# file exists, we're good
|
|
return True
|
|
else:
|
|
# file doesn't exist, let's create an empty file
|
|
cm_fd = open(queryFilePath, "w")
|
|
cm_fd.close()
|
|
return True
|
|
|
|
# main entry point for SBOM maker
|
|
# Arguments:
|
|
# 1) cfg: SBOMConfig
|
|
def makeSPDX(cfg):
|
|
# report any odd configuration settings
|
|
if cfg.analyzeIncludes and not cfg.includeSDK:
|
|
log.wrn(f"config: requested to analyze includes but not to generate SDK SPDX document;")
|
|
log.wrn(f"config: will proceed but will discard detected includes for SDK header files")
|
|
|
|
# set up walker configuration
|
|
walkerCfg = WalkerConfig()
|
|
walkerCfg.namespacePrefix = cfg.namespacePrefix
|
|
walkerCfg.buildDir = cfg.buildDir
|
|
walkerCfg.analyzeIncludes = cfg.analyzeIncludes
|
|
walkerCfg.includeSDK = cfg.includeSDK
|
|
|
|
# make and run the walker
|
|
w = Walker(walkerCfg)
|
|
retval = w.makeDocuments()
|
|
if not retval:
|
|
log.err("SPDX walker failed; bailing")
|
|
return False
|
|
|
|
# set up scanner configuration
|
|
scannerCfg = ScannerConfig()
|
|
|
|
# scan each document from walker
|
|
if cfg.includeSDK:
|
|
scanDocument(scannerCfg, w.docSDK)
|
|
scanDocument(scannerCfg, w.docApp)
|
|
scanDocument(scannerCfg, w.docZephyr)
|
|
scanDocument(scannerCfg, w.docBuild)
|
|
|
|
# write each document, in this particular order so that the
|
|
# hashes for external references are calculated
|
|
|
|
# write SDK document, if we made one
|
|
if cfg.includeSDK:
|
|
retval = writeSPDX(os.path.join(cfg.spdxDir, "sdk.spdx"), w.docSDK)
|
|
if not retval:
|
|
log.err("SPDX writer failed for SDK document; bailing")
|
|
return False
|
|
|
|
# write app document
|
|
retval = writeSPDX(os.path.join(cfg.spdxDir, "app.spdx"), w.docApp)
|
|
if not retval:
|
|
log.err("SPDX writer failed for app document; bailing")
|
|
return False
|
|
|
|
# write zephyr document
|
|
writeSPDX(os.path.join(cfg.spdxDir, "zephyr.spdx"), w.docZephyr)
|
|
if not retval:
|
|
log.err("SPDX writer failed for zephyr document; bailing")
|
|
return False
|
|
|
|
# write build document
|
|
writeSPDX(os.path.join(cfg.spdxDir, "build.spdx"), w.docBuild)
|
|
if not retval:
|
|
log.err("SPDX writer failed for build document; bailing")
|
|
return False
|
|
|
|
# write modules document
|
|
writeSPDX(os.path.join(cfg.spdxDir, "modules-deps.spdx"), w.docModulesExtRefs)
|
|
if not retval:
|
|
log.err("SPDX writer failed for modules-deps document; bailing")
|
|
return False
|
|
|
|
return True
|