1*9e94795aSAndroid Build Coastguard Worker#!/usr/bin/env python3 2*9e94795aSAndroid Build Coastguard Worker# 3*9e94795aSAndroid Build Coastguard Worker# Copyright (C) 2023 The Android Open Source Project 4*9e94795aSAndroid Build Coastguard Worker# 5*9e94795aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 6*9e94795aSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 7*9e94795aSAndroid Build Coastguard Worker# You may obtain a copy of the License at 8*9e94795aSAndroid Build Coastguard Worker# 9*9e94795aSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 10*9e94795aSAndroid Build Coastguard Worker# 11*9e94795aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 12*9e94795aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 13*9e94795aSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*9e94795aSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 15*9e94795aSAndroid Build Coastguard Worker# limitations under the License. 16*9e94795aSAndroid Build Coastguard Worker 17*9e94795aSAndroid Build Coastguard Workerimport hashlib 18*9e94795aSAndroid Build Coastguard Workerimport unittest 19*9e94795aSAndroid Build Coastguard Workerimport sbom_data 20*9e94795aSAndroid Build Coastguard Worker 21*9e94795aSAndroid Build Coastguard WorkerBUILD_FINGER_PRINT = 'build_finger_print' 22*9e94795aSAndroid Build Coastguard WorkerSUPPLIER_GOOGLE = 'Organization: Google' 23*9e94795aSAndroid Build Coastguard WorkerSUPPLIER_UPSTREAM = 'Organization: upstream' 24*9e94795aSAndroid Build Coastguard Worker 25*9e94795aSAndroid Build Coastguard WorkerSPDXID_PREBUILT_PACKAGE1 = 'SPDXRef-PREBUILT-package1' 26*9e94795aSAndroid Build Coastguard WorkerSPDXID_PREBUILT_PACKAGE2 = 'SPDXRef-PREBUILT-package2' 27*9e94795aSAndroid Build Coastguard WorkerSPDXID_SOURCE_PACKAGE1 = 'SPDXRef-SOURCE-package1' 28*9e94795aSAndroid Build Coastguard WorkerSPDXID_UPSTREAM_PACKAGE1 = 'SPDXRef-UPSTREAM-package1' 29*9e94795aSAndroid Build Coastguard Worker 30*9e94795aSAndroid Build Coastguard WorkerSPDXID_FILE1 = 'SPDXRef-file1' 31*9e94795aSAndroid Build Coastguard WorkerSPDXID_FILE2 = 'SPDXRef-file2' 32*9e94795aSAndroid Build Coastguard WorkerSPDXID_FILE3 = 'SPDXRef-file3' 33*9e94795aSAndroid Build Coastguard WorkerSPDXID_FILE4 = 'SPDXRef-file4' 34*9e94795aSAndroid Build Coastguard Worker 35*9e94795aSAndroid Build Coastguard WorkerSPDXID_LICENSE1 = "SPDXRef-License-1" 36*9e94795aSAndroid Build Coastguard WorkerSPDXID_LICENSE2 = "SPDXRef-License-2" 37*9e94795aSAndroid Build Coastguard Worker 38*9e94795aSAndroid Build Coastguard Worker 39*9e94795aSAndroid Build Coastguard Workerclass SBOMDataTest(unittest.TestCase): 40*9e94795aSAndroid Build Coastguard Worker 41*9e94795aSAndroid Build Coastguard Worker def setUp(self): 42*9e94795aSAndroid Build Coastguard Worker # SBOM of a product 43*9e94795aSAndroid Build Coastguard Worker self.sbom_doc = sbom_data.Document(name='test doc', 44*9e94795aSAndroid Build Coastguard Worker namespace='http://www.google.com/sbom/spdx/android', 45*9e94795aSAndroid Build Coastguard Worker creators=[SUPPLIER_GOOGLE], 46*9e94795aSAndroid Build Coastguard Worker created='2023-03-31T22:17:58Z', 47*9e94795aSAndroid Build Coastguard Worker describes=sbom_data.SPDXID_PRODUCT) 48*9e94795aSAndroid Build Coastguard Worker self.sbom_doc.add_external_ref( 49*9e94795aSAndroid Build Coastguard Worker sbom_data.DocumentExternalReference(id='DocumentRef-external_doc_ref', 50*9e94795aSAndroid Build Coastguard Worker uri='external_doc_uri', 51*9e94795aSAndroid Build Coastguard Worker checksum='SHA1: 1234567890')) 52*9e94795aSAndroid Build Coastguard Worker self.sbom_doc.add_package( 53*9e94795aSAndroid Build Coastguard Worker sbom_data.Package(id=sbom_data.SPDXID_PRODUCT, 54*9e94795aSAndroid Build Coastguard Worker name=sbom_data.PACKAGE_NAME_PRODUCT, 55*9e94795aSAndroid Build Coastguard Worker download_location=sbom_data.VALUE_NONE, 56*9e94795aSAndroid Build Coastguard Worker supplier=SUPPLIER_GOOGLE, 57*9e94795aSAndroid Build Coastguard Worker version=BUILD_FINGER_PRINT, 58*9e94795aSAndroid Build Coastguard Worker files_analyzed=True, 59*9e94795aSAndroid Build Coastguard Worker verification_code='', 60*9e94795aSAndroid Build Coastguard Worker file_ids=[SPDXID_FILE1, SPDXID_FILE2, SPDXID_FILE3, SPDXID_FILE4])) 61*9e94795aSAndroid Build Coastguard Worker 62*9e94795aSAndroid Build Coastguard Worker self.sbom_doc.add_package( 63*9e94795aSAndroid Build Coastguard Worker sbom_data.Package(id=sbom_data.SPDXID_PLATFORM, 64*9e94795aSAndroid Build Coastguard Worker name=sbom_data.PACKAGE_NAME_PLATFORM, 65*9e94795aSAndroid Build Coastguard Worker download_location=sbom_data.VALUE_NONE, 66*9e94795aSAndroid Build Coastguard Worker supplier=SUPPLIER_GOOGLE, 67*9e94795aSAndroid Build Coastguard Worker version=BUILD_FINGER_PRINT, 68*9e94795aSAndroid Build Coastguard Worker )) 69*9e94795aSAndroid Build Coastguard Worker 70*9e94795aSAndroid Build Coastguard Worker self.sbom_doc.add_package( 71*9e94795aSAndroid Build Coastguard Worker sbom_data.Package(id=SPDXID_PREBUILT_PACKAGE1, 72*9e94795aSAndroid Build Coastguard Worker name='Prebuilt package1', 73*9e94795aSAndroid Build Coastguard Worker download_location=sbom_data.VALUE_NONE, 74*9e94795aSAndroid Build Coastguard Worker supplier=SUPPLIER_GOOGLE, 75*9e94795aSAndroid Build Coastguard Worker version=BUILD_FINGER_PRINT, 76*9e94795aSAndroid Build Coastguard Worker )) 77*9e94795aSAndroid Build Coastguard Worker 78*9e94795aSAndroid Build Coastguard Worker self.sbom_doc.add_package( 79*9e94795aSAndroid Build Coastguard Worker sbom_data.Package(id=SPDXID_SOURCE_PACKAGE1, 80*9e94795aSAndroid Build Coastguard Worker name='Source package1', 81*9e94795aSAndroid Build Coastguard Worker download_location=sbom_data.VALUE_NONE, 82*9e94795aSAndroid Build Coastguard Worker supplier=SUPPLIER_GOOGLE, 83*9e94795aSAndroid Build Coastguard Worker version=BUILD_FINGER_PRINT, 84*9e94795aSAndroid Build Coastguard Worker external_refs=[sbom_data.PackageExternalRef( 85*9e94795aSAndroid Build Coastguard Worker category=sbom_data.PackageExternalRefCategory.SECURITY, 86*9e94795aSAndroid Build Coastguard Worker type=sbom_data.PackageExternalRefType.cpe22Type, 87*9e94795aSAndroid Build Coastguard Worker locator='cpe:/a:jsoncpp_project:jsoncpp:1.9.4')] 88*9e94795aSAndroid Build Coastguard Worker )) 89*9e94795aSAndroid Build Coastguard Worker 90*9e94795aSAndroid Build Coastguard Worker self.sbom_doc.add_package( 91*9e94795aSAndroid Build Coastguard Worker sbom_data.Package(id=SPDXID_UPSTREAM_PACKAGE1, 92*9e94795aSAndroid Build Coastguard Worker name='Upstream package1', 93*9e94795aSAndroid Build Coastguard Worker supplier=SUPPLIER_UPSTREAM, 94*9e94795aSAndroid Build Coastguard Worker version='1.1', 95*9e94795aSAndroid Build Coastguard Worker )) 96*9e94795aSAndroid Build Coastguard Worker 97*9e94795aSAndroid Build Coastguard Worker self.sbom_doc.add_relationship(sbom_data.Relationship(id1=SPDXID_SOURCE_PACKAGE1, 98*9e94795aSAndroid Build Coastguard Worker relationship=sbom_data.RelationshipType.VARIANT_OF, 99*9e94795aSAndroid Build Coastguard Worker id2=SPDXID_UPSTREAM_PACKAGE1)) 100*9e94795aSAndroid Build Coastguard Worker 101*9e94795aSAndroid Build Coastguard Worker self.sbom_doc.files.append( 102*9e94795aSAndroid Build Coastguard Worker sbom_data.File(id=SPDXID_FILE1, name='/bin/file1', 103*9e94795aSAndroid Build Coastguard Worker checksum='SHA1: 356a192b7913b04c54574d18c28d46e6395428ab')) # sha1 hash of 1 104*9e94795aSAndroid Build Coastguard Worker self.sbom_doc.files.append( 105*9e94795aSAndroid Build Coastguard Worker sbom_data.File(id=SPDXID_FILE2, name='/bin/file2', 106*9e94795aSAndroid Build Coastguard Worker checksum='SHA1: da4b9237bacccdf19c0760cab7aec4a8359010b0')) # sha1 hash of 2 107*9e94795aSAndroid Build Coastguard Worker self.sbom_doc.files.append( 108*9e94795aSAndroid Build Coastguard Worker sbom_data.File(id=SPDXID_FILE3, name='/bin/file3', 109*9e94795aSAndroid Build Coastguard Worker checksum='SHA1: 77de68daecd823babbb58edb1c8e14d7106e83bb')) # sha1 hash of 3 110*9e94795aSAndroid Build Coastguard Worker self.sbom_doc.files.append( 111*9e94795aSAndroid Build Coastguard Worker sbom_data.File(id=SPDXID_FILE4, name='file4.a', 112*9e94795aSAndroid Build Coastguard Worker checksum='SHA1: 1b6453892473a467d07372d45eb05abc2031647a')) # sha1 of 4 113*9e94795aSAndroid Build Coastguard Worker 114*9e94795aSAndroid Build Coastguard Worker self.sbom_doc.add_relationship(sbom_data.Relationship(id1=SPDXID_FILE1, 115*9e94795aSAndroid Build Coastguard Worker relationship=sbom_data.RelationshipType.GENERATED_FROM, 116*9e94795aSAndroid Build Coastguard Worker id2=sbom_data.SPDXID_PLATFORM)) 117*9e94795aSAndroid Build Coastguard Worker self.sbom_doc.add_relationship(sbom_data.Relationship(id1=SPDXID_FILE2, 118*9e94795aSAndroid Build Coastguard Worker relationship=sbom_data.RelationshipType.GENERATED_FROM, 119*9e94795aSAndroid Build Coastguard Worker id2=SPDXID_PREBUILT_PACKAGE1)) 120*9e94795aSAndroid Build Coastguard Worker self.sbom_doc.add_relationship(sbom_data.Relationship(id1=SPDXID_FILE3, 121*9e94795aSAndroid Build Coastguard Worker relationship=sbom_data.RelationshipType.GENERATED_FROM, 122*9e94795aSAndroid Build Coastguard Worker id2=SPDXID_SOURCE_PACKAGE1 123*9e94795aSAndroid Build Coastguard Worker )) 124*9e94795aSAndroid Build Coastguard Worker self.sbom_doc.add_relationship(sbom_data.Relationship(id1=SPDXID_FILE1, 125*9e94795aSAndroid Build Coastguard Worker relationship=sbom_data.RelationshipType.STATIC_LINK, 126*9e94795aSAndroid Build Coastguard Worker id2=SPDXID_FILE4 127*9e94795aSAndroid Build Coastguard Worker )) 128*9e94795aSAndroid Build Coastguard Worker 129*9e94795aSAndroid Build Coastguard Worker def test_package_verification_code(self): 130*9e94795aSAndroid Build Coastguard Worker checksums = [] 131*9e94795aSAndroid Build Coastguard Worker for file in self.sbom_doc.files: 132*9e94795aSAndroid Build Coastguard Worker checksums.append(file.checksum.split(': ')[1]) 133*9e94795aSAndroid Build Coastguard Worker checksums.sort() 134*9e94795aSAndroid Build Coastguard Worker h = hashlib.sha1() 135*9e94795aSAndroid Build Coastguard Worker h.update(''.join(checksums).encode(encoding='utf-8')) 136*9e94795aSAndroid Build Coastguard Worker expected_package_verification_code = h.hexdigest() 137*9e94795aSAndroid Build Coastguard Worker 138*9e94795aSAndroid Build Coastguard Worker self.sbom_doc.generate_packages_verification_code() 139*9e94795aSAndroid Build Coastguard Worker self.assertEqual(expected_package_verification_code, self.sbom_doc.packages[0].verification_code) 140*9e94795aSAndroid Build Coastguard Worker 141*9e94795aSAndroid Build Coastguard Worker def test_add_package_(self): 142*9e94795aSAndroid Build Coastguard Worker self.sbom_doc.add_package(sbom_data.Package(id=SPDXID_PREBUILT_PACKAGE2, 143*9e94795aSAndroid Build Coastguard Worker name='Prebuilt package2', 144*9e94795aSAndroid Build Coastguard Worker download_location=sbom_data.VALUE_NONE, 145*9e94795aSAndroid Build Coastguard Worker supplier=SUPPLIER_GOOGLE, 146*9e94795aSAndroid Build Coastguard Worker version=BUILD_FINGER_PRINT, 147*9e94795aSAndroid Build Coastguard Worker )) 148*9e94795aSAndroid Build Coastguard Worker p = next((p for p in self.sbom_doc.packages if p.id == SPDXID_PREBUILT_PACKAGE2), None) 149*9e94795aSAndroid Build Coastguard Worker self.assertNotEqual(p, None) 150*9e94795aSAndroid Build Coastguard Worker self.assertEqual(p.declared_license_ids, []) 151*9e94795aSAndroid Build Coastguard Worker 152*9e94795aSAndroid Build Coastguard Worker # Add same package with license 1 153*9e94795aSAndroid Build Coastguard Worker self.sbom_doc.add_package(sbom_data.Package(id=SPDXID_PREBUILT_PACKAGE2, 154*9e94795aSAndroid Build Coastguard Worker name='Prebuilt package2', 155*9e94795aSAndroid Build Coastguard Worker download_location=sbom_data.VALUE_NONE, 156*9e94795aSAndroid Build Coastguard Worker supplier=SUPPLIER_GOOGLE, 157*9e94795aSAndroid Build Coastguard Worker version=BUILD_FINGER_PRINT, 158*9e94795aSAndroid Build Coastguard Worker declared_license_ids=[SPDXID_LICENSE1] 159*9e94795aSAndroid Build Coastguard Worker )) 160*9e94795aSAndroid Build Coastguard Worker self.assertEqual(p.declared_license_ids, [SPDXID_LICENSE1]) 161*9e94795aSAndroid Build Coastguard Worker 162*9e94795aSAndroid Build Coastguard Worker # Add same package with license 2 163*9e94795aSAndroid Build Coastguard Worker self.sbom_doc.add_package(sbom_data.Package(id=SPDXID_PREBUILT_PACKAGE2, 164*9e94795aSAndroid Build Coastguard Worker name='Prebuilt package2', 165*9e94795aSAndroid Build Coastguard Worker download_location=sbom_data.VALUE_NONE, 166*9e94795aSAndroid Build Coastguard Worker supplier=SUPPLIER_GOOGLE, 167*9e94795aSAndroid Build Coastguard Worker version=BUILD_FINGER_PRINT, 168*9e94795aSAndroid Build Coastguard Worker declared_license_ids=[SPDXID_LICENSE2] 169*9e94795aSAndroid Build Coastguard Worker )) 170*9e94795aSAndroid Build Coastguard Worker self.assertEqual(p.declared_license_ids, [SPDXID_LICENSE1, SPDXID_LICENSE2]) 171*9e94795aSAndroid Build Coastguard Worker 172*9e94795aSAndroid Build Coastguard Worker # Add same package with license 2 again 173*9e94795aSAndroid Build Coastguard Worker self.sbom_doc.add_package(sbom_data.Package(id=SPDXID_PREBUILT_PACKAGE2, 174*9e94795aSAndroid Build Coastguard Worker name='Prebuilt package2', 175*9e94795aSAndroid Build Coastguard Worker download_location=sbom_data.VALUE_NONE, 176*9e94795aSAndroid Build Coastguard Worker supplier=SUPPLIER_GOOGLE, 177*9e94795aSAndroid Build Coastguard Worker version=BUILD_FINGER_PRINT, 178*9e94795aSAndroid Build Coastguard Worker declared_license_ids=[SPDXID_LICENSE2] 179*9e94795aSAndroid Build Coastguard Worker )) 180*9e94795aSAndroid Build Coastguard Worker self.assertEqual(p.declared_license_ids, [SPDXID_LICENSE1, SPDXID_LICENSE2]) 181*9e94795aSAndroid Build Coastguard Worker 182*9e94795aSAndroid Build Coastguard Worker 183*9e94795aSAndroid Build Coastguard Workerif __name__ == '__main__': 184*9e94795aSAndroid Build Coastguard Worker unittest.main(verbosity=2) 185