platform_build/tools/sbom/sbom_data.py
Wei Li fd7e6517d3 Some changes to support SBOM generation for b build unbundled APEXs.
1) Use output file path of installed files in build system since there is no PRODUCT_OUT in Bazel
2) Use CONTAINS to describe the relationship between a APEX and files it contains
3) Generate SBOM of APEXs, which is similar to SBOM of products

Bug: 275472038
Test: CIs
Change-Id: I41622366e5e6ed9dc78cca7bc7bb69a1f8f9bd9f
2023-05-11 13:58:37 -07:00

124 lines
3.2 KiB
Python

#!/usr/bin/env python3
#
# Copyright (C) 2023 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Define data classes that model SBOMs defined by SPDX. The data classes could be
written out to different formats (tagvalue, JSON, etc) of SPDX with corresponding
writer utilities.
Rrefer to SPDX 2.3 spec: https://spdx.github.io/spdx-spec/v2.3/ and go/android-spdx for details of
fields in each data class.
"""
from dataclasses import dataclass, field
from typing import List
SPDXID_DOC = 'SPDXRef-DOCUMENT'
SPDXID_PRODUCT = 'SPDXRef-PRODUCT'
SPDXID_PLATFORM = 'SPDXRef-PLATFORM'
PACKAGE_NAME_PRODUCT = 'PRODUCT'
PACKAGE_NAME_PLATFORM = 'PLATFORM'
VALUE_NOASSERTION = 'NOASSERTION'
VALUE_NONE = 'NONE'
class PackageExternalRefCategory:
SECURITY = 'SECURITY'
PACKAGE_MANAGER = 'PACKAGE-MANAGER'
PERSISTENT_ID = 'PERSISTENT-ID'
OTHER = 'OTHER'
class PackageExternalRefType:
cpe22Type = 'cpe22Type'
cpe23Type = 'cpe23Type'
@dataclass
class PackageExternalRef:
category: PackageExternalRefCategory
type: PackageExternalRefType
locator: str
@dataclass
class Package:
name: str
id: str
version: str = None
supplier: str = None
download_location: str = None
files_analyzed: bool = False
verification_code: str = None
file_ids: List[str] = field(default_factory=list)
external_refs: List[PackageExternalRef] = field(default_factory=list)
@dataclass
class File:
id: str
name: str
checksum: str
class RelationshipType:
DESCRIBES = 'DESCRIBES'
VARIANT_OF = 'VARIANT_OF'
GENERATED_FROM = 'GENERATED_FROM'
CONTAINS = 'CONTAINS'
@dataclass
class Relationship:
id1: str
relationship: RelationshipType
id2: str
@dataclass
class DocumentExternalReference:
id: str
uri: str
checksum: str
@dataclass
class Document:
name: str
namespace: str
id: str = SPDXID_DOC
describes: str = SPDXID_PRODUCT
creators: List[str] = field(default_factory=list)
created: str = None
external_refs: List[DocumentExternalReference] = field(default_factory=list)
packages: List[Package] = field(default_factory=list)
files: List[File] = field(default_factory=list)
relationships: List[Relationship] = field(default_factory=list)
def add_external_ref(self, external_ref):
if not any(external_ref.uri == ref.uri for ref in self.external_refs):
self.external_refs.append(external_ref)
def add_package(self, package):
if not any(package.id == p.id for p in self.packages):
self.packages.append(package)
def add_relationship(self, rel):
if not any(rel.id1 == r.id1 and rel.id2 == r.id2 and rel.relationship == r.relationship
for r in self.relationships):
self.relationships.append(rel)