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, 10 Jun 2025 14:04:11 +0200 X-Sieve: CMU Sieve 2.4 Received: from mail-pj1-f55.google.com (mail-pj1-f55.google.com [209.85.216.55]) by shymkent.ilbers.de (8.15.2/8.15.2/Debian-8+deb9u1) with ESMTPS id 55AC48V0025423 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 10 Jun 2025 14:04:10 +0200 Received: by mail-pj1-f55.google.com with SMTP id 98e67ed59e1d1-311ef4fb5eesf4486646a91.1 for ; Tue, 10 Jun 2025 05:04:09 -0700 (PDT) ARC-Seal: i=3; a=rsa-sha256; t=1749557043; cv=pass; d=google.com; s=arc-20240605; b=IxjiXeTuvGqheuSQPkFlDpWK+pgPAgdKbDCpHUoeo5FmZPADYDn8VtwIN+30rISOu5 14f3K038o3hwvytYG2cmv2nXHiBEonJKGmnW+OfRQLDSnjhyR6hwr9vv7j4SH81i+kS2 esIB3tVVRQdH7EzJq7hKigxiPak89qnExYfHSPXYMkrTVKILPRvINsz/FOvPK9BV8S10 Z8JKlGBI7Aw3EB67yrZspUKzOIJ1plx88HhOv27mJODbyC6IAJE+t3nXW9JaDGMkYePs da2dd291czDwA1HWd0vLQGDR0bSuulpjxQoVVEYEpsjhIgsdFp4/gte/fDN5s0sKZih5 r5Gg== 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=bOHOCZMMd/ZMFyxBjfvevoxTgOazqIxQiPVNLH602mw=; fh=ER0hs13Y+hw+s4BkIyLLowC5gebE71kM28D5YsVLgmw=; b=TkHQ4rnRnSo8qSuFa/CAFO2IrqOQ2ozK0eryPKD3hxz5slMGiULqbH/OeopbQXtOUv Oub2otBgAEAE5Wy4CslrgpDw/YR/NNNsG79WObZZBJ0Sw0qPfYs0nOt7eYTPL0T9WPEY +zm5t0g3tfYTwHUlwMZFg6FLOePGYmJpqjTqchIIgO9oa8jvnCfI5qAcIzOu69R1f7/t hj8vliKLTrwyIfuwXsKwI0jWkcViLORAKG/r+0scMgmnAt1Y29S58vk5bOrwtY3kk+fp E8AppY/Qxv3uawY4Y7CU/p4Kj9pH/bcxtDmWO2eKchdvG6HoG2pBqBUch2zfj4Mo6GzJ 5WbQ==; darn=ilbers.de ARC-Authentication-Results: i=3; gmr-mx.google.com; dkim=pass header.i=@siemens.com header.s=selector2 header.b=KNeg7UJf; 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:c200::5 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=1749557043; x=1750161843; 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=bOHOCZMMd/ZMFyxBjfvevoxTgOazqIxQiPVNLH602mw=; b=Li7GRqHB8a3CjY/AS4ubqlf3Is+4XLB4FVgm7iZ8fES+TFquQ1g7Va0ODI6KT5n3xO XYyvgoYntGebEmymvY+/fVsHOhXIOETa3CaRmCLvlDA6wEvIfk3RqeVv5arIXrrlZR8Z o/nP92k4dV0soztjt3uhsSkyvg51VWsTcSPUwoxie44Uexg0GRwv+j8O54UPEQHm3KkR FR+BgRmDyMwLQEK9sATUXCD2PFOdpe4mFGe5cdX0MZtwUPtEzNGpwq7iKUOjY/iznA/c ivzfs+qqpND0wuiIq120lIrc/s9SFwp6f+ph4SRPpJz7jBSvol7wCOtJYPHFbXkiWEH1 FEvA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1749557043; x=1750161843; 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 :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=bOHOCZMMd/ZMFyxBjfvevoxTgOazqIxQiPVNLH602mw=; b=VMsLQL+/MJpchTgx7lNk8tuzvI2MphqEf+M+IJN8xRJIl/Ie7LzoCgmbbl42oyhueK hE/MfHNTAwopCaneC5aJYvC/EZwsZG6GriYDsbXtnwps2btaN73GBG7BH4BB+FjyjMYp FvA6gyZbrPF+IefXJtCmdAMzs8T8XYLUOHEISfWVi6UBI0TBsyXihHN2ZocK5FiAFL7e F/A0Jjae8rmEi5ibTgEExEL1j2XZiFkzVnPNsJi0gNAIF9ASRi01OsuadsHAnp4PoOj/ xG9fpz7PM0lUjV1jYRyq1xSQx2aj0PiDcbfkRGZ9QICW8lwm3reu6vMwI7l+Z+V0xUKe JMcQ== X-Forwarded-Encrypted: i=3; AJvYcCXYzPh+xqodXRi4b8wd/Z6U5rWKJ6Ahv1P5pZW7lfHlq2AguoP0bP4poAYK2lzRYGzvyrWA@ilbers.de X-Gm-Message-State: AOJu0YzD7BHV50PJbF+fu5SmPU+YBS36bbuBpWi4ugSRFat9w9X4n3BV Q4YjqBjQhpKneQMwPUhOZHtOBfyIBGpMB5A/3S5Z1udBufuVNlf4S0Oa X-Google-Smtp-Source: AGHT+IF8Kd0AcpqlzQSmWnkv158GwCzpU4r5ZTUY0KgJrAWamG2//DvWUphuJMDKhciXBpJTk1J4Bg== X-Received: by 2002:a17:90b:2e49:b0:311:83d3:fd9c with SMTP id 98e67ed59e1d1-3139dee16b0mr4705019a91.0.1749557043043; Tue, 10 Jun 2025 05:04:03 -0700 (PDT) X-BeenThere: isar-users@googlegroups.com; h=AZMbMZf72k30GqxavvjXmmxVO8S2mIuvjRoJ5JnZsIOkkvw75w== Received: by 2002:a17:90b:353:b0:310:af10:d180 with SMTP id 98e67ed59e1d1-3132aafb386ls2035738a91.1.-pod-prod-00-us; Tue, 10 Jun 2025 05:04:01 -0700 (PDT) X-Forwarded-Encrypted: i=3; AJvYcCWdUx/QIZ6QWrQW5YtrkrDWuQ259uXbrk1xuThg3FcCZPqn15N4HUWpvJl/3zkbI80a2+6yLuuP9COS@googlegroups.com X-Received: by 2002:a17:90b:4b92:b0:311:abba:53b6 with SMTP id 98e67ed59e1d1-3139e015d08mr4626706a91.14.1749557041602; Tue, 10 Jun 2025 05:04:01 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1749557041; cv=pass; d=google.com; s=arc-20240605; b=lzp2S3pp2okc5I3WilexcKJlVgeiTOdaE9hDrGuuCi+P9IY4eIbCco7jkQKyDqxZAN 8VJRA0zB3YLMqd3ho0x8/72p5DV0SPV3KCt9dFlQCspoGHv84HXxphyguh5tSMq7VMRz AIcXa9eESdG0hltu6Htj8CDMSNC/rlkP8vKZOWBiMAl8Ftdbx6r4d2vH6Md1vA8YbTvA jR4qNOE70O5O0M+TRjHpAKXOHWpqlFm9jPLA64JLuPCs30YmtuzTYbdYUqYUXNsmvCRH oKbe5fkdmU5TcXcc9CYuk43MCYz9ZtEE4HuTHRIe7E/zUh6i/WqHRYWOSbfpZ5qD4K15 tFBg== 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=3fL14Fz9AxSORPzqCPKUpi7RXIgQXUo5G9Y6SMdo/0U=; fh=z1Jzvlt44K9vfRwvHetv7m4DQ4343YGUWadkLyT2Gbs=; b=fR79N4Wu+qRrNhHswYqSU+mmXoFvSjp7OXauKrUzZogej6hcFCSV488udNI8iVSM3H 5ES96TDQyCBRAReJqRYNNSu3vCBlQtnIorDBRdSLHMLUUbKnRs8ussqYyTTE1g5rs8ws FfAcHZM3MDDvx7BIkRHxHO3VzFUagAUAivOVbL2X50UfQ27hhk9U2yQZS4Ye6Mk+DRu0 jDAOdGjxoV/3+iSUyGxyl+3ibPW2c5YSosfaVNNL/BLCFfVt4UjUmtpfT4bTqeHPJV6u XxMKh8p5C0WLUeKZ/+nW14NgBH0KIAxWq/XUd7HxMaTwUODor25zhubdWQmai/EZoIIL wNsQ==; dara=google.com ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@siemens.com header.s=selector2 header.b=KNeg7UJf; 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:c200::5 as permitted sender) smtp.mailfrom=christoph.steiger@siemens.com; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=siemens.com Received: from DUZPR83CU001.outbound.protection.outlook.com (mail-northeuropeazlp170120005.outbound.protection.outlook.com. [2a01:111:f403:c200::5]) by gmr-mx.google.com with ESMTPS id 98e67ed59e1d1-31349686ea2si719722a91.0.2025.06.10.05.04.01 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 10 Jun 2025 05:04:01 -0700 (PDT) Received-SPF: pass (google.com: domain of christoph.steiger@siemens.com designates 2a01:111:f403:c200::5 as permitted sender) client-ip=2a01:111:f403:c200::5; ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=IOb4Zh2JbF2heO/6WKgzVGYqcgtMU5tLnaPSK+XnIl+mBHmXHHEDMe5c2kVxVP9oMUQ7dEcjhuXGVunaNGrqQunxugMI5G3nQdFzoXdl2LgpoTeEmKSRglCP1orSroJBbwcmBQJka7KV+gxtmW6gvOuSAKGHjP1VAHsaDyXi11pTB4bUKSKRMmt8jY5NgHebqiWLCtBO5uqcPEvnTj85YUjsGFjI61c45wbGPjQK62sF7KdxOfPqCWq0aksDRcI1yI3joErQ+CcyeyPrO0nbSUgBo5n5p9Er03dcz6gmuvjMu00CSbRFbvF05Nzfx1UY2nAt4BUEBK2usj5LWvdvrQ== 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=3fL14Fz9AxSORPzqCPKUpi7RXIgQXUo5G9Y6SMdo/0U=; b=X1RX9uEn8+yKXcWMJDQynHQDJy3zgIs/scq6qUTWzu/WY1F04XC34hv/ke/TS0noHz5oBNohL5ZoLAaLJaiTi6NiX4rWhFKUH2Kwk9/U7nDxaV1OEKvt6e/r4F7+PENDmJG5WQ00jkANm8PS6FsuFLWB+DMhJAfsN0RpcrKwH7Y/oqq+10w+80UHUFl5pJWEtdvBSMTnSWa8PZkFKDek+ITrQWqTE6P8wGkzWhOnU9fABoRuNEnUULNchDuKhyntCYXQ+eyGb+nOwwljnk7ayTFUhGNJ0I/hXWOJ79+zxlfu6CFW9trFJeDpdnJXLOeyRMWoVIeGR7B8vz/uNR1ioQ== 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 PA2PR10MB8410.EURPRD10.PROD.OUTLOOK.COM (2603:10a6:102:417::15) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.8813.30; Tue, 10 Jun 2025 12:03:58 +0000 Received: from AS8PR10MB7136.EURPRD10.PROD.OUTLOOK.COM ([fe80::fb1c:78f4:4286:6306]) by AS8PR10MB7136.EURPRD10.PROD.OUTLOOK.COM ([fe80::fb1c:78f4:4286:6306%2]) with mapi id 15.20.8813.024; Tue, 10 Jun 2025 12:03:58 +0000 Message-ID: Date: Tue, 10 Jun 2025 14:03:51 +0200 User-Agent: Mozilla Thunderbird Subject: Re: [RFC PATCH 1/1] meta: add CycloneDX/SPDX SBOM generation To: Felix Moessbauer , isar-users@googlegroups.com Cc: schilling.benjamin@siemens.com, cedric.hombourger@siemens.com, mete.bahadir@siemens.com 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: <20250220095944.114203-2-felix.moessbauer@siemens.com> Content-Type: text/plain; charset="UTF-8"; format=flowed X-ClientProxiedBy: CH2PR07CA0021.namprd07.prod.outlook.com (2603:10b6:610:20::34) To AS8PR10MB7136.EURPRD10.PROD.OUTLOOK.COM (2603:10a6:20b:61c::5) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: AS8PR10MB7136:EE_|PA2PR10MB8410:EE_ X-MS-Office365-Filtering-Correlation-Id: 6a679e93-ac9c-46ab-b874-08dda816e111 X-MS-Exchange-AtpMessageProperties: SA X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|376014|1800799024|366016; X-Microsoft-Antispam-Message-Info: =?utf-8?B?UUhucUFMS1BTNVRyMXAyaHZlbjRMWTFlNi9QOTJJRUQvMkJPSlBaN1c0M0xs?= =?utf-8?B?d0gyUlhnZVNzYVVCMG9qdDk0bWRKVG1DYWxPNUFnZkxiT1NyN0M3QzZIczZO?= =?utf-8?B?ZUg5VndySmM4dDZvZEdzKzFCV1M4UVJ5Slp3cUNDd2YwU1pxTjlEU3ByT04r?= =?utf-8?B?dWlQVnhpUkUybllxZ1d3MStFcUhnSzBxMEhoNk5YN1Q5RDNjQ0k2bFJvS3BN?= =?utf-8?B?ajNvSkdvLzNJYW9TZHhWU3hEK1RTVkpPTmpOU1I0eG1ndXRucUlBTkhsaDRz?= =?utf-8?B?cnRLUUQ4R3FTMjJIWWVjVTIwZGZ5b09jTXVyOE93RTVyc21teVJhVHZYVVQ1?= =?utf-8?B?cmxEdTU5KzdXWlA5czhIbGZrSitOUlpSZ0tLcWdnN3dUMHhUYVJyZnhCTk43?= =?utf-8?B?czdDRkM3UWREajhNVjlOSmNvYlZqbHhsRnlReVJ5UExzUHpWc0xzTlJnTjk4?= =?utf-8?B?RGRZdTZrbTFPbUI2dVZTTnJlUmM1OUp3ZldkcGtrU2VNQ0dhNm54eG9KQ3JC?= =?utf-8?B?ZUdnRDViNUtxNFZnNmJabGVWTFZJR1dQQzZWdlpVUFFhOEk2c2xBaW5nZnBs?= =?utf-8?B?MVgrWCs3R1FVeEllOWtSc1BZSzNzMjA3VmVWNVl6NTU0OUVLMzA3VmtyclJx?= =?utf-8?B?RTNpVmFwK3MrL3B6dFBYaWIzQi9DSEI3cHJDbkFDbWE2SU9TWkpGYW1oV3Ny?= =?utf-8?B?QnhMSTV0WjdjQVRLWlk0ekxBVlRGcnE4TUxNcURkS20rd3E2dnhXaFJIVzRx?= =?utf-8?B?Vlp6aUN5TGxncVZBZERKWEZMRlFpMTNHTUhrSEprMWdvcTdWSmNHeTJXSXJo?= =?utf-8?B?Z3NOZ29ZSjVIK0lFRTBlcWhyWkR2cTlyLzNqeDVwY2g2Q0hWRThaYW9mZktV?= =?utf-8?B?enlrWG04TkJyRHZ1cGJUTFh1dHRFK2ljeHhIT05jMFR0RnNnRHlkbS95QmR1?= =?utf-8?B?b1E1Uk1ZZXVvT0NnMGRFQzZwVkVQNFJkeTlqWlRySDhrVHRlOThCQk11NDFR?= =?utf-8?B?aFBtZnc5YTFPU1RaSGp1d0tvWGUxdkt5RGVyMTVIOVRlZ01TbzJFN2RSK3dw?= =?utf-8?B?L2k2azJ5Yk4wbE5TcnpHN3dVNnRMb1VHTmhHS09hM3k5aXJLYWJ4ZEYxSXMz?= =?utf-8?B?S0tXcitaTmJWWUlwcHRJdjhPNXd3MjNyY0pqSVhGUEhiZjM3MUZiZGFCYnFl?= =?utf-8?B?T2IrVEFrMmFZOEoyRmFGckdkMzFHVjhZcllna1kyZGpvV2pOTDlUTVArTDZ2?= =?utf-8?B?OGpvWGlxMGVlNHBJUUx2ZjBMVnE2VHloZm1FV25wQkZpYkVJdmZBb2RxZjVZ?= =?utf-8?B?Qi9EVzAxeDhlL0VDLzhPU1ppRGtJS3hLRUxtK3pjYUgyd1hnOGdxTFU1TEFq?= =?utf-8?B?Wm9LZWFCU0ZueFY3bjh4RFU0SzBWMG5CM3MzNGpNU1YzQ2hpL2hWblNjZFly?= =?utf-8?B?a3lSWXY0NjBXSjROZG10WU1KWFhCamJLa0FQWnBmRVl5aU5wd01ZMWczVWp6?= =?utf-8?B?Y3JORWg1aW9tbU9CWlkrL2M3ckgxMmxxZHFSUm5IUkpOdEFhc1Y0YzBGVmJV?= =?utf-8?B?cmJvUHphQnJCblBrV0lLWnBObm5HTExtWDlpOWpEQ0ZPU09YcjlzUEQ5L0Z4?= =?utf-8?B?UmJNMHJVVUJZdmpjL0srUmpkcWZkWGwxcjB4dkdCeGVxNVpiamowZHY0ZVpQ?= =?utf-8?B?cWFhSm5DK0FDMjBaaG9TV3huTE10Q1U4ZXNBTm9QYU1zMGJIUWdVWW5yc0xW?= =?utf-8?B?WllUL1U0Qm9KVjY1THZuOU9vTGFwOElZWU1vcjdoM2V1YVVSUmpDQ3BjSklk?= =?utf-8?Q?jdqHVNnfewhs0izbJiNpVCRuSdWluVdf9V9jk=3D?= 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)(376014)(1800799024)(366016);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?RnVGZGdQYU9YTFMzT0lvMm56Q280MmJYaTJLcklxOWhLcnJldmRkckpDNFpF?= =?utf-8?B?UEZBWGxwSGVVMUZkR2tlQmhEYnIwN1hoRHB0VjNGM2tXZExLbGVERlgyR1cx?= =?utf-8?B?Yi83a0pkdDFZTXVBZ3VsMnY2RnFIRjgwNjdoNXRTSFlKRTdkdVhkc000dm5k?= =?utf-8?B?VEJyNi85VVpwa0gzV1daYjdrektiRHpKb0VSeG1aTzdvNEwyK29HWWR2NWhX?= =?utf-8?B?Mm1IaEhONm52eGRCTmFHK2xjZWw5VFVaWjlFNlhxODkvY0pjSExhcmxjZ1lI?= =?utf-8?B?ckNXR1V2VlBDVkYva0JGU0FiQjVXTGFkSjNwWTlOQ1FTK041cmFzUjRPZGN5?= =?utf-8?B?TzFoMzBRWTIrVTJLYkFYRll6UHhxdWgrZG12V003Uk1DSm1oOFh5bFVpbzE5?= =?utf-8?B?ZFNvcGZremthMG9PQ0VUeVJHUEZVS2dXYktNdGRzb2pXZ2creVJEd3lzVnpS?= =?utf-8?B?ajBLRXNtTHFxMFllRlc5THN5dWEyVkRRd1RGVCtLNkY1bWFuZm9ZS3FvOEJG?= =?utf-8?B?c0hTZEgzWXo4dDhwemFyNmQ1Y0RpWCtORkFwZXFXUFMyWWwrOEJ2alVtRXR1?= =?utf-8?B?R0FkUWdrMDBhZEtSNDNDbkp6dkt5U0ZLYmN0WkhtMjFlcXNCRStheUdlSFRO?= =?utf-8?B?UFJkS09tenhoMnIvcERxVzcwK3RYL09NaVVybzg4UkI1NFlLRGYreG9CZVFE?= =?utf-8?B?QVpjZnFIVmFDOXZydC9Ld3ZySzVJS0NmK3ZZUzJFeFh5aXdqNVNHM1Z2RnNI?= =?utf-8?B?S0NSWjlVMW1lZjlrY3FYb2hyY25Mb3JXM3ZRRHg2VHN0NHQ1cVFtaFRZMm9W?= =?utf-8?B?cjFxOHVqdmFHMkV4aFZadXhqUEt6ekpJQ2F2Q2JRTDJIdlIrSllDMjIxd2R6?= =?utf-8?B?WnRzYVBEb2Z1N0NkODhaeFFibzZBWW9Td29UdHp1OW5LTDBhR3AyREgxUlBJ?= =?utf-8?B?MklPUHhNLzMzcHJSMDFRS3hnR0lLcVRaemtXeDVlUjV4Z2dqSnJKQkxsVjFD?= =?utf-8?B?OEtQQzVIRlNOakkxc3ZVcFpXTzlnUkc4VVJ6Z1lmVVBhOG9ZMzNLNmFHeXN1?= =?utf-8?B?SWhieGFJU0VFYjVWWUMyNkxWM254OUJPbm5GdHc2enlocXZXVFpEVGdiZ052?= =?utf-8?B?RnRwMVBqeERMRCtUYVhqczgrUjFSZVhvb0x5NXNRcDhIa3lkYTVMcXdsZW56?= =?utf-8?B?VnRvdkljbTFDMXVRc2FTbElTeFlMZXVKMWQrQ1hrTzRwNHRmTVNieXM5bkR4?= =?utf-8?B?WVNVejR5SlUzL2s3Vy9CZHVNMmlQRUt6T0J4eFA1dGo0Y1k2TGY0Q21tUGhI?= =?utf-8?B?eGdYdE5obExES0doaVY3bDJFcHh2RldncnFWdkpsMkNwYUNiRUh6Vm5VdVBF?= =?utf-8?B?S1VPR0tMWEQ1UUZ6eXE5eWhwZEpSRDhnVi9MU3VwTlZtbWZ6MEU5dStpU0Fz?= =?utf-8?B?YU9MVGlYMWRzTi93TE5hZGRLdkhxdmtScVRDdnFGYzAvQ1V1WTA5eG5yendx?= =?utf-8?B?eGNRdGtaaWZLYzhvNkd5OGhuMkFjVHpRUXovQ3FtcUFoMjh6YWl4d2I4dnY3?= =?utf-8?B?aTc3Y2VmcEdvTStpM1k2RHpudVBOb0txdjFZTWpuV3ZrcTZDUGkzd1VTZ1ho?= =?utf-8?B?UWNENHFnUXB6enYwWEJGdU90anFQRXh4NWUxL1JKM3Zma3dnZnprUmUrV3h6?= =?utf-8?B?eXl5UTdBQVIrU0dRT1hXMVNQTDg3MGo3NEx5WTNMOWpCRzRsSHZUVWcyanB4?= =?utf-8?B?NENuL1c1aDh1enZsbXhyK0p6ZjBzMkNzQkplVzhIckNtaTFkY2VqODR4MnBl?= =?utf-8?B?YUVna0swOGJpbk00MDJSVEw0MTcreDFHVURtNCs4b1h3bytrQzFCVWpkcmlI?= =?utf-8?B?b2FUZC80a1A1Z284cEFDaUh2QmhZWjBLalNsZlNvdkhBMFRYM1dTYjRpRjRX?= =?utf-8?B?QlpXNE9RNUNjTXV3TDJWQXc5YXh4N1NHRW83V3dwNWJFT2dvVTNpalB1bUFh?= =?utf-8?B?bmZRRG50K2JpSVRjdFdNK1RmUytlcEphT1dTL1FVSW92SEN4a0pEWFM3ZCtK?= =?utf-8?B?NEF0Q3NPaFFhVjduRThLVmZFdE1vd3hTdkdPZWQ1emdyNEJ3MjFpV3cwL3p2?= =?utf-8?B?QjBHU0RjYldNd2ViRWRIdDNWUVVTUWhGMVlZMStmZDlxTnNFWFF4SlhTWDBh?= =?utf-8?B?aVE9PQ==?= X-OriginatorOrg: siemens.com X-MS-Exchange-CrossTenant-Network-Message-Id: 6a679e93-ac9c-46ab-b874-08dda816e111 X-MS-Exchange-CrossTenant-AuthSource: AS8PR10MB7136.EURPRD10.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 10 Jun 2025 12:03:57.9045 (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: AEzeTXIH7pU0hZ96Zm1C5mi1kGzXWhW1JX46u4Xhx9c8Y42jNkK920GhWevQDsbS3HM+uVGuyv3OyGHgx6la1pSZ05yOIYXvBJ98fV3IKbU= X-MS-Exchange-Transport-CrossTenantHeadersStamped: PA2PR10MB8410 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=KNeg7UJf; 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:c200::5 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-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=-4.9 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_H3,RCVD_IN_MSPIKE_WL, RCVD_IN_RP_CERTIFIED,RCVD_IN_RP_RNBL,RCVD_IN_RP_SAFE,SPF_PASS 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: 63/hLBAz2jsp FYI Benjamin, Cedric and Mete: We are currently working on a V2 for this with more or less the same functionality and some internal changes. It might be interesting for you too. Maybe you could try this version out in your builds and see if anything important/nice-to-have is missing in the SBOMs? > 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. > > 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") > +} > + > +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"]: > + 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"]]: > + """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"]]: > + """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/d2a35f01-2eac-4900-861f-c4094c9b9556%40siemens.com.