blob: 0c380f60d449fa83e2c8da084a009000bdb1e413 [file] [log] [blame]
Wei Lidec97b12023-04-07 16:45:17 -07001#!/usr/bin/env python3
2#
3# Copyright (C) 2023 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17"""
18Define data classes that model SBOMs defined by SPDX. The data classes could be
19written out to different formats (tagvalue, JSON, etc) of SPDX with corresponding
20writer utilities.
21
22Rrefer to SPDX 2.3 spec: https://spdx.github.io/spdx-spec/v2.3/ and go/android-spdx for details of
23fields in each data class.
24"""
25
26from dataclasses import dataclass, field
27from typing import List
28
29SPDXID_DOC = 'SPDXRef-DOCUMENT'
30SPDXID_PRODUCT = 'SPDXRef-PRODUCT'
31SPDXID_PLATFORM = 'SPDXRef-PLATFORM'
32
33PACKAGE_NAME_PRODUCT = 'PRODUCT'
34PACKAGE_NAME_PLATFORM = 'PLATFORM'
35
36
37class PackageExternalRefCategory:
38 SECURITY = 'SECURITY'
39 PACKAGE_MANAGER = 'PACKAGE-MANAGER'
40 PERSISTENT_ID = 'PERSISTENT-ID'
41 OTHER = 'OTHER'
42
43
44class PackageExternalRefType:
45 cpe22Type = 'cpe22Type'
46 cpe23Type = 'cpe23Type'
47
48
49@dataclass
50class PackageExternalRef:
51 category: PackageExternalRefCategory
52 type: PackageExternalRefType
53 locator: str
54
55
56@dataclass
57class Package:
58 name: str
59 id: str
60 version: str = None
61 supplier: str = None
62 download_location: str = None
63 files_analyzed: bool = False
64 verification_code: str = None
65 file_ids: List[str] = field(default_factory=list)
66 external_refs: List[PackageExternalRef] = field(default_factory=list)
67
68
69@dataclass
70class File:
71 id: str
72 name: str
73 checksum: str
74
75
76class RelationshipType:
77 DESCRIBES = 'DESCRIBES'
78 VARIANT_OF = 'VARIANT_OF'
79 GENERATED_FROM = 'GENERATED_FROM'
80
81
82@dataclass
83class Relationship:
84 id1: str
85 relationship: RelationshipType
86 id2: str
87
88
89@dataclass
90class DocumentExternalReference:
91 id: str
92 uri: str
93 checksum: str
94
95
96@dataclass
97class Document:
98 name: str
99 namespace: str
100 id: str = SPDXID_DOC
101 describes: str = SPDXID_PRODUCT
102 creators: List[str] = field(default_factory=list)
103 created: str = None
104 external_refs: List[DocumentExternalReference] = field(default_factory=list)
105 packages: List[Package] = field(default_factory=list)
106 files: List[File] = field(default_factory=list)
107 relationships: List[Relationship] = field(default_factory=list)
108
109 def add_external_ref(self, external_ref):
110 if not any(external_ref.uri == ref.uri for ref in self.external_refs):
111 self.external_refs.append(external_ref)
112
113 def add_package(self, package):
114 if not any(package.id == p.id for p in self.packages):
115 self.packages.append(package)
116
117 def add_relationship(self, rel):
118 if not any(rel.id1 == r.id1 and rel.id2 == r.id2 and rel.relationship == r.relationship
119 for r in self.relationships):
120 self.relationships.append(rel)