From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from shymkent.ilbers.de ([unix socket]) by shymkent (Cyrus 2.5.10-Debian-2.5.10-3+deb9u2) with LMTPA; Tue, 04 Mar 2025 12:55:08 +0100 X-Sieve: CMU Sieve 2.4 Received: from mail-pj1-f63.google.com (mail-pj1-f63.google.com [209.85.216.63]) by shymkent.ilbers.de (8.15.2/8.15.2/Debian-8+deb9u1) with ESMTPS id 524Bt6ve009662 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 4 Mar 2025 12:55:07 +0100 Received: by mail-pj1-f63.google.com with SMTP id 98e67ed59e1d1-2fe8c697ec3sf11040786a91.1 for ; Tue, 04 Mar 2025 03:55:07 -0800 (PST) ARC-Seal: i=3; a=rsa-sha256; t=1741089300; cv=pass; d=google.com; s=arc-20240605; b=VeGDcfYPw6CD0PWskrDRLUf7u4a6XJj6vmgSv8lOEe6C9KdayzJXY0sWvQnbDwc5iX XwzURB1pt/YvDN+a0S7XD+mQJ/vaJC5yybRXOdnWHGlawzCkk2Vx5oGgOP0+7Ad0UFAJ 4y8G7WWsjbHw9nQnZ7lJBVSD3cy4hbkouef0fZgM/xP4F8hCl7joBSRjJlQfZe5uCn/u XK7x4NM4wZDqEO8zJdC4lXVIzK4Y8LfXsaJ/qaoRd9yKTtoa6or0LVBzEfQh8LWuNr9i 6wTsMnllwDehgW48eSgUggOyCkzV1AfUnrU9jmElkwooW3Q/eU5mMIL/AxG63W/Jm0dR q04Q== ARC-Message-Signature: i=3; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:reply-to:mime-version:content-id :content-language:accept-language:in-reply-to:references:message-id :date:thread-index:thread-topic:subject:cc:to:from:dkim-signature; bh=hePLQHXxXxhxCQQv87kJy9VsRb2JHILHtbODtaCuYWw=; fh=+ckOEE0mUjskFY9rBSsS5E9ZItSWgK43H+eN9anxPOQ=; b=ZYJA43x2WYIehBOHDs8TnrlvXmwH+yXuAeAOC5vmxGTiyYoPNdTeXIsybGMw6NleRA /gZWLs/gg7WQFDul7qfdmCS5QiLr8FXS46IEqYudjju4+KhNLKNb4CKmmAQlhIELWP5Z EnMj1mh2HXSkeZg8v85shiGBwrcSwa8JVvVpGzsUpkQSJWx65uxdajTxuiKX2hkJINmY YEIvgI2vgpdq64dg8e2He0LxHYlUtv5Q4toqGLOOdACfxWT9ECza4EZVeGd3CsXehVa1 4Yuzw49ET1iGlU0DIqCCjwHVJejoXd2SK40uNILTHyoOIaMWmUBfyGHGn4ICaq+cJJqP kybA==; darn=ilbers.de ARC-Authentication-Results: i=3; gmr-mx.google.com; dkim=pass header.i=@siemens.com header.s=selector2 header.b=MRSlQ5qk; arc=pass (i=1 spf=pass spfdomain=siemens.com dkim=pass dkdomain=siemens.com dmarc=pass fromdomain=siemens.com); spf=pass (google.com: domain of benedikt.niedermayr@siemens.com designates 2a01:111:f403:2612::61d as permitted sender) smtp.mailfrom=benedikt.niedermayr@siemens.com; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=siemens.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20230601; t=1741089300; x=1741694100; darn=ilbers.de; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:reply-to :x-original-authentication-results:x-original-sender:mime-version :content-id:content-language:accept-language:in-reply-to:references :message-id:date:thread-index:thread-topic:subject:cc:to:from:from :to:cc:subject:date:message-id:reply-to; bh=hePLQHXxXxhxCQQv87kJy9VsRb2JHILHtbODtaCuYWw=; b=KEUHigM7lonEO+GasRZAXRDo9XaKz4f1D6tX1Aa5Qq0wIdGflf+pVmm11sV95vxm03 5Uog+yN8Uafl6gVbfp0RD4pXnzQp4pUmPMbp57rmP/KVPaIBkNrEOkpotpPd27mnIj+x liXJZ8/rQHkaaXSpa0RlNVjxdCFxhZu7ICysKisIdVsy8fGP8icu1DfyLbC4DkQDoEfg Os6QJGx0WfTY4o3QYx7Nm0YdZBlf+2uxUia7GzZUn+KPzpm3Ec3CX4VlBVVP7whvcPBE 2fFewnMYbo8CdN3fOX4iqevVPKk8t9o1S7WgI7N23AjnhzX8CarlSs0/kJbLXnuzx87g 1d3w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741089300; x=1741694100; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :x-spam-checked-in-group:list-id:mailing-list:precedence:reply-to :x-original-authentication-results:x-original-sender:mime-version :content-id:content-language:accept-language:in-reply-to:references :message-id:date:thread-index:thread-topic:subject:cc:to:from :x-beenthere:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=hePLQHXxXxhxCQQv87kJy9VsRb2JHILHtbODtaCuYWw=; b=QOwAPhmeJITCqMIyQEnTJtnyU/b/VnhnQH5b5RTmzxDGd2nml8Ai+5hEHlyMLam8Y2 A68DS24D39V4xtqHw39t4MITF48dsTtGlg+sHhi5Hqgto7G/ogb1dq9myuWGezBySSYF +m990rdIszy9h6OM5ixcILHE+eEytiGGUBxSQRmqR124VJswuheIiWgZXAOfLmUuI6GK tCb5o5YZPg377LC1NrRlxh0vuh4ib+EyaQa2ajADuESsdG0+XHLfbjxdOfHeMjHTgdHs x1EYNIwHJMbLDqzbOsMjkxqo3ibSnLb7UjwwaA9INWiqb6C6JSbKhpjDmWWbRnp7z+yS z8PQ== X-Forwarded-Encrypted: i=3; AJvYcCXqMsQAPAiNUlz77rylYBPP1LMsG2fY68jrE7PXxi8QHjEnJUzProG57OoKhTJ1HbPvddUE@ilbers.de X-Gm-Message-State: AOJu0YwdNAtoSfulpbEdyzJ1DWzbe/Moi9GwmxeXAkzkbg48ShCMJN8i Qr3n2butZuJ2vclsjfz79iI8VLtLdS8/9q6KLCI+O2hnkjZIECK2 X-Google-Smtp-Source: AGHT+IHw7bGEQiJ+cCI/Fi6pvBKS7lrJbKpbg7AIig07cwGB+EoAupBaQ8e6yXEoTVeR3gjKBWVdeA== X-Received: by 2002:a05:6a21:e598:b0:1f3:20be:c18a with SMTP id adf61e73a8af0-1f339163ff3mr4401733637.10.1741089300294; Tue, 04 Mar 2025 03:55:00 -0800 (PST) X-BeenThere: isar-users@googlegroups.com; h=Adn5yVGZ97TTcpIiM3wFTCWV4mNyzZjt3kJKAdmBiG7m0j2TcQ== Received: by 2002:a05:6a00:391f:b0:725:4630:50bd with SMTP id d2e1a72fcca58-7349ca14860ls5303737b3a.0.-pod-prod-00-us; Tue, 04 Mar 2025 03:54:59 -0800 (PST) X-Forwarded-Encrypted: i=3; AJvYcCX/AEdFmsBKwAHr5BCo9KHkf7TNrrqXIR3S95aFj/Wst5sAzr1ZMhCCDHYZ7slT0sptpr7od7u2++wH@googlegroups.com X-Received: by 2002:a05:6a00:2d1e:b0:732:5875:eb95 with SMTP id d2e1a72fcca58-7366e5990c3mr4798142b3a.4.1741089298824; Tue, 04 Mar 2025 03:54:58 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1741089298; cv=pass; d=google.com; s=arc-20240605; b=af0JqNQaFNJ446k9ru0SHb3pR22AGdeDfeTouCJNPFZwgk2DeP28XLSpZpOIannzLd siwdySq/6nduyHwCbkQ0l8xuowW7vdOms5h5ziw1qY2xKk/tJihx0kull3CA7E3tWCLv HV9bIVD/8G5dxNTyzocf1Lqf3j/KNLwzvt6+3OHVP1dhaNmAzixVogEKC+LH4NsHkKtX 7NldceqsiwrwiJfxnv1kJnaCVznjDbiLRul5IDGntHMCfm2YTp55g5ewBNY2k5RX3+Fs dCg15fGiYl3ocbrro2eeSp1vajFm7zBVoaagXCSch1ZAijiU/fn4tG6C1FkovcuO30wa td3Q== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=mime-version:content-transfer-encoding:content-id:content-language :accept-language:in-reply-to:references:message-id:date:thread-index :thread-topic:subject:cc:to:from:dkim-signature; bh=JhPBXIrUTRQaR+Zk5Q/PrrJL2bjuWtEB1ep4e59/lDk=; fh=aw/WYHw7/EWG7V9Osp+Rdueod4QrzvKx9coB1vkQdmc=; b=OJYIk/gONypOSdt9Epfmf/+sg7lYN2d1+KGPXRcBUcYN861TEcWH7zCtp5XrQSnf2q VvLyQua+YMsVugx5W/3jTmA+nL92PyODn5QtXk1wwuCnxmMXsIomvpM7AJkGzaGuKYfr p/HBnqT5+jNLnGghOAzDJfk468+TCn8hV3ijhvxt2I0NZH83yx5rVAwlMxYrJVS8t+9s oShnHml/Rspa+NO7iQIEEDFo9/FQcaP4oQv9+37YtZORrgespHWB4+RqbYxDIJ4hnclu ARh7j+Y3gKGvoc47vinzENdp3hh5euNqx5CgTgAcyqKCy6bk2EWA0uusKoO4zwSEeF8n Zk1A==; dara=google.com ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@siemens.com header.s=selector2 header.b=MRSlQ5qk; arc=pass (i=1 spf=pass spfdomain=siemens.com dkim=pass dkdomain=siemens.com dmarc=pass fromdomain=siemens.com); spf=pass (google.com: domain of benedikt.niedermayr@siemens.com designates 2a01:111:f403:2612::61d as permitted sender) smtp.mailfrom=benedikt.niedermayr@siemens.com; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=siemens.com Received: from EUR05-AM6-obe.outbound.protection.outlook.com (mail-am6eur05on2061d.outbound.protection.outlook.com. [2a01:111:f403:2612::61d]) by gmr-mx.google.com with ESMTPS id d2e1a72fcca58-7349fd0c529si515605b3a.0.2025.03.04.03.54.58 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 04 Mar 2025 03:54:58 -0800 (PST) Received-SPF: pass (google.com: domain of benedikt.niedermayr@siemens.com designates 2a01:111:f403:2612::61d as permitted sender) client-ip=2a01:111:f403:2612::61d; ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=tqwBEBvJJRYZpP9ZFh8Ky/JfdgJRtEBuJ+ehKbYnP0I64qb3iVP+ya9CC/ZQ+cgXc05poMvSCV2z/NTd+N3QYQXFv3LvdfNz2ZIRZiqtt/zvgGCidvDnbbgW6in9DxfGQRnzeigF63Xs8BLXtnXaH+NxCaVpDbr3Bfvehbs5TDTO9qGuyNavjO9RnZdKjCiDsXnFe44sKw5vjizxyjmz4djhbyjFC5YCh428XKaEQEIRZ/PA8WRCmcb9+2f4xLYwAjK7bij0v5yolrRXIP912TTo4N+o3H1hQQZ1xXeIqiPAjJlvaT5LePB1fqcz3GRYHetwc9HK4LV1HEIWvHEusw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; 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=JhPBXIrUTRQaR+Zk5Q/PrrJL2bjuWtEB1ep4e59/lDk=; b=SJ0KTlCDIUl8ZzXQT2ZQ42blQTv2RZ21rPxxE7ombWR8livrPOAWXBIr4pi1E0WGwolglu5oGALPTNBBRyAF73tvrmdRanmyO5qKhNTJ2o/O9c/bwevoWZMFYIj9yBq8V7seKzSJaPp+QrAqHuX4mq6sqzaYpbfNxYe+Ih5bUtnz3YukszKgBZB+s99wPZpUlAQ8izj99QdHhK66kB+oiktjtaExJYqNrV5FdcEWSChBNj4+c0XD+vbjspmMDxMpKH/AMlXb758WLk4X625MDywwwKAl4SG4DqqCXtwadg0kwQQiw/3bgme6Ezjf89NNSbpXiyXDgHWP7540SJPoyg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=siemens.com; dmarc=pass action=none header.from=siemens.com; dkim=pass header.d=siemens.com; arc=none Received: from PAXPR10MB5520.EURPRD10.PROD.OUTLOOK.COM (2603:10a6:102:23e::20) by AS2PR10MB7347.EURPRD10.PROD.OUTLOOK.COM (2603:10a6:20b:605::21) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.8511.16; Tue, 4 Mar 2025 11:54:54 +0000 Received: from PAXPR10MB5520.EURPRD10.PROD.OUTLOOK.COM ([fe80::7615:5a22:34bf:f079]) by PAXPR10MB5520.EURPRD10.PROD.OUTLOOK.COM ([fe80::7615:5a22:34bf:f079%6]) with mapi id 15.20.8489.025; Tue, 4 Mar 2025 11:54:54 +0000 From: "'Niedermayr, BENEDIKT' via isar-users" To: "MOESSBAUER, Felix" , "isar-users@googlegroups.com" CC: "Kiszka, Jan" , "Hillier, Gernot" , "Steiger, Christoph" Subject: Re: [RFC PATCH 1/1] meta: add CycloneDX/SPDX SBOM generation Thread-Topic: [RFC PATCH 1/1] meta: add CycloneDX/SPDX SBOM generation Thread-Index: AQHbg351PjenQv24QkmfIBrIajBUfrNi8X6A Date: Tue, 4 Mar 2025 11:54:53 +0000 Message-ID: References: <20250220095944.114203-1-felix.moessbauer@siemens.com> <20250220095944.114203-2-felix.moessbauer@siemens.com> In-Reply-To: <20250220095944.114203-2-felix.moessbauer@siemens.com> Accept-Language: de-DE, en-US Content-Language: de-DE X-MS-Has-Attach: X-MS-TNEF-Correlator: x-ms-publictraffictype: Email x-ms-traffictypediagnostic: PAXPR10MB5520:EE_|AS2PR10MB7347:EE_ x-ms-office365-filtering-correlation-id: 9dc7b5b9-b564-475f-a76e-08dd5b136094 x-ms-exchange-atpmessageproperties: SA x-ms-exchange-senderadcheck: 1 x-ms-exchange-antispam-relay: 0 x-microsoft-antispam: BCL:0;ARA:13230040|366016|1800799024|376014|38070700018; x-microsoft-antispam-message-info: =?utf-8?B?NmRXYUZhbFFmUGJoTTlmdCsxZXUwbjlCcVFaNFlnVkp6aDREL2VmSnNPSngw?= =?utf-8?B?UHEvUkMyM1ZFUlRERXY4cGdsYWpLV21RYUJWdDJHdXNlWGFBUHoyZjJ0WVNH?= =?utf-8?B?cmFrL2tGVjNQa093Q2xPbnlyVk9mam5TV0tJaXZKUTVLbWhWNFFnYlBINXdW?= =?utf-8?B?cHJXczhHRy8xTTJsWlBIRGRQSFdBWjRGbzUzQkZFb3VHZjRSNUU4dU9XOXc1?= =?utf-8?B?R3M0aHlIRXVKNnhtNVBxM3RFSm9WT3BqSWVkRlIwYVZnM3d3ZnVqRER4WTMr?= =?utf-8?B?ekxELytVZ0FhelpyRWlEbzNvbXcwWElGam9pYUx3TXhUVkpZNnlhNkNLNnZx?= =?utf-8?B?QWlEUk5WTDdkYUdUUXM2emN3THp4VzA0VkQvZTFKQzlleEpJRFZTeEt3QytS?= =?utf-8?B?b0tuVWJSRk9mbnRpbytiY3hTS3d0L1VzdGoxS2VxWmxPUjNCSzBGbzlxQURk?= =?utf-8?B?bHo4SlZpM3k3b0F6U09qdFlIMS94YXcrZWx4d3duYUd2SVJCVGZQSzR0UllN?= =?utf-8?B?N3JZcmNsUHJhc1ROaVdNRzVOMkJ0bG9GbE8wYmJ0RjlTNHNzZlZZRFoxQ1o4?= =?utf-8?B?VGFJbGJTQUhBQkxCTzlad2VyRlJ3TVc4cWdaczBwc3lpZDRTNHpkZ0xjSC8y?= =?utf-8?B?MXdBUml0T0NKbGdkRHordTQ5ZDR0Y2VTN0owdUhUSXk4Q3gycENCVE9iMWtt?= =?utf-8?B?KytPVGhQdGtNaU1rc1ZsUlVNU2pjY1krTXQ2cUN5SE5xbFNGbk51cmRpT3JL?= =?utf-8?B?OFdOcVJES3E0TVhBZjV0THhCV2pLT0NVLzVhVlZhUCtUUHBhMGVPRFZuWFVD?= =?utf-8?B?azV5U21MN2hhOGpwRFhra3RxVDlUWFYxWW5OdGlNdTdZS013dStCK2Z5UTdF?= =?utf-8?B?QnRaTzR1UDE4Vk5BQ2NlZWFmNnI2d2svbkt1OVBuZnFnWC9aNTRERy9IVnA1?= =?utf-8?B?bEMzWFRCL0t0MEVLb29GS09hTEZVTFVBdzV2SjNJU3FpSHZKOFp5dlBsbHJC?= =?utf-8?B?U21VMDY2eXROZGtLSDA0N3FhOHQ0dUEyWGorUjdBNnNlNnQwN2xkTk9LRzhh?= =?utf-8?B?aWdqb1drRDU1Nm9nUWY4UThpMUtMeVl4Q3ZWRHdTWFU5WTJkam1CM0xIMDdX?= =?utf-8?B?Q01DOEJqdmVZcTBjUGJoVWhIUDFFMWNlOGhqaGFnalVPbmhBeVhJb3djMGlW?= =?utf-8?B?NzkrZ2ZTZFRnOVROQ1k0ODRBUzV1b1lBSlk5U0VHMHhDamdDQ3NDMVdSR0hs?= =?utf-8?B?YXhZbHF1T3pJM1VPRDBZRVVGU2E2UXdzSWkxeGRNUkRsTEM1YXlKQzBqamtL?= =?utf-8?B?NHEraW92V0JjbmJCcktLcDVGZUFtekcxb2VJYy84SnF2N3lYM3A5elQ3a1Jk?= =?utf-8?B?a3p0YkJlNDB0aDh3YWRTbThyZnRuM1ZOR2lETzJJZnpyREZBTVJ0eWp6Uks3?= =?utf-8?B?RkltZVVmYVZPay91cEVBYlNXNFVMNVFRN2d3cFUzdHZ1WjIwa0pMZnJJaloz?= =?utf-8?B?YzN2VTJqcnlncnJwNmhuMFV6ZGFLWkF5KzBvNExPVll1WlZSYXJpTWVpREFp?= =?utf-8?B?aDhhZEcvSWhiVVNjSXZtMHdXOWNyUGFqWXM2d2lSNlFGdHowMndOb0lnS2ts?= =?utf-8?B?RUh2OVZrR2tUdmZNRlZOOG5nYlNYZDdxbkcyOXo3ekdUN2tUTUR2TkIyK3dZ?= =?utf-8?B?cytYTmsyV0xENmEzK3lRdEVlajdqZHpmRVJNSE5ieGsyQ0tDa2ZwMk9BVTBX?= =?utf-8?B?bFM0TnRGbDVRYTRGYTQ0dlB5Kzg1Q3kxMzdsS0NuQnhnV3U1cUYrWjZaUm50?= =?utf-8?B?MHZUOW90NFdyMUZDTDJRUnd5bnNLb3I2L1JMOGFvanpOMzdFbmgrUEJjSG0w?= =?utf-8?Q?OTOwc2mBoJq/g?= x-forefront-antispam-report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:PAXPR10MB5520.EURPRD10.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(366016)(1800799024)(376014)(38070700018);DIR:OUT;SFP:1101; x-ms-exchange-antispam-messagedata-chunkcount: 1 x-ms-exchange-antispam-messagedata-0: =?utf-8?B?YUJVN3R6bVJhNDhiK044WTF2dnNwOSt2S2xPdjBmRXYwekdDT1VVdnJXRTNq?= =?utf-8?B?QUVDancwUWx5bzJGM2J1bURlRUpnb1c1Wm14ejRMNWJzMmpEVlc0NW5MaHZZ?= =?utf-8?B?SGZsb3RBRThIS1pqRTFoR0VaQTVDUEtJaVFYbXpWVzlwTEtGZVJkQTY5SFBF?= =?utf-8?B?SVVxZGFpUjN0MTJibGkxNDBlYTVsNVZHVFR2djY5dDNtVS9aVkZiaU5hQ1c5?= =?utf-8?B?cFl0RHVpcWoreXFuZ1hoWThKU0MzaHkzdU5xU1M2L0tuTnp0blB3SnBIVFRo?= =?utf-8?B?L2tMUERMR2NaNUNJTERWcy8wVEVBaVNGQWQxQ2h0UkFuc1hNNEZ4bDE1d2FN?= =?utf-8?B?eUhMTTNsZGZTTmxsdGwvQ0laMU1PbzFFZ1NBc1RCaUplUlFrZDBUUXMzN0RZ?= =?utf-8?B?TmxpbWZtTmNYcnZoTCtQbXhFNHlkQmNCc01CSUl5NHpCMUVLYXI1ZTkwUWpF?= =?utf-8?B?enFtalRwQmZ5Wm5UYitvRUQwT3dTcTkyT2tRRC9ESUpnTzZRcEk3Y2Vkb3RI?= =?utf-8?B?dHB2Rk5TeU9hSGE2TXJBbDFxZ1ZuR0F1K3UwM3luN3dROWsvN0V1UFFSUmZK?= =?utf-8?B?Sml0RUdESTl4ZEhQR2xWSk0xMWRqajZQY1VVa3BIV3hraFhWVG1zUnhRUlFS?= =?utf-8?B?UEF4TVdTUWN6RGxMa1d2Zm1vUEdxUmJRSjkxK2hFNWpCbUM3QURPTXZiamRm?= =?utf-8?B?ekpYeXdBTnBobGNwcnNVYmEwQ21OOWFDMmFSd2xkVHBCS2dYbDRlV01ET3dj?= =?utf-8?B?V2Ntd3NZVUtjU2ludXNqb1dLMUQ4ay9uV1VtQ08yM1FBS05aRGwwYm1vY2ps?= =?utf-8?B?cGFoRE90cThhV0oyWFVTaUdxclhXNG5WT05LU2hKdUc2TkUvRHIveVVRZlFQ?= =?utf-8?B?aXZKOXh2akhJemEzU1J5VWgxcEpJL2w1aytVTHpnRnZDUFVNWXpSYjNYUEtP?= =?utf-8?B?VFZHdk4rdmVoQVdSbE02em4rVytqemNpQ3ErNi9MM2dpWTZHWjRSZ053ODY2?= =?utf-8?B?ZEQwd0liVmxIWG1VWXBzRU1OQllTRldnUVpOQW13VElUNGZSZ3JFQnFUNUIr?= =?utf-8?B?MEZXVTdkSTFuNGJ4ajVGb0EzT3EzelRUNlhxZ2lrT0NaTU04RlVGVVBId0Zl?= =?utf-8?B?U2dJdVRoc0h4N2JRcEY2QTdFNUxiSFM0cmZ2ang5MGJoR3dzc0N2aHVUTk1D?= =?utf-8?B?VXJvcHZPQ1RtS3RiMUNMazRsaXF0QVlNOG1PMGorTG5DM0RuNVQzR3ptTFBJ?= =?utf-8?B?WHRWaFdyd2ZObHMxY2tncHIvdW44SnpXZzFyQjhJa0tVWFNyRjZWbG5OQ2R5?= =?utf-8?B?VDNWU1NvV0RJRkpGd0x1WFBoM2VsZWU3dGR2WnU2MzZQK1RuNXRLRUl5UXNl?= =?utf-8?B?OGZMMVFEbjZKd2QwU2pUTG43SzRMMExHaDdJSU1WRzE0S2szRUp0NjVsaDRC?= =?utf-8?B?SThOZ1RIRTkrR3lVVmd2S1FCWXMzc0I0WGVGVnU1T3hOUmtvc0toSyttYmls?= =?utf-8?B?Y1lOaG5RS3V0eWluK3RJc2JBMWVUb1hxV1kvb2IxNlBScGNMYVVOeTFDSkVm?= =?utf-8?B?Y29oN0RkL3k3NWxkZWVqUTMzbWN6TVdWUnllTk9IS3hLMkZPNU1ObVYwQmVX?= =?utf-8?B?aFZoang3amRBMFF4YVU4TEs0RFdweVlRUWlUQlFXYjBtTDhvbEJqb1hOZm5l?= =?utf-8?B?bzZEdjVvU1BFZG45QzBiekdIQ1MzMGV3dVhHVXVSM2ZmZmttS0YyVkFxTUZS?= =?utf-8?B?YXdTWGZBQzhqQTVubktYeFVNU1Q5Q3A3UWhicGVoK2FZZWRENG1sRVJmMEZ5?= =?utf-8?B?ZkRsSlVhcWNOUTRTckczVHZlblVQYlhHSi9Cc3JFdHowK2Q1elhja3o5bGh1?= =?utf-8?B?N00vQkxpK01UUG1YOGxqc3hwRUpDaWdybWd4Q1NkRGJ4RnpleHFCbzF2R201?= =?utf-8?B?ZzFRekVHOU9sTGllbE5iSmhrRzN4aFBoU2VkOXpvaHJsNlpHd1NOSlJmNjVh?= =?utf-8?B?YkYwWis1THdiYVNvaDlvU29wYzVnMnNleHNDbjlNdjRiR0VBYXR5cGdzYUZ1?= =?utf-8?B?SFN0RldXeUxCaktheitBODkxSzhYazNWelNsaDdqUjVZbS9xYzhjZmpUTjlI?= =?utf-8?B?cWp2Uk5kU1JiTVdnZDg1T3h0Q2FWZjhSQSswV3BnZmxicjNXSmIyNUlRU1Ft?= =?utf-8?B?Q1E9PQ==?= Content-Type: text/plain; charset="UTF-8" Content-ID: <1C4E736694602A468548ADDCA2EC58B0@EURPRD10.PROD.OUTLOOK.COM> MIME-Version: 1.0 X-OriginatorOrg: siemens.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-AuthSource: PAXPR10MB5520.EURPRD10.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-Network-Message-Id: 9dc7b5b9-b564-475f-a76e-08dd5b136094 X-MS-Exchange-CrossTenant-originalarrivaltime: 04 Mar 2025 11:54:53.9002 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 38ae3bcd-9579-4fd4-adda-b42e1495d55a X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: Vn3j7FSay9V5rckxN6XQIe3Ci95gMhdjreM5oIPd9rHLyRAYU75tZC5YJN6hfxYMk5T2ADVIRozmdxGVa9122likQfXNVNIV9khNf/5dDHQ= X-MS-Exchange-Transport-CrossTenantHeadersStamped: AS2PR10MB7347 X-Original-Sender: benedikt.niedermayr@siemens.com X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@siemens.com header.s=selector2 header.b=MRSlQ5qk; arc=pass (i=1 spf=pass spfdomain=siemens.com dkim=pass dkdomain=siemens.com dmarc=pass fromdomain=siemens.com); spf=pass (google.com: domain of benedikt.niedermayr@siemens.com designates 2a01:111:f403:2612::61d as permitted sender) smtp.mailfrom=benedikt.niedermayr@siemens.com; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=siemens.com X-Original-From: "Niedermayr, BENEDIKT" Reply-To: "Niedermayr, BENEDIKT" Precedence: list Mailing-list: list isar-users@googlegroups.com; contact isar-users+owners@googlegroups.com List-ID: X-Spam-Checked-In-Group: isar-users@googlegroups.com X-Google-Group-Id: 914930254986 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , X-Spam-Status: No, score=-3.0 required=5.0 tests=DKIMWL_WL_MED,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,MAILING_LIST_MULTI, RCVD_IN_DNSWL_BLOCKED,RCVD_IN_MSPIKE_H2,RCVD_IN_RP_CERTIFIED, RCVD_IN_RP_RNBL,RCVD_IN_RP_SAFE,SPF_PASS,URIBL_ABUSE_SURBL autolearn=unavailable autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on shymkent.ilbers.de X-TUID: 8v+GsRt15o8M On 20.02.25 10:59, 'Felix Moessbauer' via isar-users wrote: > From: Christoph Steiger > > Add a new class to allow generation of software bill of materials > (SBOM). Supported are the two standard SBOM formats CycloneDX and SPDX. > SBOM generation is enabled per default for all images. > > Both formats support the minimal usecase of binary packages information > and their dependencies. Unfortunately there is no proper way to express > the relationships of debian source packages and their corresponding > binary packages in the CDX format, so it is left out there. > > The information included in the SBOM is parsed from the dpkg status > file found in the created image. AFAIK you're using the cyclonedx-python-lib [1], right? This package is not packaged by debian, yet and the python package needs to be run in python-virtualenv. Do you have any plans to support this? [1] https://pypi.org/project/cyclonedx-python-lib/ > > Signed-off-by: Christoph Steiger > --- > meta/classes/create-sbom.bbclass | 49 ++++ > meta/classes/image.bbclass | 2 + > meta/lib/sbom.py | 446 +++++++++++++++++++++++++++++++ > meta/lib/sbom_cdx_types.py | 82 ++++++ > meta/lib/sbom_spdx_types.py | 95 +++++++ > 5 files changed, 674 insertions(+) > create mode 100644 meta/classes/create-sbom.bbclass > create mode 100644 meta/lib/sbom.py > create mode 100644 meta/lib/sbom_cdx_types.py > create mode 100644 meta/lib/sbom_spdx_types.py > > diff --git a/meta/classes/create-sbom.bbclass b/meta/classes/create-sbom.bbclass > new file mode 100644 > index 00000000..8c647699 > --- /dev/null > +++ b/meta/classes/create-sbom.bbclass > @@ -0,0 +1,49 @@ > +# This software is a part of ISAR. > +# Copyright (C) 2025 Siemens AG > +# > +# SPDX-License-Identifier: MIT > + > +# sbom type to generate, accepted are "cyclonedx" and "spdx" > +SBOM_TYPE ?= "cyclonedx spdx" > + > +# general user variables > +SBOM_DISTRO_SUPPLIER ?= "ISAR" > +SBOM_DISTRO_NAME ?= "ISAR-Debian-GNU-Linux" > +SBOM_DISTRO_VERSION ?= "1.0.0" > +SBOM_DISTRO_SUMMARY ?= "Linux distribution built with ISAR" > +SBOM_DOCUMENT_UUID ?= "" > + > +# SPDX specific user variables > +SBOM_SPDX_NAMESPACE_PREFIX ?= "https://spdx.org/spdxdocs" > + > +SBOM_DEPLOY_BASE = "${DEPLOY_DIR_IMAGE}/${IMAGE_FULLNAME}" > + > +SBOM_GEN_VERSION = "0.1.0" > + > +# adapted from the isar-cip-core image_uuid.bbclass > +def generate_document_uuid(d): > + import uuid > + > + base_hash = d.getVar("BB_TASKHASH") > + if base_hash is None: > + bb.warn("no BB_TASKHASH available, SBOM UUID is not reproducible") > + return uuid.uuid4() > + return str(uuid.UUID(base_hash[:32], version=4)) > + > +python do_create_sbom() { > + import sbom > + > + dpkg_status = d.getVar("IMAGE_ROOTFS") + "/var/lib/dpkg/status" > + packages = sbom.Package.parse_status_file(dpkg_status) > + > + if not d.getVar("SBOM_DOCUMENT_UUID"): > + d.setVar("SBOM_DOCUMENT_UUID", generate_document_uuid(d)) > + > + sbom_type = d.getVar("SBOM_TYPE") > + if "cyclonedx" in sbom_type: > + sbom.generate(d, packages, sbom.SBOMType.CycloneDX, d.getVar("SBOM_DEPLOY_BASE") + ".cyclonedx.json") > + if "spdx" in sbom_type: > + sbom.generate(d, packages, sbom.SBOMType.SPDX, d.getVar("SBOM_DEPLOY_BASE") + ".spdx.json") > +} Maybe a variable for enabling/disabling this feature would be nice. (IMAGE_FEATURES, DISTRO_FEATURES). > + > +addtask do_create_sbom after do_rootfs before do_build > diff --git a/meta/classes/image.bbclass b/meta/classes/image.bbclass > index 56eca202..e9da6a61 100644 > --- a/meta/classes/image.bbclass > +++ b/meta/classes/image.bbclass > @@ -81,6 +81,8 @@ inherit image-postproc-extension > inherit image-locales-extension > inherit image-account-extension > > +inherit create-sbom > + > # Extra space for rootfs in MB > ROOTFS_EXTRA ?= "64" > > diff --git a/meta/lib/sbom.py b/meta/lib/sbom.py > new file mode 100644 > index 00000000..d7c79e43 > --- /dev/null > +++ b/meta/lib/sbom.py > @@ -0,0 +1,446 @@ > +# This software is part of ISAR. > +# Copyright (C) 2025 Siemens AG > +# > +# SPDX-License-Identifier: MIT > + > +from dataclasses import dataclass > +from datetime import datetime > +from enum import Enum > +from typing import Dict, List, Type > +import json > +import re > +from uuid import uuid4 > + > +import sbom_cdx_types as cdx > +import sbom_spdx_types as spdx > + > + > +class SBOMType(Enum): > + CycloneDX = (0,) > + SPDX = (1,) > + > + > +@dataclass > +class SourcePackage: > + name: str > + version: str | None > + > + def purl(self): > + """Return the PURL of the package.""" > + return "pkg:deb/debian/{}@{}?arch=source".format(self.name, self.version) > + > + def bom_ref(self, sbom_type: SBOMType) -> str: > + """Return a unique BOM reference.""" > + if sbom_type == SBOMType.CycloneDX: > + return cdx.CDXREF_PREFIX + "{}-src".format(self.name) > + elif sbom_type == SBOMType.SPDX: > + return spdx.SPDX_REF_PREFIX + "{}-src".format(self.name) > + > + def parse(s: str) -> Type["SourcePackage"]: Using "@classmethod" for this factory method would be more idiomatic. > + split = s.split(" ") > + name = split[0] > + try: > + version = " ".join(split[1:]).strip("()") > + except IndexError: > + version = None > + > + return SourcePackage(name=name, version=version) > + > + > +@dataclass > +class Dependency: > + name: str > + version: str | None > + > + def bom_ref(self, sbom_type: SBOMType) -> str: > + """Return a unique BOM reference.""" > + if sbom_type == SBOMType.CycloneDX: > + return cdx.CDX_REF_PREFIX + "{}".format(self.name) > + elif sbom_type == SBOMType.SPDX: > + return spdx.SPDX_REF_PREFIX + "{}".format(self.name) > + > + def parse_multiple(s: str) -> List[Type["Dependency"]]: ... Using "@classmethod" for this factory method would be more idiomatic. > + """Parse a 'Depends' line in the dpkg status file.""" > + dependencies = [] > + for entry in s.split(","): > + entry = entry.strip() > + for entry in entry.split("|"): > + split = entry.split("(") > + name = split[0].strip() > + try: > + version = split[1].strip(")") > + except IndexError: > + version = None > + dependencies.append(Dependency(name=name, version=version)) > + > + return dependencies > + > + > +@dataclass > +class Package: > + """Incomplete representation of a debian package.""" > + > + name: str > + section: str > + maintainer: str > + architecture: str > + source: SourcePackage > + version: str > + depends: List[Dependency] > + description: str > + homepage: str > + > + def purl(self) -> str: > + """Return the PURL of the package.""" > + purl = "pkg:deb/debian/{}@{}".format(self.name, self.version) > + if self.architecture: > + purl = purl + "?arch={}".format(self.architecture) > + return purl > + > + def bom_ref(self, sbom_type: SBOMType) -> str: > + """Return a unique BOM reference.""" > + if sbom_type == SBOMType.CycloneDX: > + return cdx.CDX_REF_PREFIX + self.name > + elif sbom_type == SBOMType.SPDX: > + return spdx.SPDX_REF_PREFIX + self.name > + > + def parse_status_file(status_file: str) -> List[Type["Package"]]: ...Using "@classmethod" for this factory method would be more idiomatic. Regards, Benedikt > + """Parse a dpkg status file.""" > + packages = [] > + with open(status_file, "r") as f: > + name = None > + section = None > + maintainer = None > + architecture = None > + source = None > + version = None > + dependencies = None > + description = None > + homepage = None > + for line in f.readlines(): > + if line.strip(): > + if line[0] == " ": > + # this is a description line, we ignore it > + continue > + else: > + split = line.split(":") > + key = split[0] > + value = ":".join(split[1:]).strip() > + if key == "Package": > + name = value > + elif key == "Section": > + section = value > + elif key == "Maintainer": > + maintainer = value > + elif key == "Architecture": > + architecture = value > + elif key == "Source": > + source = SourcePackage.parse(value) > + elif key == "Version": > + version = value > + elif key == "Depends": > + dependencies = Dependency.parse_multiple(value) > + elif key == "Description": > + description = value > + elif key == "Homepage": > + homepage = value > + else: > + # fixup source version, if not specified it is the same > + # as the package version > + if source and not source.version: > + source.version = version > + # empty line means new package, so finish the current one > + packages.append( > + Package( > + name=name, > + section=section, > + maintainer=maintainer, > + architecture=architecture, > + source=source, > + version=version, > + depends=dependencies, > + description=description, > + homepage=homepage, > + ) > + ) > + name = None > + section = None > + maintainer = None > + architecture = None > + source = None > + version = None > + dependencies = None > + description = None > + homepage = None > + > + return packages > + > + > +def cyclonedx_bom(d, packages: List[Package]) -> Dict: > + """Return a valid CycloneDX SBOM.""" > + data = [] > + dependencies = [] > + > + pattern = re.compile("(?P^[^<]*)(\\<(?P.*)\\>)?") > + for package in packages: > + match = pattern.match(package.maintainer) > + supplier = cdx.CDXSupplier(name=match["supplier_name"]) > + supplier_email = match["supplier_email"] > + if supplier_email: > + supplier.contact = [cdx.CDXSupplierContact(email=supplier_email)] > + entry = cdx.CDXComponent( > + type=cdx.CDX_COMPONENT_TYPE_LIBRARY, > + bom_ref=package.bom_ref(SBOMType.CycloneDX), > + supplier=supplier, > + name=package.name, > + version=package.version, > + description=package.description, > + purl=package.purl(), > + ) > + if package.homepage: > + entry.externalReferences = ( > + cdx.CDXExternalReference( > + url=package.homepage, > + type=cdx.CDX_PACKAGE_EXTREF_TYPE_WEBSITE, > + comment="homepage", > + ), > + ) > + data.append(entry) > + > + distro_bom_ref = cdx.CDX_REF_PREFIX + d.getVar("SBOM_DISTRO_NAME") > + distro_dependencies = [] > + # after we have found all packages we can start to resolve dependencies > + package_names = [package.name for package in packages] > + for package in packages: > + distro_dependencies.append(package.bom_ref(SBOMType.CycloneDX)) > + if package.depends: > + deps = [] > + for dep in package.depends: > + dep_bom_ref = dep.bom_ref(SBOMType.CycloneDX) > + # it is possibe to specify the same package multiple times, but > + # in different versions > + if dep.name in package_names and dep_bom_ref not in deps: > + deps.append(dep_bom_ref) > + else: > + # this might happen if we have optional dependencies > + continue > + dependency = cdx.CDXDependency( > + ref=package.bom_ref(SBOMType.CycloneDX), > + dependsOn=deps, > + ) > + dependencies.append(dependency) > + dependency = cdx.CDXDependency( > + ref=distro_bom_ref, > + dependsOn=distro_dependencies, > + ) > + dependencies.append(dependency) > + > + doc_uuid = d.getVar("SBOM_DOCUMENT_UUID") > + distro_component = cdx.CDXComponent( > + type=cdx.CDX_COMPONENT_TYPE_OS, > + bom_ref=cdx.CDX_REF_PREFIX + d.getVar("SBOM_DISTRO_NAME"), > + supplier=cdx.CDXSupplier(name=d.getVar("SBOM_DISTRO_SUPPLIER")), > + name=d.getVar("SBOM_DISTRO_NAME"), > + version=d.getVar("SBOM_DISTRO_VERSION"), > + description=d.getVar("SBOM_DISTRO_SUMMARY"), > + ) > + > + timestamp = datetime.fromtimestamp(int(d.getVar("SOURCE_DATE_EPOCH"))) > + bom = cdx.CDXBOM( > + bomFormat=cdx.CDX_BOM_FORMAT, > + specVersion=cdx.CDX_SPEC_VERSION, > + serialNumber="urn:uuid:{}".format(doc_uuid if doc_uuid else uuid4()), > + version=1, > + metadata=cdx.CDXBOMMetadata( > + timestamp=timestamp.strftime("%Y-%m-%dT%H:%M:%SZ"), > + component=distro_component, > + tools=cdx.CDXBOMMetadataTool( > + components=[ > + cdx.CDXComponent( > + type=cdx.CDX_COMPONENT_TYPE_APPLICATION, > + name="ISAR SBOM Generator", > + version=d.getVar("SBOM_GEN_VERSION"), > + ) > + ], > + ), > + ), > + components=data, > + dependencies=dependencies, > + ) > + return bom > + > + > +def spdx_bom(d, packages: List[Package]) -> Dict: > + "Return a valid SPDX SBOM." > + > + data = [] > + # create a "fake" entry for the distribution > + distro_ref = spdx.SPDX_REF_PREFIX + d.getVar("SBOM_DISTRO_NAME") > + distro_package = spdx.SPDXPackage( > + SPDXID=distro_ref, > + name=d.getVar("SBOM_DISTRO_NAME"), > + versionInfo=d.getVar("SBOM_DISTRO_VERSION"), > + primaryPackagePurpose=spdx.SPDX_PACKAGE_PURPOSE_OS, > + supplier="Organization: {}".format(d.getVar("SBOM_DISTRO_SUPPLIER")), > + downloadLocation=spdx.SPDX_NOASSERTION, > + filesAnalyzed=False, > + licenseConcluded=spdx.SPDX_NOASSERTION, > + licenseDeclared=spdx.SPDX_NOASSERTION, > + copyrightText=spdx.SPDX_NOASSERTION, > + summary=d.getVar("SBOM_DISTRO_SUMMARY"), > + ) > + > + data.append(distro_package) > + > + pattern = re.compile("(?P^[^<]*)(\\<(?P.*)\\>)?") > + for package in packages: > + match = pattern.match(package.maintainer) > + supplier_name = match["supplier_name"] > + supplier_email = match["supplier_email"] > + if any([cue in supplier_name.lower() for cue in spdx.SPDX_SUPPLIER_ORG_CUE]): > + supplier = "Organization: {}".format(supplier_name) > + else: > + supplier = "Person: {}".format(supplier_name) > + if supplier_email: > + supplier += "({})".format(supplier_email) > + > + entry = spdx.SPDXPackage( > + SPDXID=package.bom_ref(SBOMType.SPDX), > + name=package.name, > + versionInfo=package.version, > + primaryPackagePurpose=spdx.SPDX_PACKAGE_PURPOSE_LIBRARY, > + supplier=supplier, > + downloadLocation=spdx.SPDX_NOASSERTION, > + filesAnalyzed=False, > + # TODO: it should be possible to conclude license/copyright > + # information, we could look e.g. in /usr/share/doc/*/copyright > + licenseConcluded=spdx.SPDX_NOASSERTION, > + licenseDeclared=spdx.SPDX_NOASSERTION, > + copyrightText=spdx.SPDX_NOASSERTION, > + summary=package.description, > + externalRefs=[ > + spdx.SPDXExternalRef( > + referenceCategory=spdx.SPDX_REFERENCE_CATEGORY_PKG_MANAGER, > + referenceType=spdx.SPDX_REFERENCE_TYPE_PURL, > + referenceLocator=package.purl(), > + ) > + ], > + ) > + if package.homepage: > + entry.homepage = package.homepage > + data.append(entry) > + > + if package.source: > + src_entry = spdx.SPDXPackage( > + SPDXID=package.source.bom_ref(SBOMType.SPDX), > + name=package.source.name, > + versionInfo=package.source.version, > + primaryPackagePurpose=spdx.SPDX_PACKAGE_PURPOSE_SRC, > + supplier=supplier, > + downloadLocation=spdx.SPDX_NOASSERTION, > + filesAnalyzed=False, > + licenseConcluded=spdx.SPDX_NOASSERTION, > + licenseDeclared=spdx.SPDX_NOASSERTION, > + copyrightText=spdx.SPDX_NOASSERTION, > + summary="debian source code package '{}'".format(package.source.name), > + externalRefs=[ > + spdx.SPDXExternalRef( > + referenceCategory=spdx.SPDX_REFERENCE_CATEGORY_PKG_MANAGER, > + referenceType=spdx.SPDX_REFERENCE_TYPE_PURL, > + referenceLocator=package.source.purl(), > + ) > + ], > + ) > + # source packages might be referenced multiple times > + if src_entry not in data: > + data.append(src_entry) > + > + relationships = [] > + # after we have found all packages we can start to resolve dependencies > + package_names = [package.name for package in packages] > + for package in packages: > + relationships.append( > + spdx.SPDXRelationship( > + spdxElementId=package.bom_ref(SBOMType.SPDX), > + relatedSpdxElement=distro_ref, > + relationshipType=spdx.SPDX_RELATIONSHIP_PACKAGE_OF, > + ) > + ) > + if package.depends: > + for dep in package.depends: > + if dep.name in package_names: > + relationship = spdx.SPDXRelationship( > + spdxElementId=package.bom_ref(SBOMType.SPDX), > + relatedSpdxElement=dep.bom_ref(SBOMType.SPDX), > + relationshipType=spdx.SPDX_RELATIONSHIP_DEPENDS_ON, > + ) > + relationships.append(relationship) > + else: > + # this might happen if we have optional dependencies > + pass > + if package.source: > + relationship = spdx.SPDXRelationship( > + spdxElementId=package.source.bom_ref(SBOMType.SPDX), > + relatedSpdxElement=package.bom_ref(SBOMType.SPDX), > + relationshipType=spdx.SPDX_RELATIONSHIP_GENERATES, > + ) > + relationships.append(relationship) > + relationships.append( > + spdx.SPDXRelationship( > + spdxElementId=spdx.SPDX_REF_DOCUMENT, > + relatedSpdxElement=distro_ref, > + relationshipType=spdx.SPDX_RELATIONSHIP_DESCRIBES, > + ) > + ) > + > + namespace_uuid = d.getVar("SBOM_DOCUMENT_UUID") > + timestamp = datetime.fromtimestamp(int(d.getVar("SOURCE_DATE_EPOCH"))) > + bom = spdx.SPDXBOM( > + SPDXID=spdx.SPDX_REF_DOCUMENT, > + spdxVersion=spdx.SPDX_VERSION, > + creationInfo=spdx.SPDXCreationInfo( > + comment="This document has been generated as part of an ISAR build.", > + creators=[ > + "Tool: ISAR SBOM Generator - {}".format(d.getVar("SBOM_GEN_VERSION")) > + ], > + created=timestamp.strftime("%Y-%m-%dT%H:%M:%SZ"), > + ), > + name=d.getVar("SBOM_DISTRO_NAME"), > + dataLicense="CC0-1.0", > + documentNamespace="{}/{}-{}".format( > + d.getVar("SBOM_SPDX_NAMESPACE_PREFIX"), > + d.getVar("SBOM_DISTRO_NAME"), > + namespace_uuid if namespace_uuid else uuid4(), > + ), > + packages=data, > + relationships=relationships, > + ) > + return bom > + > + > +def fixup_dict(o): > + """Apply fixups for the BOMs. > + > + This is necessary for some field names and to remove fields with a None > + value. > + """ > + dct = vars(o) > + new_dct = {} > + for k, v in dct.items(): > + # remove fields with no content > + if v is not None: > + # we can not name our fields with dashes, so convert them > + k = k.replace("_", "-") > + new_dct[k] = v > + return new_dct > + > + > +def generate(d, packages: List[Package], sbom_type: SBOMType, out: str): > + """Generate a SBOM.""" > + if sbom_type == SBOMType.CycloneDX: > + bom = cyclonedx_bom(d, packages) > + elif sbom_type == SBOMType.SPDX: > + bom = spdx_bom(d, packages) > + > + with open(out, "w") as bom_file: > + json.dump(bom, bom_file, indent=2, default=fixup_dict, sort_keys=True) > diff --git a/meta/lib/sbom_cdx_types.py b/meta/lib/sbom_cdx_types.py > new file mode 100644 > index 00000000..4911cc23 > --- /dev/null > +++ b/meta/lib/sbom_cdx_types.py > @@ -0,0 +1,82 @@ > +# This software is part of ISAR. > +# Copyright (C) 2025 Siemens AG > +# > +# SPDX-License-Identifier: MIT > + > +from dataclasses import dataclass > +from typing import List, Optional > + > +# Minimal implementation of some CycloneDX SBOM types. > +# Please mind that (almost) none of these types are complete, they only > +# reflect what was strictly necessary for immediate SBOM creation > + > +CDX_BOM_FORMAT = "CycloneDX" > +CDX_SPEC_VERSION = "1.6" > + > +CDX_REF_PREFIX = "CDXRef-" > + > +CDX_PACKAGE_EXTREF_TYPE_WEBSITE = "website" > + > +CDX_COMPONENT_TYPE_LIBRARY = "library" > +CDX_COMPONENT_TYPE_APPLICATION = "application" > +CDX_COMPONENT_TYPE_OS = "operating-system" > + > + > +@dataclass > +class CDXDependency: > + ref: str > + dependsOn: Optional[str] > + > + > +@dataclass > +class CDXExternalReference: > + url: str > + type: str > + comment: Optional[str] = None > + > + > +@dataclass > +class CDXSupplierContact: > + email: Optional[str] = None > + > + > +@dataclass > +class CDXSupplier: > + name: Optional[str] = None > + contact: Optional[CDXSupplierContact] = None > + > + > +@dataclass > +class CDXComponent: > + type: str > + name: str > + bom_ref: Optional[str] = None > + supplier: Optional[str] = None > + version: Optional[CDXSupplier] = None > + description: Optional[str] = None > + purl: Optional[str] = None > + externalReferences: Optional[List[CDXExternalReference]] = None > + homepage: Optional[str] = None > + > + > +@dataclass > +class CDXBOMMetadataTool: > + components: Optional[List[CDXComponent]] > + > + > +@dataclass > +class CDXBOMMetadata: > + timestamp: Optional[str] = None > + component: Optional[str] = None > + tools: Optional[List[CDXBOMMetadataTool]] = None > + > + > +@dataclass > +class CDXBOM: > + bomFormat: str > + specVersion: str > + serialNumber: Optional[str] = None > + version: Optional[str] = None > + metadata: Optional[CDXBOMMetadata] = None > + components: Optional[List[CDXComponent]] = None > + dependencies: Optional[List[CDXDependency]] = None > diff --git a/meta/lib/sbom_spdx_types.py b/meta/lib/sbom_spdx_types.py > new file mode 100644 > index 00000000..efd7cc0c > --- /dev/null > +++ b/meta/lib/sbom_spdx_types.py > @@ -0,0 +1,95 @@ > +# This software is part of ISAR. > +# Copyright (C) 2025 Siemens AG > +# > +# SPDX-License-Identifier: MIT > + > +from dataclasses import dataclass > +from typing import List, Optional > + > +# Minimal implementation of some SPDX SBOM types. > +# Please mind that (almost) none of these types are complete, they only > +# reflect what was strictly necessary for immediate SBOM creation > + > +SPDX_VERSION = "SPDX-2.3" > + > +SPDX_REF_PREFIX = "SPDXRef-" > + > +SPDX_REF_DOCUMENT = "SPDXRef-DOCUMENT" > + > +SPDX_PACKAGE_PURPOSE_LIBRARY = "LIBRARY" > +SPDX_PACKAGE_PURPOSE_OS = "OPERATING_SYSTEM" > +SPDX_PACKAGE_PURPOSE_SRC = "SOURCE" > + > +SPDX_NOASSERTION = "NOASSERTION" > + > +SPDX_RELATIONSHIP_DEPENDS_ON = "DEPENDS_ON" > +SPDX_RELATIONSHIP_PACKAGE_OF = "PACKAGE_OF" > +SPDX_RELATIONSHIP_GENERATES = "GENERATES" > +SPDX_RELATIONSHIP_DESCRIBES = "DESCRIBES" > + > +SPDX_REFERENCE_CATEGORY_PKG_MANAGER = "PACKAGE_MANAGER" > +SPDX_REFERENCE_TYPE_PURL = "purl" > + > +# cues for an organization in the maintainer name > +SPDX_SUPPLIER_ORG_CUE = [ > + "maintainers", > + "group", > + "developers", > + "team", > + "project", > + "task force", > + "strike force", > + "packagers", > +] > + > + > +@dataclass > +class SPDXRelationship: > + spdxElementId: str > + relatedSpdxElement: str > + relationshipType: str > + > + > +@dataclass > +class SPDXExternalRef: > + referenceCategory: str > + referenceType: str > + referenceLocator: str > + > + > +@dataclass > +class SPDXPackage: > + SPDXID: str > + name: str > + downloadLocation: str > + filesAnalyzed: Optional[bool] = False > + versionInfo: Optional[str] = None > + homepage: Optional[str] = None > + primaryPackagePurpose: Optional[str] = None > + supplier: Optional[str] = None > + licenseConcluded: Optional[str] = None > + licenseDeclared: Optional[str] = None > + copyrightText: Optional[str] = None > + summary: Optional[str] = None > + externalRefs: Optional[List[SPDXExternalRef]] = None > + > + > +@dataclass > +class SPDXCreationInfo: > + created: str > + comment: Optional[str] = None > + creators: List[str] = None > + > + > +@dataclass > +class SPDXBOM: > + """Incomplete BOM as of SPDX spec v2.3.""" > + > + SPDXID: str > + spdxVersion: str > + creationInfo: SPDXCreationInfo > + name: str > + dataLicense: str > + documentNamespace: str > + packages: List[SPDXPackage] > + relationships: List[SPDXRelationship] -- You received this message because you are subscribed to the Google Groups "isar-users" group. To unsubscribe from this group and stop receiving emails from it, send an email to isar-users+unsubscribe@googlegroups.com. To view this discussion visit https://groups.google.com/d/msgid/isar-users/e331ec02-9594-41b1-b206-0ea10160543c%40siemens.com.