blob: d2ef48d52c2972edf2891db434c6cb086c689cf3 [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
Wei Li52908252023-04-14 18:49:42 -070036VALUE_NOASSERTION = 'NOASSERTION'
37VALUE_NONE = 'NONE'
38
Wei Lidec97b12023-04-07 16:45:17 -070039
40class PackageExternalRefCategory:
41 SECURITY = 'SECURITY'
42 PACKAGE_MANAGER = 'PACKAGE-MANAGER'
43 PERSISTENT_ID = 'PERSISTENT-ID'
44 OTHER = 'OTHER'
45
46
47class PackageExternalRefType:
48 cpe22Type = 'cpe22Type'
49 cpe23Type = 'cpe23Type'
50
51
52@dataclass
53class PackageExternalRef:
54 category: PackageExternalRefCategory
55 type: PackageExternalRefType
56 locator: str
57
58
59@dataclass
60class Package:
61 name: str
62 id: str
63 version: str = None
64 supplier: str = None
65 download_location: str = None
66 files_analyzed: bool = False
67 verification_code: str = None
68 file_ids: List[str] = field(default_factory=list)
69 external_refs: List[PackageExternalRef] = field(default_factory=list)
70
71
72@dataclass
73class File:
74 id: str
75 name: str
76 checksum: str
77
78
79class RelationshipType:
80 DESCRIBES = 'DESCRIBES'
81 VARIANT_OF = 'VARIANT_OF'
82 GENERATED_FROM = 'GENERATED_FROM'
83
84
85@dataclass
86class Relationship:
87 id1: str
88 relationship: RelationshipType
89 id2: str
90
91
92@dataclass
93class DocumentExternalReference:
94 id: str
95 uri: str
96 checksum: str
97
98
99@dataclass
100class Document:
101 name: str
102 namespace: str
103 id: str = SPDXID_DOC
104 describes: str = SPDXID_PRODUCT
105 creators: List[str] = field(default_factory=list)
106 created: str = None
107 external_refs: List[DocumentExternalReference] = field(default_factory=list)
108 packages: List[Package] = field(default_factory=list)
109 files: List[File] = field(default_factory=list)
110 relationships: List[Relationship] = field(default_factory=list)
111
112 def add_external_ref(self, external_ref):
113 if not any(external_ref.uri == ref.uri for ref in self.external_refs):
114 self.external_refs.append(external_ref)
115
116 def add_package(self, package):
117 if not any(package.id == p.id for p in self.packages):
118 self.packages.append(package)
119
120 def add_relationship(self, rel):
121 if not any(rel.id1 == r.id1 and rel.id2 == r.id2 and rel.relationship == r.relationship
122 for r in self.relationships):
123 self.relationships.append(rel)