From mboxrd@z Thu Jan 1 00:00:00 1970 Delivery-date: Mon, 19 Feb 2024 17:56:54 +0100 Received: from metis.whiteo.stw.pengutronix.de ([2a0a:edc0:2:b01:1d::104]) by lore.white.stw.pengutronix.de with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1rc6wo-00Evsk-2Z for lore@lore.pengutronix.de; Mon, 19 Feb 2024 17:56:54 +0100 Received: from localhost ([127.0.0.1] helo=metis.whiteo.stw.pengutronix.de) by metis.whiteo.stw.pengutronix.de with esmtp (Exim 4.92) (envelope-from ) id 1rc6wo-0005Ok-4k; Mon, 19 Feb 2024 17:56:54 +0100 Received: from mail-gv0che01on2099.outbound.protection.outlook.com ([40.107.23.99] helo=CHE01-GV0-obe.outbound.protection.outlook.com) by metis.whiteo.stw.pengutronix.de with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1rc6wg-0005BD-4D for ptxdist@pengutronix.de; Mon, 19 Feb 2024 17:56:46 +0100 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=SgIskk5MlBEC1BsADzCIckdQIOohJ0u3rkHyUtiyQlvkI5OxljooyfRUftjXixWUs3tX4N0GR10hiEn3T/MQl0A6WAvH0lJRc78Crl4iO91J2dMrNCGgzS5oD19P5qoUteBnaus902+xnGWczLth3GBs2Lmj5a47FWvsm7jWKdxOwKpiHYp5fMqqHnTcKokp1kZHU9uTKq/Sgpa+CrLIEw57ZjpETDnC8wXesxw4gNuzDi0u0jdqMhu1nPsJ6bLs3WzVVTEdFUqoKfEe8i3LIetLOHcJfSXm59TTYBkcsOkoytgs4jTX8lPlk5U8mXhHpOXtK/loRku7VGd3aYMyYg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=IWAvH+6GweermKuGnBG5i0lT4OW03uCd0FwzO0ImDiI=; b=TqcU4PnkumuzvtGDHZ68XnZjvB8vd6mJ76MINqheEgMSIzNeOe11Y/VOKu8saesmKswhmzmGH/hxnB9aONAUaro7i7NCOQzdOCLXC/ds+yV5LFqcn5Rk4JoGgNOQB5pyIMYtQ/MzjcjxGIKptdfWBUiREnr09KSoLKj3SS422RhPBxf3IRy+bsgLNM/X+LF7V56Breawr3DccWPdUNgJtSzMhtmuptfDYDZR+e8N2FxqigJcP3Tt7UdjL4Vl4dkQQvygKerEhjrQf2cXrV7XdNlwSTBhYRiBLPu68jpwbOfzkzUbdYL3S+OSUi8KNrBFf+ka3RR0ZsnMs/jzKT9M4g== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=verity.net; dmarc=pass action=none header.from=verity.net; dkim=pass header.d=verity.net; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=verity.net; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=IWAvH+6GweermKuGnBG5i0lT4OW03uCd0FwzO0ImDiI=; b=SbqwXm6w1ZuhzXx24kW5uJwHwmjFNSAO6zfrXXBGI027wisWjBmV2Wd4D+aNfraF3ff6ON5N5DbTWiyhoMPcqJjHIQ05IG50WaRK4lXpu6r0GpLhMzHx8GZAPXjgQ5qBUMDvWVusbcIQiTR0wukL1GtrWwGMgPZR8ejnZ895uXqZWWKG7eQKBXmmAHpzYYcQ8SnpYr+NJBJo0lxJOeNU2cOXP/Eg2Dy1kXbjHbhEPXofBp48eh7k9k2zujVx0a8GDSEFqLEeZB1URUPET55ICvuTKg8WLiEm8DOPuBAvhQI5mSH8NJWgKOXmCQH2aEHTcXAiBac8R9PgR2WCHsu+Fg== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=verity.net; Received: from ZR0P278MB0991.CHEP278.PROD.OUTLOOK.COM (2603:10a6:910:54::8) by ZR0P278MB1136.CHEP278.PROD.OUTLOOK.COM (2603:10a6:910:54::7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7292.38; Mon, 19 Feb 2024 16:56:44 +0000 Received: from ZR0P278MB0991.CHEP278.PROD.OUTLOOK.COM ([fe80::11ae:207:fffc:fdd1]) by ZR0P278MB0991.CHEP278.PROD.OUTLOOK.COM ([fe80::11ae:207:fffc:fdd1%7]) with mapi id 15.20.7292.036; Mon, 19 Feb 2024 16:56:44 +0000 From: Simon Falsig To: ptxdist@pengutronix.de Date: Mon, 19 Feb 2024 17:56:17 +0100 Message-Id: <20240219165617.70971-3-sfalsig@verity.net> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240219165617.70971-1-sfalsig@verity.net> References: <20240219165617.70971-1-sfalsig@verity.net> Content-Transfer-Encoding: 8bit Content-Type: text/plain X-ClientProxiedBy: ZR0P278CA0015.CHEP278.PROD.OUTLOOK.COM (2603:10a6:910:16::25) To ZR0P278MB0991.CHEP278.PROD.OUTLOOK.COM (2603:10a6:910:54::8) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: ZR0P278MB0991:EE_|ZR0P278MB1136:EE_ X-MS-Office365-Filtering-Correlation-Id: b1e1e8a6-1c74-4f0f-1de5-08dc316bc0d5 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: bEE7M/jtGGq62/Ul6GTmwf/3592M1wj5qzg2jXEazNd4zY2SMJ8vUtS/uUfGViWaczjTFv4srmBiAKjmOTONUm9MCybE+w1BM1N5dCfA1lXo9HOtkfodVZ6K541Wa1JRucV+fTBPZC9mcdYjzAp7kUvmokrhKo/EL3SRDnRp/BzrAULpNTjBBbfy6NAGH1QBYfb0ORCUTnNfIQNQypYHJDsOFbaYeZM2uRYK3bKXlKWFpNUTZS3hZpslMeTOiq7bgfC1hOWUO3fR+ek8ohh0X4NGzXtFIMNKgHrLkqMJ7Ir3oaMBtIfiHSncZilLhe42ER/EgK4UiY0daEKMDGl4dkKnEiPw4ktPN2bkMn0O+bhjkIay1hez6Dh7uKsflaVkmrtRBJVYg+CmEsU55S0/YsQC1wO1AsPC5FPeUUuqVIroFbIIbh03fq1aMstJr0PHboKznGMEaRoFAzecr3EMTBKG8r6eMkppSaRqNEeEXLAzIaOJacDSGYlDpdyhiDIzwL9aoxZygk7orcvqVyhSlEon4Pwbh6krDUEKjNoi9RAGP8F2kOXvqrD4Eca+H/Fsz7kTfj0/Jd06ukwO0Hbgn8qPT/86Y6zIhuHU63d8xhM= X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:ZR0P278MB0991.CHEP278.PROD.OUTLOOK.COM; PTR:; CAT:NONE; SFS:(13230031)(38350700005); DIR:OUT; SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?0IjPoJlBxmidzhZo5Dj44ulNKWYUX/juUbf/vCB+q/KuemKGXL2Rp5v96vko?= =?us-ascii?Q?3YtUCIN3uP1TljrCD0SWSUw+LJ5Fx4ew4jdOiMGDp0Wq2GBkHM5OHY0rr1/Y?= =?us-ascii?Q?MJQTpuUew60VfduOvDeVfaDMthAiuOCli/OH3XzsRhiFvxNjcs/5cqBE6AIy?= =?us-ascii?Q?DhYZFI2CLwuESpKF+nk+U0tgDNfxJL1nqLLdHvL8OmDmSEJ1WVpELfbXhGhc?= =?us-ascii?Q?XIK4l4TPkcaTPY4aK7wLrJf+TtIcVO5bSGKsYU+m4ym2Og2dCnhsZL4WYI4P?= =?us-ascii?Q?HbZOZ0SF5ZFI/SSRTmjgv6J7URkxM5vOxkT0S5ukqsQ1KSXTOXy8J7abGoNH?= =?us-ascii?Q?sMVi77ru2MbQcKKYebcx5lCSRZc6rk3eupC4Gz9rMHrYeUmNzq6ZHrPYiQ5c?= =?us-ascii?Q?67elwQyIObhcIhONC/seoQ4GHb+kNNQWnlh37WvEyCxhu8JzAAjX/0pWdjtE?= =?us-ascii?Q?wFBNkG206RjClZFLP3t7EbOkMD+OwcqYkzHb8yrE/EFFicspgmj42ikTya1D?= =?us-ascii?Q?JC1hw/OHccef7OaxY5FXReqkM85bW24JftczpulNBfURE7iSOeeN3NZ0AWou?= =?us-ascii?Q?SEbXVeoNJdTczJGmj2U0lLBdbvrhSLT2L24Pf1LPE8hoNC9mVC5HQaLdWHeE?= =?us-ascii?Q?XWfhdGuvIn5Pey09LPpbNClMJU9kj8w6UCiK7siZ0k+Hn/V7xz1ocUIOipwT?= =?us-ascii?Q?3Fl5xNlY7zToY3VN50jK38M1M4LgReP15w67UC/zJmwmNRXe1eU5EBNA5XGB?= =?us-ascii?Q?vrWV1r3bPD31bK7B13qYMBFzxADkruDGnmtCMJPP9pbLTdj0TX4GGvMj3xDH?= =?us-ascii?Q?dIfxJpPQ5HW7Tq4cBaH1j6DgpEGZSFhJMnq2ua4cs5JSzrX2hV73AZh8kiwz?= =?us-ascii?Q?B3AjsK/dM1Dy0FJ0ZfSFC/jCSoE8+zCxIAzPOUKU0O6DPVS8LRfemua82iVe?= =?us-ascii?Q?tLDG8yVlFW+n8lfah0wYQjmfSDzdT8phD8whQTdyMMeXjk8lFH1k5uVm2vyH?= =?us-ascii?Q?9Wl1ak7dxGm9jsw1TscDsyh++h6IGKCAQUdR6uJxA8a0ShE7WQZ8pNrVKdza?= =?us-ascii?Q?Al1kcBVzj/hsc3QAtJ6lqE2t/Vr1oJzKtV97vBGz2WpnyvDIo1SbQqRu/7Zk?= =?us-ascii?Q?m42yZLJlMH6cb0r9tkaMG5x/AL5yMqNO01gSH4SbsRWlAnA/adNFrD5Y6sKJ?= =?us-ascii?Q?Suquxbrc94NDqEpbWEmeq7fy4UsfJtyLRoOnQUqhkajmMBw0EdjPthMqD0sw?= =?us-ascii?Q?j6qHLmOk+tel6JvYvgucYT0B9v2GgUeO77zC2aY4VMld+ivPT4bCqyB6ikZw?= =?us-ascii?Q?4/KgnBEVC0fIWXA596cBRH0xygU9QBTk/S4QGsPBqDUjA3YTU2MKOMaQh3Ry?= =?us-ascii?Q?dOmaD56m7C7Y2bcJWaQrRlZJHzrFbFnmDJ+7qw+RETKSipjuKbM4ZAw1l4QK?= =?us-ascii?Q?S5awNY10HIY1zuttCJHL0hnWLfH0+mfaXf1kxLgd5B7fDcZifRN4Q8XJ0TBJ?= =?us-ascii?Q?CSS8IzZxpwpZ0tltZQQKnhoxcw7lo204HoFC63rn3HJM6R7TKNyA/2l1PLYl?= =?us-ascii?Q?I4p3ebk3l3F3DL1zys7v69u7nxv90M8iHKjo0mJa?= X-OriginatorOrg: verity.net X-MS-Exchange-CrossTenant-Network-Message-Id: b1e1e8a6-1c74-4f0f-1de5-08dc316bc0d5 X-MS-Exchange-CrossTenant-AuthSource: ZR0P278MB0991.CHEP278.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 19 Feb 2024 16:56:44.7351 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 06487c72-7d88-4632-bf56-071603defa0a X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: WMb1SIkKXtIhXtxRhFEEZBxPRkn8PvHR9MPQGnJcCsaFQOh7XlRmLgX+fJpJXc53NNA7JmxPb5YDN7EwQWJsKg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: ZR0P278MB1136 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on metis.whiteo.stw.pengutronix.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=4.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2,SPF_HELO_PASS,SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.2 Subject: [ptxdist] [PATCH 3/3] RFC: sbom_report: Add support X-BeenThere: ptxdist@pengutronix.de X-Mailman-Version: 2.1.29 Precedence: list List-Id: PTXdist Development Mailing List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: ptxdist@pengutronix.de Cc: Simon Falsig Sender: "ptxdist" X-SA-Exim-Connect-IP: 127.0.0.1 X-SA-Exim-Mail-From: ptxdist-bounces@pengutronix.de X-SA-Exim-Scanned: No (on metis.whiteo.stw.pengutronix.de); SAEximRunCond expanded to false This provides support for building SBOMs in CycloneDX format. A target is added alongside the other reports, that (based on the fast-bsp-report) extracts name, version, cpe and license of each target package, and puts these into a final sbom-report in CycloneDX/JSON format. This requires a working Python3 setup with the cyclonedx-python-lib package installed. --- bin/ptxdist | 3 +- rules/host-system-python3.in | 3 ++ rules/host-system-python3.make | 6 ++++ rules/post/ptxd_make_report.make | 16 +++++++-- rules/sbom-report.in | 9 +++++ scripts/lib/ptxd_make_report.sh | 16 +++++++++ scripts/lib/ptxd_make_sbom_report.py | 52 ++++++++++++++++++++++++++++ 7 files changed, 102 insertions(+), 3 deletions(-) create mode 100644 rules/sbom-report.in create mode 100644 scripts/lib/ptxd_make_sbom_report.py diff --git a/bin/ptxdist b/bin/ptxdist index 77cad673b..9e62d2bc0 100755 --- a/bin/ptxdist +++ b/bin/ptxdist @@ -792,6 +792,7 @@ Misc: full-bsp-report generate a yaml file that describes the BSP and all packages. More data but will build all packages if necessary. + sbom-report generate a CycloneDX json SBOM print print the contents of a variable, in the way it is known by "make" printnext assumes that the contents of is another @@ -1841,7 +1842,7 @@ EOF ptxd_make_log export_src EXPORTDIR="${1}" exit ;; - fast-bsp-report|full-bsp-report) + fast-bsp-report|full-bsp-report|sbom-report) check_premake_compiler && ptxd_make_log "${cmd}" exit diff --git a/rules/host-system-python3.in b/rules/host-system-python3.in index 25201e93f..c158a295f 100644 --- a/rules/host-system-python3.in +++ b/rules/host-system-python3.in @@ -35,4 +35,7 @@ config HOST_SYSTEM_PYTHON3_PYELFTOOLS config HOST_SYSTEM_PYTHON3_PYYAML bool +config HOST_SYSTEM_PYTHON3_CYCLONEDX + bool + endif diff --git a/rules/host-system-python3.make b/rules/host-system-python3.make index 3688cf09d..f4979a453 100644 --- a/rules/host-system-python3.make +++ b/rules/host-system-python3.make @@ -88,6 +88,12 @@ ifdef PTXCONF_HOST_SYSTEM_PYTHON3_PYYAML ptxd_bailout "Python pyyaml module not found! \ Please install python3-yaml (debian)"; endif +ifdef PTXCONF_HOST_SYSTEM_PYTHON3_CYCLONEDX + @echo "Checking for Python cyclonedx-python-lib ..." + @$(SYSTEMPYTHON3) -c 'import cyclonedx.factory' 2>/dev/null || \ + ptxd_bailout "Python cyclonedx-python-lib module not found! \ + Please install cyclonedx-python-lib (pip)"; +endif @$(call touch) diff --git a/rules/post/ptxd_make_report.make b/rules/post/ptxd_make_report.make index eecd2a577..529b1c78e 100644 --- a/rules/post/ptxd_make_report.make +++ b/rules/post/ptxd_make_report.make @@ -10,7 +10,10 @@ ptx/report-env = \ $(image/env) \ ptx_report_target="$(strip $(1))" \ ptx_packages_selected="$(filter-out $(IMAGE_PACKAGES),$(PTX_PACKAGES_SELECTED))" \ - ptx_image_packages="$(IMAGE_PACKAGES)" + ptx_image_packages="$(IMAGE_PACKAGES)" \ + ptx_target_packages="$(PACKAGES)" \ + ptx_system_python3="$(SYSTEMPYTHON3)" + PHONY += full-bsp-report full-bsp-report: $(RELEASEDIR)/full-bsp-report.yaml @@ -26,13 +29,22 @@ $(RELEASEDIR)/full-bsp-report.yaml: \ @$(call ptx/report-env, $@) ptxd_make_full_bsp_report @$(call finish) + PHONY += fast-bsp-report fast-bsp-report: $(RELEASEDIR)/fast-bsp-report.yaml - $(RELEASEDIR)/fast-bsp-report.yaml: $(addprefix $(STATEDIR)/,$(addsuffix .fast-report,$(PTX_PACKAGES_SELECTED))) @$(call targetinfo) @$(call ptx/report-env, $@) ptxd_make_fast_bsp_report @$(call finish) + +PHONY += sbom-report +sbom-report: $(RELEASEDIR)/sbom-report.json + +$(RELEASEDIR)/sbom-report.json: $(STATEDIR)/host-system-python3.install $(addprefix $(STATEDIR)/,$(addsuffix .fast-report,$(PACKAGES))) + @$(call targetinfo) + @$(call ptx/report-env, $@) ptxd_make_sbom_report + @$(call finish) + # vim: syntax=make diff --git a/rules/sbom-report.in b/rules/sbom-report.in new file mode 100644 index 000000000..311ad5a23 --- /dev/null +++ b/rules/sbom-report.in @@ -0,0 +1,9 @@ +## SECTION=ptxdist_options + +config ENABLE_SBOM_REPORT + bool + select HOST_SYSTEM_PYTHON3 + select HOST_SYSTEM_PYTHON3_CYCLONEDX + prompt "enable sbom report generation" + help + This enables the generation of an SBOM report, through ptxdist sbom-report. diff --git a/scripts/lib/ptxd_make_report.sh b/scripts/lib/ptxd_make_report.sh index 885f07828..f2e92e6be 100644 --- a/scripts/lib/ptxd_make_report.sh +++ b/scripts/lib/ptxd_make_report.sh @@ -146,3 +146,19 @@ ptxd_make_fast_bsp_report() { } export -f ptxd_make_fast_bsp_report +ptxd_make_sbom_report() { + local -a ptxd_reply + local pkg_lic pkg + + ptxd_make_layer_init || return + + echo "Generating $(ptxd_print_path "${ptx_report_target}") ..." + echo + + mkdir -p "$(dirname "${ptx_report_target}")" && + "${ptx_system_python3}" ${PTXDIST_LIB_DIR}/ptxd_make_sbom_report.py "${ptx_report_dir}/fast/" ${ptx_target_packages} > ${PTXDIST_TEMPDIR}/sbom-report && + mv "${PTXDIST_TEMPDIR}/sbom-report" "${ptx_report_target}" || + ptxd_bailout "failed to create SBOM report" +} +export -f ptxd_make_sbom_report + diff --git a/scripts/lib/ptxd_make_sbom_report.py b/scripts/lib/ptxd_make_sbom_report.py new file mode 100644 index 000000000..a9ec36697 --- /dev/null +++ b/scripts/lib/ptxd_make_sbom_report.py @@ -0,0 +1,52 @@ +from cyclonedx.factory.license import LicenseFactory +from cyclonedx.model.bom import Bom +from cyclonedx.model.component import Component +from cyclonedx.output.json import JsonV1Dot4 +import sys +import re + +lFac = LicenseFactory() +bom = Bom() + +for i in range(2, len(sys.argv)): + pkg_report = sys.argv[1] + sys.argv[i] + ".yaml" + with open(pkg_report, 'r') as file: + content = file.read() + name_ = re.search("name: \'(.+)\'", content).group(1) + version_ = re.search("version: \'(.+)\'", content).group(1) + + # First see if we have a full CPE specified, then use that + cpe_match = re.search("cpe: \'(.+)\'", content) + cpe_ = None + if cpe_match is not None: + cpe_ = cpe_match.group(1) + else: + # See if we have the individual components + cpe_vendor_match = re.search("cpe_vendor: \'(.+)\'", content) + cpe_product_match = re.search("cpe_product: \'(.+)\'", content) + cpe_version_match = re.search("cpe_version: \'(.+)\'", content) + if cpe_vendor_match is not None and cpe_product_match is not None and cpe_version_match is not None: + cpe_ = "cpe:2.3:a:{vendor}:{product}:{version}:*:*:*:*:*:*:*".format(vendor=cpe_vendor_match.group(1), + product=cpe_product_match.group(1), + version=cpe_version_match.group(1)) + + if cpe_ is not None: + # We have a CPE, let's validate it. Regex from: https://csrc.nist.gov/schema/cpe/2.3/cpe-naming_2.3.xsd + if not re.fullmatch("cpe:2\.3:[aho\*\-](:(((\?*|\*?)([a-zA-Z0-9\-\._]|(\\[\\\*\?!\"#$$%&'\(\)\+,/:;" + "<=>@\[\]\^`\{\|}~]))+(\?*|\*?))|[\*\-])){5}(:(([a-zA-Z]{2,3}(-([a-zA-Z]{2}|[0-9]{3}))?)" + "|[\*\-]))(:(((\?*|\*?)([a-zA-Z0-9\-\._]|(\\[\\\*\?!\"#$$%&'\(\)\+,/:;<=>@\[\]\^`\{\|}~]" + "))+(\?*|\*?))|[\*\-])){4}", cpe_): + raise ValueError("Constructed CPE is not valid: {cpe}".format(cpe=cpe_)) + + licenses_ = re.search("licenses: \'(.+)\'", content).group(1) + comp = Component( + name=name_, + version=version_, + cpe=cpe_, + licenses=[lFac.make_from_string(licenses_)], + bom_ref=name_ + "@" + version_ + ) + bom.components.add(comp) + +serializedJSON = JsonV1Dot4(bom).output_as_string() +print(serializedJSON) -- 2.25.1