platform_build/tools/sbom/sbom_data.py
Wei Li f99db9977c Fix the calculation of package verification code which should not include algorithm information.
Bug: 293304694
Test: atest --host sbom_data_test
Test: build/soong/tests/sbom_test.sh
Change-Id: I94ea42284a9a6b5cc787a3489bfa575aa7663282
2023-07-31 15:09:16 -07:00

140 lines
3.6 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
import hashlib
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'
STATIC_LINK = 'STATIC_LINK'
@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)
def generate_packages_verification_code(self):
for package in self.packages:
if not package.file_ids:
continue
checksums = []
for file in self.files:
if file.id in package.file_ids:
checksums.append(file.checksum.split(': ')[1])
checksums.sort()
h = hashlib.sha1()
h.update(''.join(checksums).encode(encoding='utf-8'))
package.verification_code = h.hexdigest()