blob: 14c4eb231d69195d1580979e1b635ad9ecd59192 [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'
Wei Lifd7e6512023-05-05 10:49:28 -070083 CONTAINS = 'CONTAINS'
Wei Lidec97b12023-04-07 16:45:17 -070084
85
86@dataclass
87class Relationship:
88 id1: str
89 relationship: RelationshipType
90 id2: str
91
92
93@dataclass
94class DocumentExternalReference:
95 id: str
96 uri: str
97 checksum: str
98
99
100@dataclass
101class Document:
102 name: str
103 namespace: str
104 id: str = SPDXID_DOC
105 describes: str = SPDXID_PRODUCT
106 creators: List[str] = field(default_factory=list)
107 created: str = None
108 external_refs: List[DocumentExternalReference] = field(default_factory=list)
109 packages: List[Package] = field(default_factory=list)
110 files: List[File] = field(default_factory=list)
111 relationships: List[Relationship] = field(default_factory=list)
112
113 def add_external_ref(self, external_ref):
114 if not any(external_ref.uri == ref.uri for ref in self.external_refs):
115 self.external_refs.append(external_ref)
116
117 def add_package(self, package):
118 if not any(package.id == p.id for p in self.packages):
119 self.packages.append(package)
120
121 def add_relationship(self, rel):
122 if not any(rel.id1 == r.id1 and rel.id2 == r.id2 and rel.relationship == r.relationship
123 for r in self.relationships):
124 self.relationships.append(rel)