diff --git a/README.md b/README.md index 45c0457..aa5944e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Synopsys Scan Yocto Script - bd_scan_yocto_via_sbom.py v1.0.10 +# Synopsys Scan Yocto Script - bd_scan_yocto_via_sbom.py v1.0.11 # PROVISION OF THIS SCRIPT This script is provided under the MIT license (see LICENSE file). @@ -63,6 +63,8 @@ For optimal Yocto scan results, consider the following: 3. Add the `cve_check` class to the Bitbake local.conf to ensure patched CVEs are identified, and then check that PHASE 6 picks up the cve-check file (see CVE PATCHING below). Optionally specify the output CVE check file using `--cve_check_file FILE`. 4. Where recipes have been modified from original versions against the OE data, use the `--max_oe_version_distance X.X.X` option to specify fuzzy matching against OE recipes (distance values in the range '0.0.1' to '0.0.10' are recommended), although this can also cause some matches to be disabled. Create 2 projects and compare the results with and without this option. +5. If you wish to add the Linux kernel and other packages specified in the image manifest only, +consider using the `--process_image_manifest` option and optionally specifying the image manifest license file path (--image_license_manifest FILEPATH) where it does not exist in the same folder and the license.manifest file. ## OPTIONAL BEHAVIOUR @@ -101,7 +103,12 @@ There are several additional options to modify the behaviour of this utility inc license.manifest not specified) -l LICENSE_MANIFEST, --license_manifest LICENSE_MANIFEST license.manifest file path (REQUIRED - default - 'license.manifest) + 'license.manifest') + -i IMAGE_LICENSE_MANIFEST, --image_license_manifest IMAGE_LICENSE_MANIFEST + Specify the image_license.manifest file path to process recipes from the core image. + --process_image_manifest + Process the image_license.manifest file to process recipes from the core image using the + default location. Alternatively specify the image_license.manifest file path. -b BITBAKE_LAYERS, --bitbake_layers_file BITBAKE_LAYERS File containing output of 'bitbake-layers show- recipes' command (REQUIRED) @@ -209,6 +216,9 @@ versions and the ones in the project and then to identify unmatched components w only consider using values which allow versions from different MINOR or MAJOR versions in exceptional circumstances (meaning the supplied value should probably be in the range 0.0.1 to 0.0.10). +- --process_image_manifest OR --image_license_manifest PATH: + - Process the image_license.manifest file to process and add recipes from the core image to the BOM. + ### EXAMPLE DISTANCE CALCULATIONS - Recipe version is 3.2.4 - closest previous OE recipe version is 3.2.1: Distance value would need to be minimum 0.0.3 - Recipe version is 3.2.4 - closest previous OE recipe version is 3.0.1: Distance value would need to be minimum 0.2.0 @@ -306,7 +316,8 @@ Multiple scans can be combined into the same Black Duck project (ensure to use t 6. I cannot see the Linux kernel in the Black Duck project. - _The kernel cannot always be identified due to a custom name format being used in Yocto. Consider adding the required kernel version to the project manually._ + _Consider using the `--process_image_manifest` OR `--image_license_manifest PATH` options to add processing of the + packages in the image manifest usually including the Linux kernel. Note that the kernel cannot always be identified due to a custom name format being used in Yocto in which case consider adding the required kernel version to the project manually._ 7. I am using another Yocto wrapper such as KAS https://kas.readthedocs.io/ and cannot run bitbake, or the script fails for some other reason. diff --git a/pyproject.toml b/pyproject.toml index 8119e5c..9e88d89 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "bd_scan_yocto_via_sbom" -version = "1.0.10" +version = "1.0.11" authors = [ { name="Matthew Brady", email="mbrad@synopsys.com" }, ] diff --git a/yocto_import_sbom/BBClass.py b/yocto_import_sbom/BBClass.py index dec3c7a..8ce11a2 100644 --- a/yocto_import_sbom/BBClass.py +++ b/yocto_import_sbom/BBClass.py @@ -26,6 +26,9 @@ def process(self, conf, reclist): return False self.process_licman_file(conf.license_manifest, reclist) + if conf.process_image_manifest: + self.process_licman_file(conf.image_license_manifest, reclist) + if not self.process_showlayers(tfile, reclist): return False return True @@ -227,6 +230,7 @@ def process_licman_file(lic_manifest_file, reclist): @staticmethod def check_files(conf): machine = conf.machine.replace('_', '-') + licman_dir = '' if not conf.license_manifest: if conf.license_dir: @@ -234,6 +238,7 @@ def check_files(conf): f"{conf.target}-{machine}", "license.manifest") if os.path.isfile(manpath): conf.license_manifest = manpath + licman_dir = os.path.dirname(manpath) if not conf.license_manifest: if not conf.target or not conf.machine: @@ -255,6 +260,19 @@ def check_files(conf): else: logging.info(f"Located license.manifest file {manifest}") conf.license_manifest = manifest + licman_dir = os.path.dirname(manifest) + + if conf.process_image_manifest: + if conf.image_license_manifest == '' and licman_dir != '': + image_licman = os.path.join(licman_dir, "image_license.manifest") + if os.path.isfile(image_licman): + conf.image_license_manifest = image_licman + if conf.image_license_manifest != '' and os.path.isfile(conf.image_license_manifest): + logging.info(f"Will process image license manifest file '{conf.image_license_manifest}'") + else: + logging.warning(f"Unable to locate image_license.manifest file and --process_image_manifest specified - " + f"Will skip processing") + conf.process_image_manifest = False imgdir = os.path.join(conf.deploy_dir, "images", machine) if conf.cve_check_file != "": diff --git a/yocto_import_sbom/ConfigClass.py b/yocto_import_sbom/ConfigClass.py index 306e49f..b433fbe 100644 --- a/yocto_import_sbom/ConfigClass.py +++ b/yocto_import_sbom/ConfigClass.py @@ -33,6 +33,13 @@ def __init__(self): "(usually determined from Bitbake env - default " "'license.manifest')", default="") + parser.add_argument("--process_image_manifest", + help="Process image_license.manifest file", + action='store_true') + parser.add_argument("-i", "--image_license_manifest", help="OPTIONAL image_license.manifest file path " + "(usually determined from Bitbake env - default " + "'image_license.manifest')", + default="") parser.add_argument("-b", "--bitbake_layers_file", help="OPTIONAL File containing output of 'bitbake-layers show-recipes' command (usually " "determined from Bitbake command)", @@ -96,6 +103,8 @@ def __init__(self): self.bd_trustcert = False self.skip_bitbake = args.skip_bitbake self.license_manifest = '' + self.image_license_manifest = '' + self.process_image_manifest = False self.target = '' self.machine = args.machine self.bitbake_layers_file = '' @@ -132,7 +141,7 @@ def __init__(self): else: logging.basicConfig(level=loglevel) - logging.info("Black Duck Yocto scan via SBOM utility - v1.0.10") + logging.info("Black Duck Yocto scan via SBOM utility - v1.0.11") logging.info("SUPPLIED ARGUMENTS:") for arg in vars(args): logging.info(f"--{arg}={getattr(args, arg)}") @@ -185,7 +194,19 @@ def __init__(self): if not os.path.exists(args.license_manifest): logging.error(f"License.manifest '{args.license_manifest}' file does not exist") terminate = True - self.license_manifest = args.license_manifest + else: + self.license_manifest = args.license_manifest + + if args.process_image_manifest: + self.process_image_manifest = True + + if args.image_license_manifest: + if not os.path.exists(args.image_license_manifest): + logging.error(f"License.manifest '{args.image_license_manifest}' file does not exist") + terminate = True + else: + self.image_license_manifest = args.image_license_manifest + self.process_image_manifest = True if args.target: self.target = args.target @@ -197,7 +218,8 @@ def __init__(self): if not os.path.exists(args.bitbake_layers_file): logging.error(f"Bitbake layers command output file '{args.bitbake_layers_file}' file does not exist") terminate = True - self.bitbake_layers_file = args.bitbake_layers_file + else: + self.bitbake_layers_file = args.bitbake_layers_file if args.cve_check_file and not os.path.exists(args.cve_check_file): logging.error(f"CVE Check file '{args.cve_check_file}' does not exist") diff --git a/yocto_import_sbom/main.py b/yocto_import_sbom/main.py index 70068f0..6bec258 100644 --- a/yocto_import_sbom/main.py +++ b/yocto_import_sbom/main.py @@ -68,7 +68,7 @@ def main(): logging.info("--- PHASE 6 - SIGNATURE SCAN PACKAGES ------------------------------------") if not conf.skip_sig_scan: if conf.package_dir and conf.download_dir: - if reclist.scan_pkg_download_files(conf, bom): + if not reclist.scan_pkg_download_files(conf, bom): logging.error(f"Unable to Signature scan package and download files") sys.exit(2) logging.info("Done")