From mboxrd@z Thu Jan 1 00:00:00 1970 Delivery-date: Mon, 18 Sep 2023 16:34:08 +0200 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.94.2) (envelope-from ) id 1qiFKD-0026uG-SH for lore@lore.pengutronix.de; Mon, 18 Sep 2023 16:34:08 +0200 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 1qiFKC-0003Zh-71; Mon, 18 Sep 2023 16:34:08 +0200 Received: from mail-zr0che01on2072.outbound.protection.outlook.com ([40.107.24.72] helo=CHE01-ZR0-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 1qiFK3-0003Ss-LU for ptxdist@pengutronix.de; Mon, 18 Sep 2023 16:34:00 +0200 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=Xw7ApjXfCZFC3OuLxc7/T0Etd2MkpLw42kDdJ16TQv3S8646Nqpkif13++QSfiGpXcfeNU+30TkSE8jmgjPB+m8/bve0WLB1bgSych6kzj5xc6a0XV6Lnzu/T7AOPqQZDGZDCW72f00KUGOZE3kkyzfWh4MRvMHdzjrIkXVa9OFxhHdMvSn6SKpjHdU4opu9IOP2ZJauOhlKc/RvsVS54KphA+Nla3IU0sg7UBMBITyUrTKSrLuz6M3pOPRZ4dVFX9j/J6bvqWIDx1uFoXOGUGCwI7YxgWB2lFFJ5jEg5PtYgPPrJ02Tyjl1dzEIEIlFWlN63luUmoBXcyU6duQMAQ== 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=P5jpZvOC5Zs0Z0VVok8gtcf2FYhopnptqFIbDiMXv7g=; b=kjn2PFdN79rL7k3EUpRbFuY/3O1Z4vbrh319BlDPIdtt2gIkvyz29GOwx8zPHZQSiCENEVEFIiqxk03HMBvBjwu5bGa0BFGD9gyuLZ1LAA+ETbZ8eNjWouv4Pd93s1ufyD7Qx1jUiABuC6lqIWCt++hs3VuBdOMaJu5o33N124+86ET96RZAMTwbegkdXiMdtdNfq/hSb2rWe1IFSFRyfsJp7mQBKDzSscPzGggrBdoQh1URXJhmTv9OMcU81eMdmzdFLB0HrUG22rrMR/gd9Oo1bIT9dvjtxHCUIKX+ilN8mR+g9QNpzWi48NSAozX/ZdUz+WottsdWoLA4M4/XFQ== 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=P5jpZvOC5Zs0Z0VVok8gtcf2FYhopnptqFIbDiMXv7g=; b=jIyzU0kBwyOWQNXdhrwbTossc/qz09bhvKrAGK8D1eThJB+FkcN16cpNYK7PStwVwaK4GTiVlae77r5oO0BP/2Gmr1d0rg7OEcARViZMkL2T2c3xS21WWFs4NPPO3w0QZDmjefQjsS22067RMbHTv8+HeDjZO2FenbuYxSMV0Gte/I+093LcGSm41kmOkwxSyp3axPLejoF29vvU+r5dM0/YDsIzZFQnCtgGQLrGciv59l9suCe08VE1GQJeW/DQzS5wfB3yxOEJMEE4G1DfT5Y6lpwwTdzaY1rTZoI7AuB7nbxP2Anpvm4pLEZ2aty/sVt+GtuA3HaFXKSI8/0qyQ== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=verity.net; Received: from GV0P278MB0784.CHEP278.PROD.OUTLOOK.COM (2603:10a6:710:53::9) by ZRAP278MB0771.CHEP278.PROD.OUTLOOK.COM (2603:10a6:910:4b::11) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6792.23; Mon, 18 Sep 2023 14:33:57 +0000 Received: from GV0P278MB0784.CHEP278.PROD.OUTLOOK.COM ([fe80::a5a5:a491:679b:42e]) by GV0P278MB0784.CHEP278.PROD.OUTLOOK.COM ([fe80::a5a5:a491:679b:42e%6]) with mapi id 15.20.6792.026; Mon, 18 Sep 2023 14:33:57 +0000 From: Simon Falsig To: ptxdist@pengutronix.de Date: Mon, 18 Sep 2023 16:33:39 +0200 Message-Id: <20230918143339.4126-1-sfalsig@verity.net> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230913160546.71046-3-sfalsig@verity.net> References: <20230913160546.71046-3-sfalsig@verity.net> Content-Transfer-Encoding: 8bit Content-Type: text/plain X-ClientProxiedBy: ZR0P278CA0122.CHEP278.PROD.OUTLOOK.COM (2603:10a6:910:20::19) To GV0P278MB0784.CHEP278.PROD.OUTLOOK.COM (2603:10a6:710:53::9) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: GV0P278MB0784:EE_|ZRAP278MB0771:EE_ X-MS-Office365-Filtering-Correlation-Id: 249f498d-f90a-48c0-d893-08dbb8544a93 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: X976K0Ca8fp2Ty7SFNh/8p3cP04X9JG084grvcOHNQkveAkpAr8HRsgQo/5FB29xJvpnCI0vu8mHwyyiWFT+EQigSl7A5P1uNTNp965JmuC2G3I0hSjG+onHRiMerCxTEV8llM6avJOJ1RkeplyrFbHiTh3j601F8Ae16bBAsYw0a2MNq4efAo+AG8vTIblxXWMUUQJQvxjAgiyhozBGxJZTIC6z1yU9Bm6lyfh9GFfvATRn3zAsL8IYcONU/eR9iCVV+9FLjXmpF06FRBjnbvlzd7i/xIGUhIWD8wJx/KXGr4Q8E5dSMAr5+GxwNmLQyi0AE1R3fH+vpW2EDOiruGjpYCO+Dvl1xsMrLCT1+zM39ZqffeGhbKfHrraJwbsZpDlhTtbeksOA0C6LAoVI3IpN0cuPf6RRpWnE8KD94NGVcEF3lj0M8ajbd4CHV1kFG8/goKEj/olgvXuDEUk5s/EuXxZx4eDf4vZsmjQ18x6db/XkQHi45TJ6Id+3cLybFnNdumA/85BwR6efyTXNCKnJSvBQ8VxaE4R5lziCon0RdGanaRDYLqniE/bk1+osk6rHekdNoiAKXwI+O/lUJP/GiPDj7BlGdQwRl8p7aPI= X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:GV0P278MB0784.CHEP278.PROD.OUTLOOK.COM; PTR:; CAT:NONE; SFS:(13230031)(376002)(396003)(136003)(39840400004)(346002)(366004)(186009)(1800799009)(451199024)(38350700002)(2906002)(83380400001)(38100700002)(6666004)(52116002)(478600001)(6506007)(6512007)(6486002)(966005)(5660300002)(6916009)(107886003)(316002)(4326008)(8936002)(8676002)(66946007)(66556008)(66476007)(41300700001)(1076003)(2616005)(26005)(36756003)(86362001); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?llTdz/gqDll/0sBfftzCgLZnIbTeqjcKPjxKcwJN8l4VK+eCzBmsDVaGBB+o?= =?us-ascii?Q?U4VCGBUOkfTVQScgCVydFIPz5PQ5S3Cout/+zgHA2IUscl4XmKrqYTY1huxe?= =?us-ascii?Q?k3gyqsL8fIJuo8rqmZrg+d/a8p2jZy6YxQBMakwqnc43W76tJ+fruOOCPpmS?= =?us-ascii?Q?+XhdNp3Xpi7YnSQe6wO8IVD1sRIY3D42KMtnsEUHGEDsqbYHMHumla1wjCtX?= =?us-ascii?Q?viWZgCMYqcOUr/WzA2vkJNlJ/A38alwIhrsRHMRdMDm55qd+1KKg5TP6T+3x?= =?us-ascii?Q?20OSK/jAVEF5OfUzdcLzJWMcg3dy8a94hiV8PDA2S8ntwHY5buGIBfhMAQ6g?= =?us-ascii?Q?tu+ISSd7QifT5sdsdr3zMcDItSSXX0ypm91AU4kOH1JBljkAu4xOYnmr7Nlw?= =?us-ascii?Q?Op1mgYHnHajvyHmQF6FOEgvjB2TUkK+ZMEqdtJAHSuPjQBUpu89UwFoO49IN?= =?us-ascii?Q?cK86SPefQuoGbRDemi/BkI1LYlt9cB7CNqqN6UmcYze62B7d96bJjtvtdMao?= =?us-ascii?Q?hp9vbhrUFlRaqyVRBeYU3qZbZCOqaNPWulgW26r4Cz8oyGvOfpZictgO46ZB?= =?us-ascii?Q?78ND3rTLndqi2zEfswsoDGnxxZiIT0afP0438vuwKMI2xDsIRcvL5zopOXIO?= =?us-ascii?Q?N64SMJj8UVXw1MbqwNlZzk49rPRU6z6bb+/zYY455/Ztb3eYwVGawVjdX4d1?= =?us-ascii?Q?cOiMLObWPTTvoJfuYuXjyWFqvNYtN1MSb9KKL1nmBy/2AlaiXEuzy06tM2we?= =?us-ascii?Q?PgiAKKRprI/WZe/IDz+1N/VaEheiLJEW/YX++cZ1jVMelN31mGDj2yYtYrC7?= =?us-ascii?Q?TOOSJfthRCfHn69o6dH0dmDCP6smQiwPgl1w0DRM4hnuX3ch+xSN15AVUsu5?= =?us-ascii?Q?60Vq02vs1Q+aMllVipjsZdUGG8igsp9V24Z97IDk2Uby+BQHjEsG6J6fA2g2?= =?us-ascii?Q?lgPg7aMbT5uSlD1FNPJoA3wmnxMzmGBuVlw7YdeQiNhgT6M2B58+hIsX11oP?= =?us-ascii?Q?NE5iXo3XbeBd6a4GvwduMSRxz0pb2VFoFnTY8V5UT127du+9JIXjWI4yQoz0?= =?us-ascii?Q?D65HiPR4gblPS5jkb3sgwDcR6ksqa5GPJyDDCV4IH0qgRGAHt9xEQOH18Z8w?= =?us-ascii?Q?E5SsHgsDNHikhpvyzkGseQgKiIbH8126bXNMxBhORBDiaL+NeCmPvZ91HJrf?= =?us-ascii?Q?tHiESIRVnUFcbG5nl/rCyRgIM6/zVlQWU76U0DmE79EXfivyPOrMp6rCQfuU?= =?us-ascii?Q?Ow0AcfT3LydNqqJpPkR0nBdfN5n6NP91jvD2sNoTl76Y4H7tr4nVwzaihNAM?= =?us-ascii?Q?swyyQ4RbgqiENkHoNVKuxYWLuoIMaAYKhBI1m6aW6rdzzbFUKvk5LnVc+DBP?= =?us-ascii?Q?288ZpuCTADN6DE5IhkBvmTzp1fYvPyROGJM5+DgGigHQif1UT7lPVCw23Wv+?= =?us-ascii?Q?RClOmjii05wU+BwPZrW+coTEyQhQ8xjMV3tlL897NlcscwO2WU8lYT5cGhri?= =?us-ascii?Q?1vDWEhjMzw5t/Ix2ZOemMLg1NJNa5HJlnqHaFP8E5E5RqVBRICZNOryVUch3?= =?us-ascii?Q?F1LJGbCQ7Vs0Yn1WFyTVQ5zAvqJ5NSOTzbi1mc5I?= X-OriginatorOrg: verity.net X-MS-Exchange-CrossTenant-Network-Message-Id: 249f498d-f90a-48c0-d893-08dbb8544a93 X-MS-Exchange-CrossTenant-AuthSource: GV0P278MB0784.CHEP278.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 18 Sep 2023 14:33:57.2848 (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: evUQppLMYOzi4rcHUXjOqdHopt/DfZ/i5FcpbuiCIIwTYmUz3MzmVyun7tbL3d68ORFxetPYsgqHpBfSFJZ7cA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: ZRAP278MB0771 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.0 required=4.0 tests=AWL,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 autolearn=ham autolearn_force=no version=3.4.2 Subject: [ptxdist] [PATCH] 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 From: Simon Falsig 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-bom package installed. --- bin/ptxdist | 3 +- rules/post/ptxd_make_report.make | 15 ++++++-- scripts/lib/ptxd_make_report.sh | 16 +++++++++ scripts/lib/ptxd_make_sbom_report.py | 54 ++++++++++++++++++++++++++++ 4 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 scripts/lib/ptxd_make_sbom_report.py diff --git a/bin/ptxdist b/bin/ptxdist index dfb619cbd..15be851f5 100755 --- a/bin/ptxdist +++ b/bin/ptxdist @@ -780,6 +780,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 @@ -1807,7 +1808,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/post/ptxd_make_report.make b/rules/post/ptxd_make_report.make index eecd2a577..ffa398c95 100644 --- a/rules/post/ptxd_make_report.make +++ b/rules/post/ptxd_make_report.make @@ -10,7 +10,9 @@ 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)" + PHONY += full-bsp-report full-bsp-report: $(RELEASEDIR)/full-bsp-report.yaml @@ -26,13 +28,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: $(addprefix $(STATEDIR)/,$(addsuffix .fast-report,$(PACKAGES))) + @$(call targetinfo) + @$(call ptx/report-env, $@) ptxd_make_sbom_report + @$(call finish) + # vim: syntax=make diff --git a/scripts/lib/ptxd_make_report.sh b/scripts/lib/ptxd_make_report.sh index a363ca5b3..e2da4c05f 100644 --- a/scripts/lib/ptxd_make_report.sh +++ b/scripts/lib/ptxd_make_report.sh @@ -144,3 +144,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}")" && + 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..cc6a6f703 --- /dev/null +++ b/scripts/lib/ptxd_make_sbom_report.py @@ -0,0 +1,54 @@ +from cyclonedx.factory.license import LicenseFactory +from cyclonedx.factory.license import LicenseChoiceFactory +from cyclonedx.model.bom import Bom +from cyclonedx.model.component import Component +from cyclonedx.output.json import JsonV1Dot4 +import sys +import re + +lFac = LicenseFactory() +lcFac = LicenseChoiceFactory(license_factory=lFac) +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=[lcFac.make_with_license(licenses_)], + bom_ref=name_ + "@" + version_ + ) + bom.components.add(comp) + +serializedJSON = JsonV1Dot4(bom).output_as_string() +print(serializedJSON) -- 2.25.1