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 14:20:56 +0100 X-Sieve: CMU Sieve 2.4 Received: from mail-qv1-f63.google.com (mail-qv1-f63.google.com [209.85.219.63]) by shymkent.ilbers.de (8.15.2/8.15.2/Debian-8+deb9u1) with ESMTPS id 524DKrxM009991 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 4 Mar 2025 14:20:54 +0100 Received: by mail-qv1-f63.google.com with SMTP id 6a1803df08f44-6e8a0f19ae1sf107785496d6.0 for ; Tue, 04 Mar 2025 05:20:54 -0800 (PST) ARC-Seal: i=3; a=rsa-sha256; t=1741094448; cv=pass; d=google.com; s=arc-20240605; b=bAH/CnUCKQYmXJZqFFg1KoYVmo5KHu+jb11KH7y3ZPx62LvX9/HzmYMHEWkCJMWObm 6UZbzR8lilDmtQCqpjXEnoEVN28MuURJb1e1V5q6W65HnCeRneBb3WdCADwI/VNDGgdy 2q0CFzPe8C/liTI3Z74T8rEzhCGNDIILS5DwKBNu8KYTz0zDNLDDeSUhelFKQH7sXgj5 ZHlPOcd4LEriMcM6Z0hHwd0XmEDjTbsoVYm7dhLphjT9XDbTNULiJBWavJwPZ/97Lj1J tkfMYf9uFSu5HzXLMmdkVcE6K9oIdU+8xdSB8E7uh7Hmvc8mZ5tssgBzo31c1vv44HfC mMEQ== 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:in-reply-to :from:content-language:references:cc:to:subject:user-agent:date :message-id:dkim-signature; bh=Ny6KHgBU90QpUYrlO8HtzY5g5ZVHYL8lkjQ///CO1Bs=; fh=EMsyW+4ojFUtaRqXnSSfrv65KszVpcEnLqiwaE6RrSQ=; b=kNwpr6uGqo9PeGj159imXqSBdwjPiNXJx+9zrGSrROiEMxWEX9fmUhmpgBHxJns+Se TEE/UOQv0hUXjb823Zlx4F7PZ8Te6flJPW5gMN0m+bbZWMJ/qWJxH9igdVgZm1UeibhH d9zjkjehoEn6J3G4XehIdd39KPMmlNR3UmMTUCMSbx2yW/6QwHf5XhuDvNEkpHsuflT+ 2rxK7lY40FuqE6J0jc85iwanzITPdceqQb32K8SrKHsQ5sVkLMc1uKGLtlUMxWZw9Qew pczhaBwVfX/RSvdeX1G6HV4b6ojzwLRNQNQB1F/V8UxJV39MNDiaNrc0a+KEHTE4JhJw O9/Q==; darn=ilbers.de ARC-Authentication-Results: i=3; gmr-mx.google.com; dkim=pass header.i=@siemens.com header.s=selector2 header.b=OWMVfeRP; 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 christoph.steiger@siemens.com designates 2a01:111:f403:2607::626 as permitted sender) smtp.mailfrom=christoph.steiger@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=1741094448; x=1741699248; 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 :in-reply-to:from:content-language:references:cc:to:subject :user-agent:date:message-id:from:to:cc:subject:date:message-id :reply-to; bh=Ny6KHgBU90QpUYrlO8HtzY5g5ZVHYL8lkjQ///CO1Bs=; b=cn1f1mUC41OPS0Yis94qXX+Kj6RaEfBtnC25jt2lRpbBu7KGL2oKYan+szObGM6DQY aP3GakY050Mo1KdIaCLCX3qmZwZUphdQsHLA6jjSYGRwBThQIW6Q/MWmCPDsTajY1uv7 IC7nXZiKBeRi5TEDKK5boD9rQ0/GVih48XS7FpaEvQx7oNBjOVPZ/cmEVX/BrcVpELPy nADccSvHRJxWiqrxWTLWDETvRMaCMQvGXQVtSoZcAU/kj9ROkbAqWjezZiIe9mwUZWEL uOsIchGyGHH8eouTTWfJY+1ojo7qcv8g6g2rTZkbhxvGOCk2byfhbVCQ/5R6I5YpHzGl FnyA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741094448; x=1741699248; 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 :in-reply-to:from:content-language:references:cc:to:subject :user-agent:date:message-id:x-beenthere:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=Ny6KHgBU90QpUYrlO8HtzY5g5ZVHYL8lkjQ///CO1Bs=; b=IjuCg7R1MK/ErR9p46QNBGjNSRB+zBOmy0/60S1pc3WjPXZzEgVA6EW+ajqxlU1hF3 Wa95Cjg+PN1SBAXbSQDc0eTIgtZ/wLBbDLotultq3b16dnYOg/0m6lJLREIfJzL9Wa1B ZQj/vIOhnpbZ4yPxOID5ipRKPGPa2xsN8pM0zWWzuV2pO0BAET3asaEqppNsOK2+X0Wp 4qKY999OhNNgIF1O1UyL2kZVjtc7w7laMZUlXpy5J8d8KqlU90wh80zkFJPSh6csWedl AsaU82EAUcENAjdVKry7VSkKCpl4vfiuUKkXAZbf9HsidLOnZq1JrGZU/PDbWwqBGe1V nV8A== X-Forwarded-Encrypted: i=3; AJvYcCX8DkJHZnqN0Fr7jIg/NEDQtJzHmve8HDkVmvhwVgXm1WoUo2BVE729mu1oTgxydh//tnvS@ilbers.de X-Gm-Message-State: AOJu0YxUiiz/Cdv2bgj1K0y/yibehIYb2IpyDWV/HTdhuNIwWTih9y7t Opex5mrkSiUC2zY6WIHOfvYWWXSyze7uQFSSk0mqtZ81eaoII9Gu X-Google-Smtp-Source: AGHT+IFUKqxmZmVOO5AToENiInR7YEhP6MRxuf1TPatjge6hAHx47e1+DRJtcs1hDqKBECML5npXQw== X-Received: by 2002:a05:6214:21c9:b0:6e4:2e5b:8d3f with SMTP id 6a1803df08f44-6e8da8922a1mr42494656d6.14.1741094447753; Tue, 04 Mar 2025 05:20:47 -0800 (PST) X-BeenThere: isar-users@googlegroups.com; h=Adn5yVE44mC2vT+VpfgYpj4s5fItYvU21DSlt71meFJ5Z8WhXQ== Received: by 2002:a0c:f785:0:b0:6e6:58a1:caec with SMTP id 6a1803df08f44-6e895670f5dls73493596d6.2.-pod-prod-00-us; Tue, 04 Mar 2025 05:20:47 -0800 (PST) X-Forwarded-Encrypted: i=3; AJvYcCWnepACmBrcyr7pEr8cEe/dkuSL7ZLWOXaD1Vqh7JOmz7VgCqFOHbxTIR8lNxkF3KFQ7ixMMhTjWP/v@googlegroups.com X-Received: by 2002:a05:620a:2856:b0:7c3:cb72:6682 with SMTP id af79cd13be357-7c3cc3281aamr473598485a.13.1741094447268; Tue, 04 Mar 2025 05:20:47 -0800 (PST) Received: by 2002:a05:620a:c8a:b0:7c0:9619:31e1 with SMTP id af79cd13be357-7c3cd031f90ms85a; Tue, 4 Mar 2025 04:12:55 -0800 (PST) X-Forwarded-Encrypted: i=3; AJvYcCWc4KlIKyFziiEKLg9CjixWjuhe2Xuc41fzsVbZTMjNlCAIpPBz/Ur1mAuN4zDgWr73KXUnDDYEOfLR@googlegroups.com X-Received: by 2002:a05:6122:330d:b0:521:b3ee:4970 with SMTP id 71dfb90a1353d-523abbe68damr1751399e0c.2.1741090375010; Tue, 04 Mar 2025 04:12:55 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1741090374; cv=pass; d=google.com; s=arc-20240605; b=cRidMHU328y+8CPVmpiKGJfvg7chDvO1tBx/MLoI0MMVappvb4wdeKUBxRF+7ZjP0K JSGkbCbV9/DJ9SQvHUUBGIxHNkqJt8kY58LtKwKEG6TLYUPhIIRRrz/+y4BgbujdpMeJ 3qJn8VZRR1CVyni6s99PFbTr+spyGGnU+c5dU5vfAL4tDakjDGlU6+3yV6lLVeiYZe9e q0Ikb0e0p85PZC4acMF3jnkrAl21Z3Nd5rFIGBnXQ9ijAijAeFcgcc0crOOjZ1qW0L2s 7sPkuo6SwLfzLXvwu+0kXRksxncqvPYD1SIulpnPHiloZnU1QrsGpqEp/2oB9PcdX3K/ EDmw== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=mime-version:content-transfer-encoding:in-reply-to:from :content-language:references:cc:to:subject:user-agent:date :message-id:dkim-signature; bh=Y064IHOPeOrox1Ap8td0KClAbQxpM5cKwSFkg81p2xM=; fh=FAtwk7+urqdYATd9hEVkV8AC12bs+6XwzC2zRQrjxxc=; b=MNBrCIzX2ytbV6OkUy3JVeXv+R1sDsdjJHQ/poWBZW85jQP+SgqCTWN7Mi6wSemZUF wpCAxEJRsi9B0QY+4srJ5Ltd8bjV+ZQo1eTmCIL8f+gzykvnRLQVjmyTo5tUfDohSXGL Bi9x1Dq0dF/iJXb1XBnMwCz91A91sQ7fWilzOWYnn1+PBr6yPF3+/lQzkzUat541XgMR WL33kfC96rAOwdSBbK3tHNHDXdVy9928Xl2z3w/QZMEA/fx84A2RTnpGBMh0khH3JvZL cZuyOKztVcbvHPQSE0WyID73TOCFus1zlYYRRHTY3AS7pztMcP1upmCBWkc7O9zEelKi nsPw==; dara=google.com ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@siemens.com header.s=selector2 header.b=OWMVfeRP; 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 christoph.steiger@siemens.com designates 2a01:111:f403:2607::626 as permitted sender) smtp.mailfrom=christoph.steiger@siemens.com; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=siemens.com Received: from EUR02-VI1-obe.outbound.protection.outlook.com (mail-vi1eur02on20626.outbound.protection.outlook.com. [2a01:111:f403:2607::626]) by gmr-mx.google.com with ESMTPS id 71dfb90a1353d-5234bec9e4esi606690e0c.1.2025.03.04.04.12.54 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 04 Mar 2025 04:12:54 -0800 (PST) Received-SPF: pass (google.com: domain of christoph.steiger@siemens.com designates 2a01:111:f403:2607::626 as permitted sender) client-ip=2a01:111:f403:2607::626; ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=IGpIq3DSwBVEnx5lef6c/5m9nH8LfPr58SzWQGUnUPwwueZEXg/qo7kdnINrzYhhPGLlOvZHq0XOaDTIQRMKF5Xiq9RCSeICkd7L6hI12Q+1uiwI+Uc2Q9Ju2XKc6e5uFzBpfQsHcqFF90Hvzb/XfPQ6UZhqY6s7jAc3jdITyq1bvCkEtmDZYWFhg5lWzb+TZNqTgdW9/QbZbvWR4H+2EQqxZVi9qa/wVl5jv1grEJkYN8+eGNsT2wW9w2bJgKkuBphWdUXjXsKFwC+eJOS/L8OyaAOWIq2JGQDXsNUa6/vFJBXnl0tr2ZQi/gs/c1tRfe+Znz8vvWY8mtiVAOBtKw== 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=Y064IHOPeOrox1Ap8td0KClAbQxpM5cKwSFkg81p2xM=; b=l1Q3XY7r1SBQ2nwoPvM5wC+RypJB03Kk27JPQsLZ1Klce8ITZGiKaTttOfOwqBHuErvclbs2S357QjWqq8lxsyhJ3EA+z/jmLJRxt/K0FQPa4tLYkCs6GeYNxqBNPEt6riTLJcE+JQUGW/TY3zynnNk89XIO+UEXYLOsXkLDewTKSst8m/Ukaw7MLrp0d3hxS12kKAKFelP9B/YLvbfJzJxA+v/mnqsYgz8Rps+xIx62mhtT7Dnn69amZq8iIYWbOi44beAXdgSQbw7Kix5a8FZYSEAVmGVwrfsCtOltAhEa2jKH7CPUYX4Xzo4mpuTZlD6kpzrTWlWBPWbVRpjj4A== 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 AS8PR10MB7136.EURPRD10.PROD.OUTLOOK.COM (2603:10a6:20b:61c::5) by PR3PR10MB3802.EURPRD10.PROD.OUTLOOK.COM (2603:10a6:102:43::13) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.8466.29; Tue, 4 Mar 2025 12:12:51 +0000 Received: from AS8PR10MB7136.EURPRD10.PROD.OUTLOOK.COM ([fe80::fb1c:78f4:4286:6306]) by AS8PR10MB7136.EURPRD10.PROD.OUTLOOK.COM ([fe80::fb1c:78f4:4286:6306%7]) with mapi id 15.20.8489.028; Tue, 4 Mar 2025 12:12:51 +0000 Message-ID: <1076fd9d-6365-4b71-9892-09dd2d932fa9@siemens.com> Date: Tue, 4 Mar 2025 13:12:49 +0100 User-Agent: Mozilla Thunderbird Subject: Re: [RFC PATCH 1/1] meta: add CycloneDX/SPDX SBOM generation To: "Niedermayr, Benedikt (FT RPD CED OES-DE)" , "Moessbauer, Felix (FT RPD CED OES-DE)" , "isar-users@googlegroups.com" Cc: "Kiszka, Jan (FT RPD CED)" , "Hillier, Gernot (FT RPD CED OES-DE)" References: <20250220095944.114203-1-felix.moessbauer@siemens.com> <20250220095944.114203-2-felix.moessbauer@siemens.com> Content-Language: en-US From: "'Christoph Steiger' via isar-users" In-Reply-To: Content-Type: text/plain; charset="UTF-8"; format=flowed X-ClientProxiedBy: FR3P281CA0050.DEUP281.PROD.OUTLOOK.COM (2603:10a6:d10:4a::19) To AS8PR10MB7136.EURPRD10.PROD.OUTLOOK.COM (2603:10a6:20b:61c::5) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: AS8PR10MB7136:EE_|PR3PR10MB3802:EE_ X-MS-Office365-Filtering-Correlation-Id: cf386289-0c72-4c69-9a2c-08dd5b15e27f 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; X-Microsoft-Antispam-Message-Info: =?utf-8?B?bEoweDdDRUxRRVBvRjUvSmtSY3FncW84cTRIMEZpZjhmeGpBMFkyamRQdzJp?= =?utf-8?B?RnQ3eWF3SG4xMy9ia2lFeG56Z0VYdWtVY3RWZHhtRDAyV2xTWHN2Q2xnTElQ?= =?utf-8?B?dENiNWh3b21hS21DSkhlMnRPcExJM1FzcDhtckptNzhBWFVpS2l4eG9VT1FO?= =?utf-8?B?dlZ5a2NpL21pVHZoVFJvNFBRQmU5bHhJdUNUSStCM2Y0RXlMUC9hMmlEVElG?= =?utf-8?B?MTRRVks4K0xKR0R1VHlSYkRNVGtOUkU1TU5MWEJUSmhxZ0hSKzlEdDVid3A4?= =?utf-8?B?VUZNWE1ldHAwRnlURmZQUEdlcTJwbEtnOGxGTWJiMS9xVENFUkRaSHNqdnlj?= =?utf-8?B?Y0pPa2NSbHpycVprYlIzZ1AvbG1oZS9OQXV4WXVCRnpCWUtveENVdEhmQUdG?= =?utf-8?B?Y2NiSkdjTzRXdGNjeTRBZWFBc0w4eWtYTW96UVNzV2JIbDJuRENTZVZPZXlY?= =?utf-8?B?NmxWZUZkYmtkcTQyTW1tRVpTbjNwL3VjSlcvTytUU0JtQzVwMEtuQXU1cXRn?= =?utf-8?B?R2UySDJETmFHdDBpZmtENTMwMkdzZ2x1aVJnUlMxRVdtUVEwT3FEQWl0VUd5?= =?utf-8?B?ZXh0UmVCeE5xUnhjZGxDdHA0R21lajQ1V3NhNU5qL0tVMDNZenY4K3VKRXNi?= =?utf-8?B?aGdZS1FvZFg5YnB5eklmRjFqWlBrK2M2NFE2V293TzJqMkxmM0pVWEZTOWNt?= =?utf-8?B?K0djUVZIMkVQUGRMaFBkRDZSb3lCMjJPTzl0aDdkY29YM05HOGJTUXhVMlZK?= =?utf-8?B?M2xhUEE5VnVIVEhEUUNMSVp1aVBCb0hFb1hRMllzNTVVOWtYZGxNSHdKVDVv?= =?utf-8?B?NDZYZ1NzVGJSZVJ1WlgzTjZCZTBoM3lnOHpYMTVZeFhCN21nclUzZlR5VTR6?= =?utf-8?B?Zll3azMvdGVZZ1V0MjJhSGQ0MWtCRHZyYVRwQUo3aUF0K1JFdkdHaHM4TVVt?= =?utf-8?B?c3lwMnpWa3dpUVRFdklrNm5PRjRjVG1vRVRWamhaMDVjMzdZc0N6REdCZ3Bs?= =?utf-8?B?aXVkMUJIRFJLZjJwQkxNSTMzZldZMUlkWCtuMGUwQm5sYXhmRW9hbGhoMWt0?= =?utf-8?B?OURMeGNYZmhkS0Z0R2t3b010V0Exa3lwbnFnejFJSVl0bmRFUHZXbURvNHZ0?= =?utf-8?B?SkRPanlsYTJKeldRcm1BcUI4ZVJxdWg3cTJMSUlLQk9jSDI4cHZIMUtBLyt0?= =?utf-8?B?cHlpbUFaVFNQblZkUmdESExGUlBIc0NHdjBPc3dVRFFSb1VaNUpwUExRczhh?= =?utf-8?B?VWNITTYrS2VycXE3NHhrZ0MySTR3UEFUK094UGtCbTgwb3hVVTRTeDQzVUhu?= =?utf-8?B?b25CVmFESnU2V1p5QUgzc21laXlIdVhxNjFxeERZbWQvYlZXemlnUWQ3bmRl?= =?utf-8?B?YkZIamxPdUtwUGxkR3ZQUkFKUDA1cFZCVUhDSXVpNCthUUpBaTdjTEFadXlQ?= =?utf-8?B?b2crNkxYZnJjWmlIR0xCU0g4emN3RGkyVVZvVWhBaFVkZWtpcHBGc0d2RUZm?= =?utf-8?B?ZTIzMmpCMjc5MUZkQldMbnRTckp3UVVwcUtSenNPaWF6OVhEM0hNd3NXYW51?= =?utf-8?B?THh2bks1bEtWS1kyVzVyNktacTB6YXRwQXhZMHZDUzU5WTdYT2hNZFdjLzVp?= =?utf-8?B?U1JJT1RPQTl2WDI5ODM1Y3FyLzI4YTRJTDVVWUNhcXl1V0g4b3JZWVRQcWtY?= =?utf-8?B?RUVOenBLN3pJcDdiY0NzYzkrSFRGM0Z1eFpYS1dpS3A3VC9ENloyUWdNcTgr?= =?utf-8?B?TUd0d1BOOVlVR3pmYUI1S3hRL1RLbDdVNm5vRzJvMHNiV0FGYWJZanhBMTd6?= =?utf-8?B?dC9tOVNTNzRabnIycFNiUT09?= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:AS8PR10MB7136.EURPRD10.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(366016)(1800799024)(376014);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?Mk9rSTlkRkxNOGtaaTF1K3hlQlZuTXFCUEQwT2lJT2ZFRmM4ZWszREw2eHox?= =?utf-8?B?ZmxlajRibHNFenFNZzJZZGNDN2laem5MWEE1cjVhNTNwUGhKRnBqV3RaeHJ4?= =?utf-8?B?RzRhanFyYXRnaHdwNlI4QzY1Tll0UUtYV0VwbzM1QnlCZ2lEbHRIdDZVQlFZ?= =?utf-8?B?aDJTMjlRQmlXNDJGOUc3RFRBL04wVSsweWowWlVzZFFaUDBsRG5iYVRDUmVG?= =?utf-8?B?anR2YkJDNzB1VmR0YXpIbHFMZnFTRkhQL1RtVnJlSVYzSE5ma29yZ290OUk3?= =?utf-8?B?cVdIc0dmODVmYmtFWDR6V2g5dTJCUHBCdUVXcWlPTFhjREFTd1lKREF5Ulhu?= =?utf-8?B?QzNqVGNzWFRRYkNncllHVGlHU3l3VW5hM1BuOHZBM2t1empDb0l6NURzbVZ6?= =?utf-8?B?aWpveGU2OU5DRzZpMVA4czZ4blF5ZWQ5dWNSRG9TUnUwcUYvTHJOd1FXbWE0?= =?utf-8?B?Ny9YbGdOMjJaQ2Y0a2tBaTByc3dkQ2s4eU9JTGdKNzFMYXJzUGhGYUh5aVE1?= =?utf-8?B?WFpqU2IwZnZKd1Arcm8zcWUwTlpDVjRkSzNXcXZJL2c0TURwTzdxVUtUa096?= =?utf-8?B?SlU2aFFQTkZXZHdPK3VQUVAxeGRoWm5PUkRsVnJjd3JUcnZEd2V5T01rNmNx?= =?utf-8?B?T1ZxdTMvUm5EV3ExTlBXNUMweFZ5TXMyQ3JXQnU0dGpKWUdlTkhRcUFkYjdG?= =?utf-8?B?MXV0UGFuYW5CbTZTaWxqaVB5ZnMxWmx2KzgzUDE1cEQxZXpBR0RvNTlGY2s5?= =?utf-8?B?Wk45aUtDMTVUMjFLcVo0eWZ0THo2dmc5cGZyOTl0OVJsUTJ2QWgvd2FLelNL?= =?utf-8?B?MTQ5UTlNR2xQbFpKMm1wMkRNMlhNM04ya0U1UkVBc0luMXFPbzJqWGd6Ykpz?= =?utf-8?B?TnQyU2UyUmFGRTUwTVJ6QW1LMUNUdWZHQlhFajUvSFBXWVpNK1hwem5uRS9N?= =?utf-8?B?NXJYZ29iZm9FSVlvVDM3d0s5aW94OWMxdlFPeC9jMG5Gd2ovUzBvL3hPYlFh?= =?utf-8?B?WG41aVF0VFAwbWQ2RUNJc093RFIvWTIyMWpJT2ZSU3BJNUQ5UXFIUjRrRVd2?= =?utf-8?B?N1M0Tmg5YUxuaUM5eGVvbmI1VmF0NEpOT05DdENEZlNWS0VDZGV5TTFFY3U5?= =?utf-8?B?Z05FSGJOZVFVdTF2SzJrbFRYVzdiaFZWamVRSkFsZEgxMDlkdDA5ejFNT25L?= =?utf-8?B?cUFmM3BnbTgxMHVaaVk5Rk4rOTVOM3IwR2pzM1Rsc01uVGZOcHkwOTE5a3Jk?= =?utf-8?B?UkNhRVJ4OTR6SmZOajFsWkYydTFmaUNGUnZqaC9GNWtzY0pkS3c2TkNRc3Uz?= =?utf-8?B?WEt3eUI1KzlLMGNwdlgwcWNjT0RaQU1qZjl5ZEJIUWNqalU1eEROMzEzWEJH?= =?utf-8?B?SEozQXkrUE85TmhYMTFHaTBaTlFsNHphMUVEZUgwQlF2SWNDd2hCQTNrc3l3?= =?utf-8?B?VEtOVkVZTnFnWkN2ZytKU014bkVEdVd3NnNrYWNDcHpMbHVoNHA0dkFmSi9u?= =?utf-8?B?cGo4cnUvL3hXb2FaY2JVWVI3cUZuYitFRzVITWoxTnBOaTVleVVrUUZMOXN1?= =?utf-8?B?L0NEUnhBWDZKenlFak9iUjlBb2RhalhOLzd2bGUydnR1S3hxWnpQbjBML1Zy?= =?utf-8?B?cUNWa0Q0dVhmd0gwVEpXeklWcG9kUzdQdVM1OEgydjJzbGZWVHV5ZXRkVUZm?= =?utf-8?B?czYwMzR4YldkUjI1TUk3b1RmZE8veDh0bUVNSk9sSGE2THpJbXdtUUdBNW1i?= =?utf-8?B?blRFMFhnTURxUG5xVkF1bUdDR2hMQ1hTRW1lRUprU0FoOVA2QXFZaFNOSVFS?= =?utf-8?B?bHlVbjRqY2czVXJmS1N1SHpCMWxjQUZQMUMya0kxQk1oaE1TcHRrdW9vQW84?= =?utf-8?B?Uk1IN0ZWZjdGSmw0MEJlS3IvMlJhWHFOa0djRENVcjRKL0kveWNjM25pSyt0?= =?utf-8?B?ZXFvUU9ZUDF2aDhtN3Mvd0JRbWxyMXAwUTRwcEtZY1p2dGlCTmdRYXg4eUJi?= =?utf-8?B?VlZ4b0daUmZnYVFzTFdwU09yNUFzVU1NbnNWVzJpQSs2RndMcHBYaGNyUGN3?= =?utf-8?B?VG4wOE95K2xZZTBPV2xZUHdDSGluemoxKzI0eWN0Z2NGbi9JcEFiaUxyQUc4?= =?utf-8?B?eFFZeTFpTlA2SVlOZXlWQXFISTB2T1lVNTZYODJJV0t4QlZtbUJkOFhzNnpH?= =?utf-8?Q?7PJg38Dtkjh3N1EV3PZMV14=3D?= X-OriginatorOrg: siemens.com X-MS-Exchange-CrossTenant-Network-Message-Id: cf386289-0c72-4c69-9a2c-08dd5b15e27f X-MS-Exchange-CrossTenant-AuthSource: AS8PR10MB7136.EURPRD10.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 04 Mar 2025 12:12:51.1119 (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: h9O2TokMVcM1Nb5WBmKf6CBZqOt9aleJLnkv54NV4l5p47fP18EggdKmFntS0qukrKVrLfdS+9uTdzQX5dODSST6f8O51kMf7hO9nptBpKA= X-MS-Exchange-Transport-CrossTenantHeadersStamped: PR3PR10MB3802 X-Original-Sender: christoph.steiger@siemens.com X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@siemens.com header.s=selector2 header.b=OWMVfeRP; 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 christoph.steiger@siemens.com designates 2a01:111:f403:2607::626 as permitted sender) smtp.mailfrom=christoph.steiger@siemens.com; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=siemens.com X-Original-From: Christoph Steiger Reply-To: Christoph Steiger Precedence: list Mailing-list: list isar-users@googlegroups.com; contact isar-users+owners@googlegroups.com List-ID: 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: k+1RFn9vQXZZ On 3/4/25 12:54, Niedermayr, Benedikt (FT RPD CED OES-DE) wrote: > 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/ Right now a very minimal version of the SBOM standards is implemented in pure python so we can include it in meta/lib. This has some disadvantages of course. We had an extended internal discussion about this and we have decided that using the standard tooling is a better approach instead of rolling our own. Since the generation tooling is likely to grow in the future (e.g. additional versions and formats required by some people) we can minimize our development effort that way. So we are planning to actually use cyclonedx-python-lib and the spdx-tools for the SBOM generation part. Since these packages are not available yet the plan is to create a chroot for the SBOM generation and package the tools and dependencies directly in isar. The end goal is of course to get these packaged in Debian and simply use them. >> >> 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). > > Good idea, this would belong to IMAGE_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/1076fd9d-6365-4b71-9892-09dd2d932fa9%40siemens.com.