github.com/google/osv-scalibr@v0.4.1/binary/proto/container_image_metadata.go (about) 1 // Copyright 2025 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package proto 16 17 import ( 18 "github.com/google/osv-scalibr/extractor" 19 "github.com/google/osv-scalibr/log" 20 "github.com/opencontainers/go-digest" 21 22 spb "github.com/google/osv-scalibr/binary/proto/scan_result_go_proto" 23 ) 24 25 func layerMetadataToProto(lm *extractor.LayerMetadata) *spb.LayerMetadata { 26 if lm == nil { 27 return nil 28 } 29 return &spb.LayerMetadata{ 30 Index: int32(lm.Index), 31 DiffId: lm.DiffID.String(), 32 ChainId: lm.ChainID.String(), 33 Command: lm.Command, 34 IsEmpty: lm.IsEmpty, 35 BaseImageIndex: int32(lm.BaseImageIndex), 36 } 37 } 38 39 func baseImageDetailsToProto(bid *extractor.BaseImageDetails) *spb.BaseImageDetails { 40 if bid == nil { 41 return nil 42 } 43 return &spb.BaseImageDetails{ 44 Repository: bid.Repository, 45 Registry: bid.Registry, 46 Plugin: bid.Plugin, 47 } 48 } 49 50 func containerImageMetadataToProto(cim *extractor.ContainerImageMetadata) *spb.ContainerImageMetadata { 51 if cim == nil { 52 return nil 53 } 54 var layerMetadata []*spb.LayerMetadata 55 for _, lm := range cim.LayerMetadata { 56 layerMetadata = append(layerMetadata, layerMetadataToProto(lm)) 57 } 58 59 baseImageChains := []*spb.BaseImageChain{ 60 // The first base image is always empty. 61 &spb.BaseImageChain{}, 62 } 63 64 if len(cim.BaseImages) > 1 { 65 for _, bi := range cim.BaseImages[1:] { 66 var baseImageDetails []*spb.BaseImageDetails 67 for _, bid := range bi { 68 baseImageDetails = append(baseImageDetails, baseImageDetailsToProto(bid)) 69 } 70 if len(bi) == 0 { 71 // This should never happen 72 continue 73 } 74 75 baseImageChains = append(baseImageChains, &spb.BaseImageChain{ 76 BaseImages: baseImageDetails, 77 ChainId: bi[0].ChainID.String(), 78 }) 79 } 80 } 81 82 return &spb.ContainerImageMetadata{ 83 Index: int32(cim.Index), 84 OsInfo: cim.OSInfo, 85 LayerMetadata: layerMetadata, 86 BaseImageChains: baseImageChains, 87 } 88 } 89 90 func layerMetadataToStruct(lm *spb.LayerMetadata) *extractor.LayerMetadata { 91 if lm == nil { 92 return nil 93 } 94 diffID, err := digest.Parse(lm.GetDiffId()) 95 if err != nil { 96 log.Errorf("Failed to parse diff ID %q: %v", lm.GetDiffId(), err) 97 } 98 chainID, err := digest.Parse(lm.GetChainId()) 99 if err != nil { 100 log.Errorf("Failed to parse chain ID %q: %v", lm.GetChainId(), err) 101 } 102 return &extractor.LayerMetadata{ 103 Index: int(lm.GetIndex()), 104 DiffID: diffID, 105 ChainID: chainID, 106 Command: lm.GetCommand(), 107 IsEmpty: lm.GetIsEmpty(), 108 BaseImageIndex: int(lm.GetBaseImageIndex()), 109 } 110 } 111 112 func baseImageDetailsToStruct(bid *spb.BaseImageDetails, chainID digest.Digest) *extractor.BaseImageDetails { 113 if bid == nil { 114 return nil 115 } 116 117 return &extractor.BaseImageDetails{ 118 Repository: bid.GetRepository(), 119 Registry: bid.GetRegistry(), 120 Plugin: bid.GetPlugin(), 121 ChainID: chainID, 122 } 123 } 124 125 func containerImageMetadataToStruct(cim *spb.ContainerImageMetadata) *extractor.ContainerImageMetadata { 126 if cim == nil { 127 return nil 128 } 129 var layerMetadata []*extractor.LayerMetadata 130 for _, lm := range cim.GetLayerMetadata() { 131 layerMetadata = append(layerMetadata, layerMetadataToStruct(lm)) 132 } 133 baseImages := [][]*extractor.BaseImageDetails{ 134 // The first base image is always empty. 135 []*extractor.BaseImageDetails{}, 136 } 137 baseImageChains := cim.GetBaseImageChains() 138 if len(baseImageChains) > 1 { 139 for _, bic := range baseImageChains[1:] { 140 chainID, err := digest.Parse(bic.GetChainId()) 141 if err != nil { 142 log.Errorf("Failed to parse chain ID %q: %v", bic.GetChainId(), err) 143 continue 144 } 145 146 var baseImageDetails []*extractor.BaseImageDetails 147 for _, bid := range bic.GetBaseImages() { 148 baseImageDetails = append(baseImageDetails, baseImageDetailsToStruct(bid, chainID)) 149 } 150 baseImages = append(baseImages, baseImageDetails) 151 } 152 } 153 154 return &extractor.ContainerImageMetadata{ 155 Index: int(cim.GetIndex()), 156 OSInfo: cim.GetOsInfo(), 157 LayerMetadata: layerMetadata, 158 BaseImages: baseImages, 159 } 160 }