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 Worker""" 18*9e94795aSAndroid Build Coastguard WorkerGenerate the SBOM of the current target product in SPDX format. 19*9e94795aSAndroid Build Coastguard WorkerUsage example: 20*9e94795aSAndroid Build Coastguard Worker generate-sbom.py --output_file out/target/product/vsoc_x86_64/sbom.spdx \ 21*9e94795aSAndroid Build Coastguard Worker --metadata out/target/product/vsoc_x86_64/sbom-metadata.csv \ 22*9e94795aSAndroid Build Coastguard Worker --build_version $(cat out/target/product/vsoc_x86_64/build_fingerprint.txt) \ 23*9e94795aSAndroid Build Coastguard Worker --product_mfr=Google 24*9e94795aSAndroid Build Coastguard Worker""" 25*9e94795aSAndroid Build Coastguard Worker 26*9e94795aSAndroid Build Coastguard Workerimport argparse 27*9e94795aSAndroid Build Coastguard Workerimport csv 28*9e94795aSAndroid Build Coastguard Workerimport datetime 29*9e94795aSAndroid Build Coastguard Workerimport google.protobuf.text_format as text_format 30*9e94795aSAndroid Build Coastguard Workerimport hashlib 31*9e94795aSAndroid Build Coastguard Workerimport os 32*9e94795aSAndroid Build Coastguard Workerimport metadata_file_pb2 33*9e94795aSAndroid Build Coastguard Workerimport sbom_data 34*9e94795aSAndroid Build Coastguard Workerimport sbom_writers 35*9e94795aSAndroid Build Coastguard Worker 36*9e94795aSAndroid Build Coastguard Worker 37*9e94795aSAndroid Build Coastguard Worker# Package type 38*9e94795aSAndroid Build Coastguard WorkerPKG_SOURCE = 'SOURCE' 39*9e94795aSAndroid Build Coastguard WorkerPKG_UPSTREAM = 'UPSTREAM' 40*9e94795aSAndroid Build Coastguard WorkerPKG_PREBUILT = 'PREBUILT' 41*9e94795aSAndroid Build Coastguard Worker 42*9e94795aSAndroid Build Coastguard Worker# Security tag 43*9e94795aSAndroid Build Coastguard WorkerNVD_CPE23 = 'NVD-CPE2.3:' 44*9e94795aSAndroid Build Coastguard Worker 45*9e94795aSAndroid Build Coastguard Worker# Report 46*9e94795aSAndroid Build Coastguard WorkerISSUE_NO_METADATA = 'No metadata generated in Make for installed files:' 47*9e94795aSAndroid Build Coastguard WorkerISSUE_NO_METADATA_FILE = 'No METADATA file found for installed file:' 48*9e94795aSAndroid Build Coastguard WorkerISSUE_METADATA_FILE_INCOMPLETE = 'METADATA file incomplete:' 49*9e94795aSAndroid Build Coastguard WorkerISSUE_UNKNOWN_SECURITY_TAG_TYPE = 'Unknown security tag type:' 50*9e94795aSAndroid Build Coastguard WorkerISSUE_INSTALLED_FILE_NOT_EXIST = 'Non-exist installed files:' 51*9e94795aSAndroid Build Coastguard WorkerINFO_METADATA_FOUND_FOR_PACKAGE = 'METADATA file found for packages:' 52*9e94795aSAndroid Build Coastguard Worker 53*9e94795aSAndroid Build Coastguard WorkerSOONG_PREBUILT_MODULE_TYPES = [ 54*9e94795aSAndroid Build Coastguard Worker 'android_app_import', 55*9e94795aSAndroid Build Coastguard Worker 'android_library_import', 56*9e94795aSAndroid Build Coastguard Worker 'cc_prebuilt_binary', 57*9e94795aSAndroid Build Coastguard Worker 'cc_prebuilt_library', 58*9e94795aSAndroid Build Coastguard Worker 'cc_prebuilt_library_headers', 59*9e94795aSAndroid Build Coastguard Worker 'cc_prebuilt_library_shared', 60*9e94795aSAndroid Build Coastguard Worker 'cc_prebuilt_library_static', 61*9e94795aSAndroid Build Coastguard Worker 'cc_prebuilt_object', 62*9e94795aSAndroid Build Coastguard Worker 'dex_import', 63*9e94795aSAndroid Build Coastguard Worker 'java_import', 64*9e94795aSAndroid Build Coastguard Worker 'java_sdk_library_import', 65*9e94795aSAndroid Build Coastguard Worker 'java_system_modules_import', 66*9e94795aSAndroid Build Coastguard Worker 'libclang_rt_prebuilt_library_static', 67*9e94795aSAndroid Build Coastguard Worker 'libclang_rt_prebuilt_library_shared', 68*9e94795aSAndroid Build Coastguard Worker 'llvm_prebuilt_library_static', 69*9e94795aSAndroid Build Coastguard Worker 'ndk_prebuilt_object', 70*9e94795aSAndroid Build Coastguard Worker 'ndk_prebuilt_shared_stl', 71*9e94795aSAndroid Build Coastguard Worker 'nkd_prebuilt_static_stl', 72*9e94795aSAndroid Build Coastguard Worker 'prebuilt_apex', 73*9e94795aSAndroid Build Coastguard Worker 'prebuilt_bootclasspath_fragment', 74*9e94795aSAndroid Build Coastguard Worker 'prebuilt_dsp', 75*9e94795aSAndroid Build Coastguard Worker 'prebuilt_firmware', 76*9e94795aSAndroid Build Coastguard Worker 'prebuilt_kernel_modules', 77*9e94795aSAndroid Build Coastguard Worker 'prebuilt_rfsa', 78*9e94795aSAndroid Build Coastguard Worker 'prebuilt_root', 79*9e94795aSAndroid Build Coastguard Worker 'rust_prebuilt_dylib', 80*9e94795aSAndroid Build Coastguard Worker 'rust_prebuilt_library', 81*9e94795aSAndroid Build Coastguard Worker 'rust_prebuilt_rlib', 82*9e94795aSAndroid Build Coastguard Worker 'vndk_prebuilt_shared', 83*9e94795aSAndroid Build Coastguard Worker] 84*9e94795aSAndroid Build Coastguard Worker 85*9e94795aSAndroid Build Coastguard WorkerTHIRD_PARTY_IDENTIFIER_TYPES = [ 86*9e94795aSAndroid Build Coastguard Worker # Types defined in metadata_file.proto 87*9e94795aSAndroid Build Coastguard Worker 'Git', 88*9e94795aSAndroid Build Coastguard Worker 'SVN', 89*9e94795aSAndroid Build Coastguard Worker 'Hg', 90*9e94795aSAndroid Build Coastguard Worker 'Darcs', 91*9e94795aSAndroid Build Coastguard Worker 'VCS', 92*9e94795aSAndroid Build Coastguard Worker 'Archive', 93*9e94795aSAndroid Build Coastguard Worker 'PrebuiltByAlphabet', 94*9e94795aSAndroid Build Coastguard Worker 'LocalSource', 95*9e94795aSAndroid Build Coastguard Worker 'Other', 96*9e94795aSAndroid Build Coastguard Worker # OSV ecosystems defined at https://ossf.github.io/osv-schema/#affectedpackage-field. 97*9e94795aSAndroid Build Coastguard Worker 'Go', 98*9e94795aSAndroid Build Coastguard Worker 'npm', 99*9e94795aSAndroid Build Coastguard Worker 'OSS-Fuzz', 100*9e94795aSAndroid Build Coastguard Worker 'PyPI', 101*9e94795aSAndroid Build Coastguard Worker 'RubyGems', 102*9e94795aSAndroid Build Coastguard Worker 'crates.io', 103*9e94795aSAndroid Build Coastguard Worker 'Hackage', 104*9e94795aSAndroid Build Coastguard Worker 'GHC', 105*9e94795aSAndroid Build Coastguard Worker 'Packagist', 106*9e94795aSAndroid Build Coastguard Worker 'Maven', 107*9e94795aSAndroid Build Coastguard Worker 'NuGet', 108*9e94795aSAndroid Build Coastguard Worker 'Linux', 109*9e94795aSAndroid Build Coastguard Worker 'Debian', 110*9e94795aSAndroid Build Coastguard Worker 'Alpine', 111*9e94795aSAndroid Build Coastguard Worker 'Hex', 112*9e94795aSAndroid Build Coastguard Worker 'Android', 113*9e94795aSAndroid Build Coastguard Worker 'GitHub Actions', 114*9e94795aSAndroid Build Coastguard Worker 'Pub', 115*9e94795aSAndroid Build Coastguard Worker 'ConanCenter', 116*9e94795aSAndroid Build Coastguard Worker 'Rocky Linux', 117*9e94795aSAndroid Build Coastguard Worker 'AlmaLinux', 118*9e94795aSAndroid Build Coastguard Worker 'Bitnami', 119*9e94795aSAndroid Build Coastguard Worker 'Photon OS', 120*9e94795aSAndroid Build Coastguard Worker 'CRAN', 121*9e94795aSAndroid Build Coastguard Worker 'Bioconductor', 122*9e94795aSAndroid Build Coastguard Worker 'SwiftURL' 123*9e94795aSAndroid Build Coastguard Worker] 124*9e94795aSAndroid Build Coastguard Worker 125*9e94795aSAndroid Build Coastguard Worker 126*9e94795aSAndroid Build Coastguard Workerdef get_args(): 127*9e94795aSAndroid Build Coastguard Worker parser = argparse.ArgumentParser() 128*9e94795aSAndroid Build Coastguard Worker parser.add_argument('-v', '--verbose', action='store_true', default=False, help='Print more information.') 129*9e94795aSAndroid Build Coastguard Worker parser.add_argument('--output_file', required=True, help='The generated SBOM file in SPDX format.') 130*9e94795aSAndroid Build Coastguard Worker parser.add_argument('--metadata', required=True, help='The SBOM metadata file path.') 131*9e94795aSAndroid Build Coastguard Worker parser.add_argument('--build_version', required=True, help='The build version.') 132*9e94795aSAndroid Build Coastguard Worker parser.add_argument('--product_mfr', required=True, help='The product manufacturer.') 133*9e94795aSAndroid Build Coastguard Worker parser.add_argument('--module_name', help='The module name. If specified, the generated SBOM is for the module.') 134*9e94795aSAndroid Build Coastguard Worker parser.add_argument('--json', action='store_true', default=False, help='Generated SBOM file in SPDX JSON format') 135*9e94795aSAndroid Build Coastguard Worker parser.add_argument('--unbundled_apk', action='store_true', default=False, help='Generate SBOM for unbundled APKs') 136*9e94795aSAndroid Build Coastguard Worker parser.add_argument('--unbundled_apex', action='store_true', default=False, help='Generate SBOM for unbundled APEXs') 137*9e94795aSAndroid Build Coastguard Worker 138*9e94795aSAndroid Build Coastguard Worker return parser.parse_args() 139*9e94795aSAndroid Build Coastguard Worker 140*9e94795aSAndroid Build Coastguard Worker 141*9e94795aSAndroid Build Coastguard Workerdef log(*info): 142*9e94795aSAndroid Build Coastguard Worker if args.verbose: 143*9e94795aSAndroid Build Coastguard Worker for i in info: 144*9e94795aSAndroid Build Coastguard Worker print(i) 145*9e94795aSAndroid Build Coastguard Worker 146*9e94795aSAndroid Build Coastguard Worker 147*9e94795aSAndroid Build Coastguard Workerdef new_package_id(package_name, type): 148*9e94795aSAndroid Build Coastguard Worker return f'SPDXRef-{type}-{sbom_data.encode_for_spdxid(package_name)}' 149*9e94795aSAndroid Build Coastguard Worker 150*9e94795aSAndroid Build Coastguard Worker 151*9e94795aSAndroid Build Coastguard Workerdef new_file_id(file_path): 152*9e94795aSAndroid Build Coastguard Worker return f'SPDXRef-{sbom_data.encode_for_spdxid(file_path)}' 153*9e94795aSAndroid Build Coastguard Worker 154*9e94795aSAndroid Build Coastguard Worker 155*9e94795aSAndroid Build Coastguard Workerdef checksum(file_path): 156*9e94795aSAndroid Build Coastguard Worker h = hashlib.sha1() 157*9e94795aSAndroid Build Coastguard Worker if os.path.islink(file_path): 158*9e94795aSAndroid Build Coastguard Worker h.update(os.readlink(file_path).encode('utf-8')) 159*9e94795aSAndroid Build Coastguard Worker else: 160*9e94795aSAndroid Build Coastguard Worker with open(file_path, 'rb') as f: 161*9e94795aSAndroid Build Coastguard Worker h.update(f.read()) 162*9e94795aSAndroid Build Coastguard Worker return f'SHA1: {h.hexdigest()}' 163*9e94795aSAndroid Build Coastguard Worker 164*9e94795aSAndroid Build Coastguard Worker 165*9e94795aSAndroid Build Coastguard Workerdef is_soong_prebuilt_module(file_metadata): 166*9e94795aSAndroid Build Coastguard Worker return (file_metadata['soong_module_type'] and 167*9e94795aSAndroid Build Coastguard Worker file_metadata['soong_module_type'] in SOONG_PREBUILT_MODULE_TYPES) 168*9e94795aSAndroid Build Coastguard Worker 169*9e94795aSAndroid Build Coastguard Worker 170*9e94795aSAndroid Build Coastguard Workerdef is_source_package(file_metadata): 171*9e94795aSAndroid Build Coastguard Worker module_path = file_metadata['module_path'] 172*9e94795aSAndroid Build Coastguard Worker return module_path.startswith('external/') and not is_prebuilt_package(file_metadata) 173*9e94795aSAndroid Build Coastguard Worker 174*9e94795aSAndroid Build Coastguard Worker 175*9e94795aSAndroid Build Coastguard Workerdef is_prebuilt_package(file_metadata): 176*9e94795aSAndroid Build Coastguard Worker module_path = file_metadata['module_path'] 177*9e94795aSAndroid Build Coastguard Worker if module_path: 178*9e94795aSAndroid Build Coastguard Worker return (module_path.startswith('prebuilts/') or 179*9e94795aSAndroid Build Coastguard Worker is_soong_prebuilt_module(file_metadata) or 180*9e94795aSAndroid Build Coastguard Worker file_metadata['is_prebuilt_make_module']) 181*9e94795aSAndroid Build Coastguard Worker 182*9e94795aSAndroid Build Coastguard Worker kernel_module_copy_files = file_metadata['kernel_module_copy_files'] 183*9e94795aSAndroid Build Coastguard Worker if kernel_module_copy_files and not kernel_module_copy_files.startswith('ANDROID-GEN:'): 184*9e94795aSAndroid Build Coastguard Worker return True 185*9e94795aSAndroid Build Coastguard Worker 186*9e94795aSAndroid Build Coastguard Worker return False 187*9e94795aSAndroid Build Coastguard Worker 188*9e94795aSAndroid Build Coastguard Worker 189*9e94795aSAndroid Build Coastguard Workerdef get_source_package_info(file_metadata, metadata_file_path): 190*9e94795aSAndroid Build Coastguard Worker """Return source package info exists in its METADATA file, currently including name, security tag 191*9e94795aSAndroid Build Coastguard Worker and external SBOM reference. 192*9e94795aSAndroid Build Coastguard Worker 193*9e94795aSAndroid Build Coastguard Worker See go/android-spdx and go/android-sbom-gen for more details. 194*9e94795aSAndroid Build Coastguard Worker """ 195*9e94795aSAndroid Build Coastguard Worker if not metadata_file_path: 196*9e94795aSAndroid Build Coastguard Worker return file_metadata['module_path'], [] 197*9e94795aSAndroid Build Coastguard Worker 198*9e94795aSAndroid Build Coastguard Worker metadata_proto = metadata_file_protos[metadata_file_path] 199*9e94795aSAndroid Build Coastguard Worker external_refs = [] 200*9e94795aSAndroid Build Coastguard Worker for tag in metadata_proto.third_party.security.tag: 201*9e94795aSAndroid Build Coastguard Worker if tag.lower().startswith((NVD_CPE23 + 'cpe:2.3:').lower()): 202*9e94795aSAndroid Build Coastguard Worker external_refs.append( 203*9e94795aSAndroid Build Coastguard Worker sbom_data.PackageExternalRef(category=sbom_data.PackageExternalRefCategory.SECURITY, 204*9e94795aSAndroid Build Coastguard Worker type=sbom_data.PackageExternalRefType.cpe23Type, 205*9e94795aSAndroid Build Coastguard Worker locator=tag.removeprefix(NVD_CPE23))) 206*9e94795aSAndroid Build Coastguard Worker elif tag.lower().startswith((NVD_CPE23 + 'cpe:/').lower()): 207*9e94795aSAndroid Build Coastguard Worker external_refs.append( 208*9e94795aSAndroid Build Coastguard Worker sbom_data.PackageExternalRef(category=sbom_data.PackageExternalRefCategory.SECURITY, 209*9e94795aSAndroid Build Coastguard Worker type=sbom_data.PackageExternalRefType.cpe22Type, 210*9e94795aSAndroid Build Coastguard Worker locator=tag.removeprefix(NVD_CPE23))) 211*9e94795aSAndroid Build Coastguard Worker 212*9e94795aSAndroid Build Coastguard Worker if metadata_proto.name: 213*9e94795aSAndroid Build Coastguard Worker return metadata_proto.name, external_refs 214*9e94795aSAndroid Build Coastguard Worker else: 215*9e94795aSAndroid Build Coastguard Worker return os.path.basename(metadata_file_path), external_refs # return the directory name only as package name 216*9e94795aSAndroid Build Coastguard Worker 217*9e94795aSAndroid Build Coastguard Worker 218*9e94795aSAndroid Build Coastguard Workerdef get_prebuilt_package_name(file_metadata, metadata_file_path): 219*9e94795aSAndroid Build Coastguard Worker """Return name of a prebuilt package, which can be from the METADATA file, metadata file path, 220*9e94795aSAndroid Build Coastguard Worker module path or kernel module's source path if the installed file is a kernel module. 221*9e94795aSAndroid Build Coastguard Worker 222*9e94795aSAndroid Build Coastguard Worker See go/android-spdx and go/android-sbom-gen for more details. 223*9e94795aSAndroid Build Coastguard Worker """ 224*9e94795aSAndroid Build Coastguard Worker name = None 225*9e94795aSAndroid Build Coastguard Worker if metadata_file_path: 226*9e94795aSAndroid Build Coastguard Worker metadata_proto = metadata_file_protos[metadata_file_path] 227*9e94795aSAndroid Build Coastguard Worker if metadata_proto.name: 228*9e94795aSAndroid Build Coastguard Worker name = metadata_proto.name 229*9e94795aSAndroid Build Coastguard Worker else: 230*9e94795aSAndroid Build Coastguard Worker name = metadata_file_path 231*9e94795aSAndroid Build Coastguard Worker elif file_metadata['module_path']: 232*9e94795aSAndroid Build Coastguard Worker name = file_metadata['module_path'] 233*9e94795aSAndroid Build Coastguard Worker elif file_metadata['kernel_module_copy_files']: 234*9e94795aSAndroid Build Coastguard Worker src_path = file_metadata['kernel_module_copy_files'].split(':')[0] 235*9e94795aSAndroid Build Coastguard Worker name = os.path.dirname(src_path) 236*9e94795aSAndroid Build Coastguard Worker 237*9e94795aSAndroid Build Coastguard Worker return name.removeprefix('prebuilts/').replace('/', '-') 238*9e94795aSAndroid Build Coastguard Worker 239*9e94795aSAndroid Build Coastguard Worker 240*9e94795aSAndroid Build Coastguard Workerdef get_metadata_file_path(file_metadata): 241*9e94795aSAndroid Build Coastguard Worker """Search for METADATA file of a package and return its path.""" 242*9e94795aSAndroid Build Coastguard Worker metadata_path = '' 243*9e94795aSAndroid Build Coastguard Worker if file_metadata['module_path']: 244*9e94795aSAndroid Build Coastguard Worker metadata_path = file_metadata['module_path'] 245*9e94795aSAndroid Build Coastguard Worker elif file_metadata['kernel_module_copy_files']: 246*9e94795aSAndroid Build Coastguard Worker metadata_path = os.path.dirname(file_metadata['kernel_module_copy_files'].split(':')[0]) 247*9e94795aSAndroid Build Coastguard Worker 248*9e94795aSAndroid Build Coastguard Worker while metadata_path and not os.path.exists(metadata_path + '/METADATA'): 249*9e94795aSAndroid Build Coastguard Worker metadata_path = os.path.dirname(metadata_path) 250*9e94795aSAndroid Build Coastguard Worker 251*9e94795aSAndroid Build Coastguard Worker return metadata_path 252*9e94795aSAndroid Build Coastguard Worker 253*9e94795aSAndroid Build Coastguard Worker 254*9e94795aSAndroid Build Coastguard Workerdef get_package_version(metadata_file_path): 255*9e94795aSAndroid Build Coastguard Worker """Return a package's version in its METADATA file.""" 256*9e94795aSAndroid Build Coastguard Worker if not metadata_file_path: 257*9e94795aSAndroid Build Coastguard Worker return None 258*9e94795aSAndroid Build Coastguard Worker metadata_proto = metadata_file_protos[metadata_file_path] 259*9e94795aSAndroid Build Coastguard Worker return metadata_proto.third_party.version 260*9e94795aSAndroid Build Coastguard Worker 261*9e94795aSAndroid Build Coastguard Worker 262*9e94795aSAndroid Build Coastguard Workerdef get_package_homepage(metadata_file_path): 263*9e94795aSAndroid Build Coastguard Worker """Return a package's homepage URL in its METADATA file.""" 264*9e94795aSAndroid Build Coastguard Worker if not metadata_file_path: 265*9e94795aSAndroid Build Coastguard Worker return None 266*9e94795aSAndroid Build Coastguard Worker metadata_proto = metadata_file_protos[metadata_file_path] 267*9e94795aSAndroid Build Coastguard Worker if metadata_proto.third_party.homepage: 268*9e94795aSAndroid Build Coastguard Worker return metadata_proto.third_party.homepage 269*9e94795aSAndroid Build Coastguard Worker for url in metadata_proto.third_party.url: 270*9e94795aSAndroid Build Coastguard Worker if url.type == metadata_file_pb2.URL.Type.HOMEPAGE: 271*9e94795aSAndroid Build Coastguard Worker return url.value 272*9e94795aSAndroid Build Coastguard Worker 273*9e94795aSAndroid Build Coastguard Worker return None 274*9e94795aSAndroid Build Coastguard Worker 275*9e94795aSAndroid Build Coastguard Worker 276*9e94795aSAndroid Build Coastguard Workerdef get_package_download_location(metadata_file_path): 277*9e94795aSAndroid Build Coastguard Worker """Return a package's code repository URL in its METADATA file.""" 278*9e94795aSAndroid Build Coastguard Worker if not metadata_file_path: 279*9e94795aSAndroid Build Coastguard Worker return None 280*9e94795aSAndroid Build Coastguard Worker metadata_proto = metadata_file_protos[metadata_file_path] 281*9e94795aSAndroid Build Coastguard Worker if metadata_proto.third_party.url: 282*9e94795aSAndroid Build Coastguard Worker urls = sorted(metadata_proto.third_party.url, key=lambda url: url.type) 283*9e94795aSAndroid Build Coastguard Worker if urls[0].type != metadata_file_pb2.URL.Type.HOMEPAGE: 284*9e94795aSAndroid Build Coastguard Worker return urls[0].value 285*9e94795aSAndroid Build Coastguard Worker elif len(urls) > 1: 286*9e94795aSAndroid Build Coastguard Worker return urls[1].value 287*9e94795aSAndroid Build Coastguard Worker 288*9e94795aSAndroid Build Coastguard Worker return None 289*9e94795aSAndroid Build Coastguard Worker 290*9e94795aSAndroid Build Coastguard Worker 291*9e94795aSAndroid Build Coastguard Workerdef get_sbom_fragments(installed_file_metadata, metadata_file_path): 292*9e94795aSAndroid Build Coastguard Worker """Return SPDX fragment of source/prebuilt packages, which usually contains a SOURCE/PREBUILT 293*9e94795aSAndroid Build Coastguard Worker package, a UPSTREAM package and an external SBOM document reference if sbom_ref defined in its 294*9e94795aSAndroid Build Coastguard Worker METADATA file. 295*9e94795aSAndroid Build Coastguard Worker 296*9e94795aSAndroid Build Coastguard Worker See go/android-spdx and go/android-sbom-gen for more details. 297*9e94795aSAndroid Build Coastguard Worker """ 298*9e94795aSAndroid Build Coastguard Worker external_doc_ref = None 299*9e94795aSAndroid Build Coastguard Worker packages = [] 300*9e94795aSAndroid Build Coastguard Worker relationships = [] 301*9e94795aSAndroid Build Coastguard Worker 302*9e94795aSAndroid Build Coastguard Worker # Info from METADATA file 303*9e94795aSAndroid Build Coastguard Worker homepage = get_package_homepage(metadata_file_path) 304*9e94795aSAndroid Build Coastguard Worker version = get_package_version(metadata_file_path) 305*9e94795aSAndroid Build Coastguard Worker download_location = get_package_download_location(metadata_file_path) 306*9e94795aSAndroid Build Coastguard Worker 307*9e94795aSAndroid Build Coastguard Worker if is_source_package(installed_file_metadata): 308*9e94795aSAndroid Build Coastguard Worker # Source fork packages 309*9e94795aSAndroid Build Coastguard Worker name, external_refs = get_source_package_info(installed_file_metadata, metadata_file_path) 310*9e94795aSAndroid Build Coastguard Worker source_package_id = new_package_id(name, PKG_SOURCE) 311*9e94795aSAndroid Build Coastguard Worker source_package = sbom_data.Package(id=source_package_id, name=name, version=args.build_version, 312*9e94795aSAndroid Build Coastguard Worker download_location=sbom_data.VALUE_NONE, 313*9e94795aSAndroid Build Coastguard Worker supplier='Organization: ' + args.product_mfr, 314*9e94795aSAndroid Build Coastguard Worker external_refs=external_refs) 315*9e94795aSAndroid Build Coastguard Worker 316*9e94795aSAndroid Build Coastguard Worker upstream_package_id = new_package_id(name, PKG_UPSTREAM) 317*9e94795aSAndroid Build Coastguard Worker upstream_package = sbom_data.Package(id=upstream_package_id, name=name, version=version, 318*9e94795aSAndroid Build Coastguard Worker supplier=('Organization: ' + homepage) if homepage else sbom_data.VALUE_NOASSERTION, 319*9e94795aSAndroid Build Coastguard Worker download_location=download_location) 320*9e94795aSAndroid Build Coastguard Worker packages += [source_package, upstream_package] 321*9e94795aSAndroid Build Coastguard Worker relationships.append(sbom_data.Relationship(id1=source_package_id, 322*9e94795aSAndroid Build Coastguard Worker relationship=sbom_data.RelationshipType.VARIANT_OF, 323*9e94795aSAndroid Build Coastguard Worker id2=upstream_package_id)) 324*9e94795aSAndroid Build Coastguard Worker elif is_prebuilt_package(installed_file_metadata): 325*9e94795aSAndroid Build Coastguard Worker # Prebuilt fork packages 326*9e94795aSAndroid Build Coastguard Worker name = get_prebuilt_package_name(installed_file_metadata, metadata_file_path) 327*9e94795aSAndroid Build Coastguard Worker prebuilt_package_id = new_package_id(name, PKG_PREBUILT) 328*9e94795aSAndroid Build Coastguard Worker prebuilt_package = sbom_data.Package(id=prebuilt_package_id, 329*9e94795aSAndroid Build Coastguard Worker name=name, 330*9e94795aSAndroid Build Coastguard Worker download_location=sbom_data.VALUE_NONE, 331*9e94795aSAndroid Build Coastguard Worker version=version if version else args.build_version, 332*9e94795aSAndroid Build Coastguard Worker supplier='Organization: ' + args.product_mfr) 333*9e94795aSAndroid Build Coastguard Worker 334*9e94795aSAndroid Build Coastguard Worker upstream_package_id = new_package_id(name, PKG_UPSTREAM) 335*9e94795aSAndroid Build Coastguard Worker upstream_package = sbom_data.Package(id=upstream_package_id, name=name, version = version, 336*9e94795aSAndroid Build Coastguard Worker supplier=('Organization: ' + homepage) if homepage else sbom_data.VALUE_NOASSERTION, 337*9e94795aSAndroid Build Coastguard Worker download_location=download_location) 338*9e94795aSAndroid Build Coastguard Worker packages += [prebuilt_package, upstream_package] 339*9e94795aSAndroid Build Coastguard Worker relationships.append(sbom_data.Relationship(id1=prebuilt_package_id, 340*9e94795aSAndroid Build Coastguard Worker relationship=sbom_data.RelationshipType.VARIANT_OF, 341*9e94795aSAndroid Build Coastguard Worker id2=upstream_package_id)) 342*9e94795aSAndroid Build Coastguard Worker 343*9e94795aSAndroid Build Coastguard Worker if metadata_file_path: 344*9e94795aSAndroid Build Coastguard Worker metadata_proto = metadata_file_protos[metadata_file_path] 345*9e94795aSAndroid Build Coastguard Worker if metadata_proto.third_party.WhichOneof('sbom') == 'sbom_ref': 346*9e94795aSAndroid Build Coastguard Worker sbom_url = metadata_proto.third_party.sbom_ref.url 347*9e94795aSAndroid Build Coastguard Worker sbom_checksum = metadata_proto.third_party.sbom_ref.checksum 348*9e94795aSAndroid Build Coastguard Worker upstream_element_id = metadata_proto.third_party.sbom_ref.element_id 349*9e94795aSAndroid Build Coastguard Worker if sbom_url and sbom_checksum and upstream_element_id: 350*9e94795aSAndroid Build Coastguard Worker doc_ref_id = f'DocumentRef-{PKG_UPSTREAM}-{sbom_data.encode_for_spdxid(name)}' 351*9e94795aSAndroid Build Coastguard Worker external_doc_ref = sbom_data.DocumentExternalReference(id=doc_ref_id, 352*9e94795aSAndroid Build Coastguard Worker uri=sbom_url, 353*9e94795aSAndroid Build Coastguard Worker checksum=sbom_checksum) 354*9e94795aSAndroid Build Coastguard Worker relationships.append( 355*9e94795aSAndroid Build Coastguard Worker sbom_data.Relationship(id1=upstream_package_id, 356*9e94795aSAndroid Build Coastguard Worker relationship=sbom_data.RelationshipType.VARIANT_OF, 357*9e94795aSAndroid Build Coastguard Worker id2=doc_ref_id + ':' + upstream_element_id)) 358*9e94795aSAndroid Build Coastguard Worker 359*9e94795aSAndroid Build Coastguard Worker return external_doc_ref, packages, relationships 360*9e94795aSAndroid Build Coastguard Worker 361*9e94795aSAndroid Build Coastguard Worker 362*9e94795aSAndroid Build Coastguard Workerdef save_report(report_file_path, report): 363*9e94795aSAndroid Build Coastguard Worker with open(report_file_path, 'w', encoding='utf-8') as report_file: 364*9e94795aSAndroid Build Coastguard Worker for type, issues in report.items(): 365*9e94795aSAndroid Build Coastguard Worker report_file.write(type + '\n') 366*9e94795aSAndroid Build Coastguard Worker for issue in issues: 367*9e94795aSAndroid Build Coastguard Worker report_file.write('\t' + issue + '\n') 368*9e94795aSAndroid Build Coastguard Worker report_file.write('\n') 369*9e94795aSAndroid Build Coastguard Worker 370*9e94795aSAndroid Build Coastguard Worker 371*9e94795aSAndroid Build Coastguard Worker# Validate the metadata generated by Make for installed files and report if there is no metadata. 372*9e94795aSAndroid Build Coastguard Workerdef installed_file_has_metadata(installed_file_metadata, report): 373*9e94795aSAndroid Build Coastguard Worker installed_file = installed_file_metadata['installed_file'] 374*9e94795aSAndroid Build Coastguard Worker module_path = installed_file_metadata['module_path'] 375*9e94795aSAndroid Build Coastguard Worker product_copy_files = installed_file_metadata['product_copy_files'] 376*9e94795aSAndroid Build Coastguard Worker kernel_module_copy_files = installed_file_metadata['kernel_module_copy_files'] 377*9e94795aSAndroid Build Coastguard Worker is_platform_generated = installed_file_metadata['is_platform_generated'] 378*9e94795aSAndroid Build Coastguard Worker 379*9e94795aSAndroid Build Coastguard Worker if (not module_path and 380*9e94795aSAndroid Build Coastguard Worker not product_copy_files and 381*9e94795aSAndroid Build Coastguard Worker not kernel_module_copy_files and 382*9e94795aSAndroid Build Coastguard Worker not is_platform_generated and 383*9e94795aSAndroid Build Coastguard Worker not installed_file.endswith('.fsv_meta')): 384*9e94795aSAndroid Build Coastguard Worker report[ISSUE_NO_METADATA].append(installed_file) 385*9e94795aSAndroid Build Coastguard Worker return False 386*9e94795aSAndroid Build Coastguard Worker 387*9e94795aSAndroid Build Coastguard Worker return True 388*9e94795aSAndroid Build Coastguard Worker 389*9e94795aSAndroid Build Coastguard Worker 390*9e94795aSAndroid Build Coastguard Worker# Validate identifiers in a package's METADATA. 391*9e94795aSAndroid Build Coastguard Worker# 1) Only known identifier type is allowed 392*9e94795aSAndroid Build Coastguard Worker# 2) Only one identifier's primary_source can be true 393*9e94795aSAndroid Build Coastguard Workerdef validate_package_metadata(metadata_file_path, package_metadata): 394*9e94795aSAndroid Build Coastguard Worker primary_source_found = False 395*9e94795aSAndroid Build Coastguard Worker for identifier in package_metadata.third_party.identifier: 396*9e94795aSAndroid Build Coastguard Worker if identifier.type not in THIRD_PARTY_IDENTIFIER_TYPES: 397*9e94795aSAndroid Build Coastguard Worker sys.exit(f'Unknown value of third_party.identifier.type in {metadata_file_path}/METADATA: {identifier.type}.') 398*9e94795aSAndroid Build Coastguard Worker if primary_source_found and identifier.primary_source: 399*9e94795aSAndroid Build Coastguard Worker sys.exit( 400*9e94795aSAndroid Build Coastguard Worker f'Field "primary_source" is set to true in multiple third_party.identifier in {metadata_file_path}/METADATA.') 401*9e94795aSAndroid Build Coastguard Worker primary_source_found = identifier.primary_source 402*9e94795aSAndroid Build Coastguard Worker 403*9e94795aSAndroid Build Coastguard Worker 404*9e94795aSAndroid Build Coastguard Workerdef report_metadata_file(metadata_file_path, installed_file_metadata, report): 405*9e94795aSAndroid Build Coastguard Worker if metadata_file_path: 406*9e94795aSAndroid Build Coastguard Worker report[INFO_METADATA_FOUND_FOR_PACKAGE].append( 407*9e94795aSAndroid Build Coastguard Worker 'installed_file: {}, module_path: {}, METADATA file: {}'.format( 408*9e94795aSAndroid Build Coastguard Worker installed_file_metadata['installed_file'], 409*9e94795aSAndroid Build Coastguard Worker installed_file_metadata['module_path'], 410*9e94795aSAndroid Build Coastguard Worker metadata_file_path + '/METADATA')) 411*9e94795aSAndroid Build Coastguard Worker 412*9e94795aSAndroid Build Coastguard Worker package_metadata = metadata_file_pb2.Metadata() 413*9e94795aSAndroid Build Coastguard Worker with open(metadata_file_path + '/METADATA', 'rt') as f: 414*9e94795aSAndroid Build Coastguard Worker text_format.Parse(f.read(), package_metadata) 415*9e94795aSAndroid Build Coastguard Worker 416*9e94795aSAndroid Build Coastguard Worker validate_package_metadata(metadata_file_path, package_metadata) 417*9e94795aSAndroid Build Coastguard Worker 418*9e94795aSAndroid Build Coastguard Worker if not metadata_file_path in metadata_file_protos: 419*9e94795aSAndroid Build Coastguard Worker metadata_file_protos[metadata_file_path] = package_metadata 420*9e94795aSAndroid Build Coastguard Worker if not package_metadata.name: 421*9e94795aSAndroid Build Coastguard Worker report[ISSUE_METADATA_FILE_INCOMPLETE].append(f'{metadata_file_path}/METADATA does not has "name"') 422*9e94795aSAndroid Build Coastguard Worker 423*9e94795aSAndroid Build Coastguard Worker if not package_metadata.third_party.version: 424*9e94795aSAndroid Build Coastguard Worker report[ISSUE_METADATA_FILE_INCOMPLETE].append( 425*9e94795aSAndroid Build Coastguard Worker f'{metadata_file_path}/METADATA does not has "third_party.version"') 426*9e94795aSAndroid Build Coastguard Worker 427*9e94795aSAndroid Build Coastguard Worker for tag in package_metadata.third_party.security.tag: 428*9e94795aSAndroid Build Coastguard Worker if not tag.startswith(NVD_CPE23): 429*9e94795aSAndroid Build Coastguard Worker report[ISSUE_UNKNOWN_SECURITY_TAG_TYPE].append( 430*9e94795aSAndroid Build Coastguard Worker f'Unknown security tag type: {tag} in {metadata_file_path}/METADATA') 431*9e94795aSAndroid Build Coastguard Worker else: 432*9e94795aSAndroid Build Coastguard Worker report[ISSUE_NO_METADATA_FILE].append( 433*9e94795aSAndroid Build Coastguard Worker "installed_file: {}, module_path: {}".format( 434*9e94795aSAndroid Build Coastguard Worker installed_file_metadata['installed_file'], installed_file_metadata['module_path'])) 435*9e94795aSAndroid Build Coastguard Worker 436*9e94795aSAndroid Build Coastguard Worker 437*9e94795aSAndroid Build Coastguard Workerdef generate_sbom_for_unbundled_apk(): 438*9e94795aSAndroid Build Coastguard Worker with open(args.metadata, newline='') as sbom_metadata_file: 439*9e94795aSAndroid Build Coastguard Worker reader = csv.DictReader(sbom_metadata_file) 440*9e94795aSAndroid Build Coastguard Worker doc = sbom_data.Document(name=args.build_version, 441*9e94795aSAndroid Build Coastguard Worker namespace=f'https://www.google.com/sbom/spdx/android/{args.build_version}', 442*9e94795aSAndroid Build Coastguard Worker creators=['Organization: ' + args.product_mfr]) 443*9e94795aSAndroid Build Coastguard Worker for installed_file_metadata in reader: 444*9e94795aSAndroid Build Coastguard Worker installed_file = installed_file_metadata['installed_file'] 445*9e94795aSAndroid Build Coastguard Worker if args.output_file != installed_file_metadata['build_output_path'] + '.spdx.json': 446*9e94795aSAndroid Build Coastguard Worker continue 447*9e94795aSAndroid Build Coastguard Worker 448*9e94795aSAndroid Build Coastguard Worker module_path = installed_file_metadata['module_path'] 449*9e94795aSAndroid Build Coastguard Worker package_id = new_package_id(module_path, PKG_PREBUILT) 450*9e94795aSAndroid Build Coastguard Worker package = sbom_data.Package(id=package_id, 451*9e94795aSAndroid Build Coastguard Worker name=module_path, 452*9e94795aSAndroid Build Coastguard Worker version=args.build_version, 453*9e94795aSAndroid Build Coastguard Worker supplier='Organization: ' + args.product_mfr) 454*9e94795aSAndroid Build Coastguard Worker file_id = new_file_id(installed_file) 455*9e94795aSAndroid Build Coastguard Worker file = sbom_data.File(id=file_id, 456*9e94795aSAndroid Build Coastguard Worker name=installed_file, 457*9e94795aSAndroid Build Coastguard Worker checksum=checksum(installed_file_metadata['build_output_path'])) 458*9e94795aSAndroid Build Coastguard Worker relationship = sbom_data.Relationship(id1=file_id, 459*9e94795aSAndroid Build Coastguard Worker relationship=sbom_data.RelationshipType.GENERATED_FROM, 460*9e94795aSAndroid Build Coastguard Worker id2=package_id) 461*9e94795aSAndroid Build Coastguard Worker doc.add_package(package) 462*9e94795aSAndroid Build Coastguard Worker doc.files.append(file) 463*9e94795aSAndroid Build Coastguard Worker doc.describes = file_id 464*9e94795aSAndroid Build Coastguard Worker doc.add_relationship(relationship) 465*9e94795aSAndroid Build Coastguard Worker doc.created = datetime.datetime.now(tz=datetime.timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ') 466*9e94795aSAndroid Build Coastguard Worker break 467*9e94795aSAndroid Build Coastguard Worker 468*9e94795aSAndroid Build Coastguard Worker with open(args.output_file, 'w', encoding='utf-8') as file: 469*9e94795aSAndroid Build Coastguard Worker sbom_writers.JSONWriter.write(doc, file) 470*9e94795aSAndroid Build Coastguard Worker fragment_file = args.output_file.removesuffix('.spdx.json') + '-fragment.spdx' 471*9e94795aSAndroid Build Coastguard Worker with open(fragment_file, 'w', encoding='utf-8') as file: 472*9e94795aSAndroid Build Coastguard Worker sbom_writers.TagValueWriter.write(doc, file, fragment=True) 473*9e94795aSAndroid Build Coastguard Worker 474*9e94795aSAndroid Build Coastguard Worker 475*9e94795aSAndroid Build Coastguard Workerdef main(): 476*9e94795aSAndroid Build Coastguard Worker global args 477*9e94795aSAndroid Build Coastguard Worker args = get_args() 478*9e94795aSAndroid Build Coastguard Worker log('Args:', vars(args)) 479*9e94795aSAndroid Build Coastguard Worker 480*9e94795aSAndroid Build Coastguard Worker if args.unbundled_apk: 481*9e94795aSAndroid Build Coastguard Worker generate_sbom_for_unbundled_apk() 482*9e94795aSAndroid Build Coastguard Worker return 483*9e94795aSAndroid Build Coastguard Worker 484*9e94795aSAndroid Build Coastguard Worker global metadata_file_protos 485*9e94795aSAndroid Build Coastguard Worker metadata_file_protos = {} 486*9e94795aSAndroid Build Coastguard Worker 487*9e94795aSAndroid Build Coastguard Worker product_package_id = sbom_data.SPDXID_PRODUCT 488*9e94795aSAndroid Build Coastguard Worker product_package_name = sbom_data.PACKAGE_NAME_PRODUCT 489*9e94795aSAndroid Build Coastguard Worker if args.module_name: 490*9e94795aSAndroid Build Coastguard Worker # Build SBOM of a module so use the module name instead. 491*9e94795aSAndroid Build Coastguard Worker product_package_id = f'SPDXRef-{sbom_data.encode_for_spdxid(args.module_name)}' 492*9e94795aSAndroid Build Coastguard Worker product_package_name = args.module_name 493*9e94795aSAndroid Build Coastguard Worker product_package = sbom_data.Package(id=product_package_id, 494*9e94795aSAndroid Build Coastguard Worker name=product_package_name, 495*9e94795aSAndroid Build Coastguard Worker download_location=sbom_data.VALUE_NONE, 496*9e94795aSAndroid Build Coastguard Worker version=args.build_version, 497*9e94795aSAndroid Build Coastguard Worker supplier='Organization: ' + args.product_mfr, 498*9e94795aSAndroid Build Coastguard Worker files_analyzed=True) 499*9e94795aSAndroid Build Coastguard Worker doc_name = args.build_version 500*9e94795aSAndroid Build Coastguard Worker if args.module_name: 501*9e94795aSAndroid Build Coastguard Worker doc_name = f'{args.build_version}/{args.module_name}' 502*9e94795aSAndroid Build Coastguard Worker doc = sbom_data.Document(name=doc_name, 503*9e94795aSAndroid Build Coastguard Worker namespace=f'https://www.google.com/sbom/spdx/android/{doc_name}', 504*9e94795aSAndroid Build Coastguard Worker creators=['Organization: ' + args.product_mfr], 505*9e94795aSAndroid Build Coastguard Worker describes=product_package_id) 506*9e94795aSAndroid Build Coastguard Worker if not args.unbundled_apex: 507*9e94795aSAndroid Build Coastguard Worker doc.packages.append(product_package) 508*9e94795aSAndroid Build Coastguard Worker 509*9e94795aSAndroid Build Coastguard Worker doc.packages.append(sbom_data.Package(id=sbom_data.SPDXID_PLATFORM, 510*9e94795aSAndroid Build Coastguard Worker name=sbom_data.PACKAGE_NAME_PLATFORM, 511*9e94795aSAndroid Build Coastguard Worker download_location=sbom_data.VALUE_NONE, 512*9e94795aSAndroid Build Coastguard Worker version=args.build_version, 513*9e94795aSAndroid Build Coastguard Worker supplier='Organization: ' + args.product_mfr)) 514*9e94795aSAndroid Build Coastguard Worker 515*9e94795aSAndroid Build Coastguard Worker # Report on some issues and information 516*9e94795aSAndroid Build Coastguard Worker report = { 517*9e94795aSAndroid Build Coastguard Worker ISSUE_NO_METADATA: [], 518*9e94795aSAndroid Build Coastguard Worker ISSUE_NO_METADATA_FILE: [], 519*9e94795aSAndroid Build Coastguard Worker ISSUE_METADATA_FILE_INCOMPLETE: [], 520*9e94795aSAndroid Build Coastguard Worker ISSUE_UNKNOWN_SECURITY_TAG_TYPE: [], 521*9e94795aSAndroid Build Coastguard Worker ISSUE_INSTALLED_FILE_NOT_EXIST: [], 522*9e94795aSAndroid Build Coastguard Worker INFO_METADATA_FOUND_FOR_PACKAGE: [], 523*9e94795aSAndroid Build Coastguard Worker } 524*9e94795aSAndroid Build Coastguard Worker 525*9e94795aSAndroid Build Coastguard Worker # Scan the metadata in CSV file and create the corresponding package and file records in SPDX 526*9e94795aSAndroid Build Coastguard Worker with open(args.metadata, newline='') as sbom_metadata_file: 527*9e94795aSAndroid Build Coastguard Worker reader = csv.DictReader(sbom_metadata_file) 528*9e94795aSAndroid Build Coastguard Worker for installed_file_metadata in reader: 529*9e94795aSAndroid Build Coastguard Worker installed_file = installed_file_metadata['installed_file'] 530*9e94795aSAndroid Build Coastguard Worker module_path = installed_file_metadata['module_path'] 531*9e94795aSAndroid Build Coastguard Worker product_copy_files = installed_file_metadata['product_copy_files'] 532*9e94795aSAndroid Build Coastguard Worker kernel_module_copy_files = installed_file_metadata['kernel_module_copy_files'] 533*9e94795aSAndroid Build Coastguard Worker build_output_path = installed_file_metadata['build_output_path'] 534*9e94795aSAndroid Build Coastguard Worker is_static_lib = installed_file_metadata['is_static_lib'] 535*9e94795aSAndroid Build Coastguard Worker 536*9e94795aSAndroid Build Coastguard Worker if not installed_file_has_metadata(installed_file_metadata, report): 537*9e94795aSAndroid Build Coastguard Worker continue 538*9e94795aSAndroid Build Coastguard Worker if not is_static_lib and not (os.path.islink(build_output_path) or os.path.isfile(build_output_path)): 539*9e94795aSAndroid Build Coastguard Worker # Ignore non-existing static library files for now since they are not shipped on devices. 540*9e94795aSAndroid Build Coastguard Worker report[ISSUE_INSTALLED_FILE_NOT_EXIST].append(installed_file) 541*9e94795aSAndroid Build Coastguard Worker continue 542*9e94795aSAndroid Build Coastguard Worker 543*9e94795aSAndroid Build Coastguard Worker file_id = new_file_id(installed_file) 544*9e94795aSAndroid Build Coastguard Worker # TODO(b/285453664): Soong should report the information of statically linked libraries to Make. 545*9e94795aSAndroid Build Coastguard Worker # This happens when a different sanitized version of static libraries is used in linking. 546*9e94795aSAndroid Build Coastguard Worker # As a workaround, use the following SHA1 checksum for static libraries created by Soong, if .a files could not be 547*9e94795aSAndroid Build Coastguard Worker # located correctly because Soong doesn't report the information to Make. 548*9e94795aSAndroid Build Coastguard Worker sha1 = 'SHA1: da39a3ee5e6b4b0d3255bfef95601890afd80709' # SHA1 of empty string 549*9e94795aSAndroid Build Coastguard Worker if os.path.islink(build_output_path) or os.path.isfile(build_output_path): 550*9e94795aSAndroid Build Coastguard Worker sha1 = checksum(build_output_path) 551*9e94795aSAndroid Build Coastguard Worker doc.files.append(sbom_data.File(id=file_id, 552*9e94795aSAndroid Build Coastguard Worker name=installed_file, 553*9e94795aSAndroid Build Coastguard Worker checksum=sha1)) 554*9e94795aSAndroid Build Coastguard Worker 555*9e94795aSAndroid Build Coastguard Worker if not is_static_lib: 556*9e94795aSAndroid Build Coastguard Worker if not args.unbundled_apex: 557*9e94795aSAndroid Build Coastguard Worker product_package.file_ids.append(file_id) 558*9e94795aSAndroid Build Coastguard Worker elif len(doc.files) > 1: 559*9e94795aSAndroid Build Coastguard Worker doc.add_relationship(sbom_data.Relationship(doc.files[0].id, sbom_data.RelationshipType.CONTAINS, file_id)) 560*9e94795aSAndroid Build Coastguard Worker 561*9e94795aSAndroid Build Coastguard Worker if is_source_package(installed_file_metadata) or is_prebuilt_package(installed_file_metadata): 562*9e94795aSAndroid Build Coastguard Worker metadata_file_path = get_metadata_file_path(installed_file_metadata) 563*9e94795aSAndroid Build Coastguard Worker report_metadata_file(metadata_file_path, installed_file_metadata, report) 564*9e94795aSAndroid Build Coastguard Worker 565*9e94795aSAndroid Build Coastguard Worker # File from source fork packages or prebuilt fork packages 566*9e94795aSAndroid Build Coastguard Worker external_doc_ref, pkgs, rels = get_sbom_fragments(installed_file_metadata, metadata_file_path) 567*9e94795aSAndroid Build Coastguard Worker if len(pkgs) > 0: 568*9e94795aSAndroid Build Coastguard Worker if external_doc_ref: 569*9e94795aSAndroid Build Coastguard Worker doc.add_external_ref(external_doc_ref) 570*9e94795aSAndroid Build Coastguard Worker for p in pkgs: 571*9e94795aSAndroid Build Coastguard Worker doc.add_package(p) 572*9e94795aSAndroid Build Coastguard Worker for rel in rels: 573*9e94795aSAndroid Build Coastguard Worker doc.add_relationship(rel) 574*9e94795aSAndroid Build Coastguard Worker fork_package_id = pkgs[0].id # The first package should be the source/prebuilt fork package 575*9e94795aSAndroid Build Coastguard Worker doc.add_relationship(sbom_data.Relationship(id1=file_id, 576*9e94795aSAndroid Build Coastguard Worker relationship=sbom_data.RelationshipType.GENERATED_FROM, 577*9e94795aSAndroid Build Coastguard Worker id2=fork_package_id)) 578*9e94795aSAndroid Build Coastguard Worker elif module_path or installed_file_metadata['is_platform_generated']: 579*9e94795aSAndroid Build Coastguard Worker # File from PLATFORM package 580*9e94795aSAndroid Build Coastguard Worker doc.add_relationship(sbom_data.Relationship(id1=file_id, 581*9e94795aSAndroid Build Coastguard Worker relationship=sbom_data.RelationshipType.GENERATED_FROM, 582*9e94795aSAndroid Build Coastguard Worker id2=sbom_data.SPDXID_PLATFORM)) 583*9e94795aSAndroid Build Coastguard Worker elif product_copy_files: 584*9e94795aSAndroid Build Coastguard Worker # Format of product_copy_files: <source path>:<dest path> 585*9e94795aSAndroid Build Coastguard Worker src_path = product_copy_files.split(':')[0] 586*9e94795aSAndroid Build Coastguard Worker # So far product_copy_files are copied from directory system, kernel, hardware, frameworks and device, 587*9e94795aSAndroid Build Coastguard Worker # so process them as files from PLATFORM package 588*9e94795aSAndroid Build Coastguard Worker doc.add_relationship(sbom_data.Relationship(id1=file_id, 589*9e94795aSAndroid Build Coastguard Worker relationship=sbom_data.RelationshipType.GENERATED_FROM, 590*9e94795aSAndroid Build Coastguard Worker id2=sbom_data.SPDXID_PLATFORM)) 591*9e94795aSAndroid Build Coastguard Worker elif installed_file.endswith('.fsv_meta'): 592*9e94795aSAndroid Build Coastguard Worker # See build/make/core/Makefile:2988 593*9e94795aSAndroid Build Coastguard Worker doc.add_relationship(sbom_data.Relationship(id1=file_id, 594*9e94795aSAndroid Build Coastguard Worker relationship=sbom_data.RelationshipType.GENERATED_FROM, 595*9e94795aSAndroid Build Coastguard Worker id2=sbom_data.SPDXID_PLATFORM)) 596*9e94795aSAndroid Build Coastguard Worker elif kernel_module_copy_files.startswith('ANDROID-GEN'): 597*9e94795aSAndroid Build Coastguard Worker # For the four files generated for _dlkm, _ramdisk partitions 598*9e94795aSAndroid Build Coastguard Worker # See build/make/core/Makefile:323 599*9e94795aSAndroid Build Coastguard Worker doc.add_relationship(sbom_data.Relationship(id1=file_id, 600*9e94795aSAndroid Build Coastguard Worker relationship=sbom_data.RelationshipType.GENERATED_FROM, 601*9e94795aSAndroid Build Coastguard Worker id2=sbom_data.SPDXID_PLATFORM)) 602*9e94795aSAndroid Build Coastguard Worker 603*9e94795aSAndroid Build Coastguard Worker # Process static libraries and whole static libraries the installed file links to 604*9e94795aSAndroid Build Coastguard Worker static_libs = installed_file_metadata['static_libraries'] 605*9e94795aSAndroid Build Coastguard Worker whole_static_libs = installed_file_metadata['whole_static_libraries'] 606*9e94795aSAndroid Build Coastguard Worker all_static_libs = (static_libs + ' ' + whole_static_libs).strip() 607*9e94795aSAndroid Build Coastguard Worker if all_static_libs: 608*9e94795aSAndroid Build Coastguard Worker for lib in all_static_libs.split(' '): 609*9e94795aSAndroid Build Coastguard Worker doc.add_relationship(sbom_data.Relationship(id1=file_id, 610*9e94795aSAndroid Build Coastguard Worker relationship=sbom_data.RelationshipType.STATIC_LINK, 611*9e94795aSAndroid Build Coastguard Worker id2=new_file_id(lib + '.a'))) 612*9e94795aSAndroid Build Coastguard Worker 613*9e94795aSAndroid Build Coastguard Worker if args.unbundled_apex: 614*9e94795aSAndroid Build Coastguard Worker doc.describes = doc.files[0].id 615*9e94795aSAndroid Build Coastguard Worker 616*9e94795aSAndroid Build Coastguard Worker # Save SBOM records to output file 617*9e94795aSAndroid Build Coastguard Worker doc.generate_packages_verification_code() 618*9e94795aSAndroid Build Coastguard Worker doc.created = datetime.datetime.now(tz=datetime.timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ') 619*9e94795aSAndroid Build Coastguard Worker prefix = args.output_file 620*9e94795aSAndroid Build Coastguard Worker if prefix.endswith('.spdx'): 621*9e94795aSAndroid Build Coastguard Worker prefix = prefix.removesuffix('.spdx') 622*9e94795aSAndroid Build Coastguard Worker elif prefix.endswith('.spdx.json'): 623*9e94795aSAndroid Build Coastguard Worker prefix = prefix.removesuffix('.spdx.json') 624*9e94795aSAndroid Build Coastguard Worker 625*9e94795aSAndroid Build Coastguard Worker output_file = prefix + '.spdx' 626*9e94795aSAndroid Build Coastguard Worker if args.unbundled_apex: 627*9e94795aSAndroid Build Coastguard Worker output_file = prefix + '-fragment.spdx' 628*9e94795aSAndroid Build Coastguard Worker with open(output_file, 'w', encoding="utf-8") as file: 629*9e94795aSAndroid Build Coastguard Worker sbom_writers.TagValueWriter.write(doc, file, fragment=args.unbundled_apex) 630*9e94795aSAndroid Build Coastguard Worker if args.json: 631*9e94795aSAndroid Build Coastguard Worker with open(prefix + '.spdx.json', 'w', encoding="utf-8") as file: 632*9e94795aSAndroid Build Coastguard Worker sbom_writers.JSONWriter.write(doc, file) 633*9e94795aSAndroid Build Coastguard Worker 634*9e94795aSAndroid Build Coastguard Worker save_report(prefix + '-gen-report.txt', report) 635*9e94795aSAndroid Build Coastguard Worker 636*9e94795aSAndroid Build Coastguard Worker 637*9e94795aSAndroid Build Coastguard Workerif __name__ == '__main__': 638*9e94795aSAndroid Build Coastguard Worker main() 639