Skip to content

Commit 2586628

Browse files
erikvargacopybara-github
authored andcommitted
Move inventories + findings under a top-level struct inside ScanResults.
This allows us to add new result types for things that are not software packages or security findings (e.g. running processes, open ports). Instead of returning just packages, extractor plugins now return the generic inventory type which allows them to extract more inventory types such as secrets in the future. Note that we still use the software package struct to store non-software inventory such as containerd runtimes. Moving that to a separate type will be done in a follow-up change. PiperOrigin-RevId: 733262169
1 parent b93cd31 commit 2586628

File tree

198 files changed

+4237
-3842
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

198 files changed

+4237
-3842
lines changed

artifact/image/layerscanning/trace/trace.go

+40-39
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424

2525
"github.com/google/osv-scalibr/extractor"
2626
"github.com/google/osv-scalibr/extractor/filesystem"
27+
"github.com/google/osv-scalibr/inventory"
2728

2829
scalibrImage "github.com/google/osv-scalibr/artifact/image"
2930
scalibrfs "github.com/google/osv-scalibr/fs"
@@ -53,7 +54,7 @@ type locationAndIndex struct {
5354
//
5455
// Note that a precondition of this algorithm is that the chain layers are ordered by order of
5556
// creation.
56-
func PopulateLayerDetails(ctx context.Context, inventory []*extractor.Inventory, chainLayers []scalibrImage.ChainLayer, config *filesystem.Config) {
57+
func PopulateLayerDetails(ctx context.Context, inventory inventory.Inventory, chainLayers []scalibrImage.ChainLayer, config *filesystem.Config) {
5758
chainLayerDetailsList := []*extractor.LayerDetails{}
5859

5960
// Create list of layer details struct to be referenced by inventory.
@@ -84,77 +85,77 @@ func PopulateLayerDetails(ctx context.Context, inventory []*extractor.Inventory,
8485
}
8586
}
8687

87-
// locationIndexToInventory is used as an inventory cache to avoid re-extracting the same
88-
// inventory from a file multiple times.
89-
locationIndexToInventory := map[locationAndIndex][]*extractor.Inventory{}
88+
// locationIndexToPackages is used as a package cache to avoid re-extracting the same
89+
// package from a file multiple times.
90+
locationIndexToPackages := map[locationAndIndex][]*extractor.Package{}
9091
lastLayerIndex := len(chainLayers) - 1
9192

92-
for _, inv := range inventory {
93+
for _, pkg := range inventory.Packages {
9394
layerDetails := chainLayerDetailsList[lastLayerIndex]
94-
invExtractor, isFilesystemExtractor := inv.Extractor.(filesystem.Extractor)
95+
pkgExtractor, isFilesystemExtractor := pkg.Extractor.(filesystem.Extractor)
9596

96-
// Only filesystem extractors are supported for layer scanning. Also, if the inventory has no
97+
// Only filesystem extractors are supported for layer scanning. Also, if the package has no
9798
// locations, it cannot be traced.
98-
isInventoryTraceable := isFilesystemExtractor && len(inv.Locations) > 0
99-
if !isInventoryTraceable {
99+
isPackageTraceable := isFilesystemExtractor && len(pkg.Locations) > 0
100+
if !isPackageTraceable {
100101
continue
101102
}
102103

103104
var foundOrigin bool
104-
fileLocation := inv.Locations[0]
105+
fileLocation := pkg.Locations[0]
105106
lastScannedLayerIndex := len(chainLayers) - 1
106107

107-
// Go backwards through the chain layers and find the first layer where the inventory is not
108-
// present. Such layer is the layer in which the inventory was introduced. If the inventory is
108+
// Go backwards through the chain layers and find the first layer where the package is not
109+
// present. Such layer is the layer in which the package was introduced. If the package is
109110
// present in all layers, then it means it was introduced in the first layer.
110111
for i := len(chainLayers) - 2; i >= 0; i-- {
111112
oldChainLayer := chainLayers[i]
112113

113-
invLocationAndIndex := locationAndIndex{
114+
pkgLocationAndIndex := locationAndIndex{
114115
location: fileLocation,
115116
index: i,
116117
}
117118

118-
var oldInventory []*extractor.Inventory
119-
if cachedInventory, ok := locationIndexToInventory[invLocationAndIndex]; ok {
120-
oldInventory = cachedInventory
119+
var oldPackages []*extractor.Package
120+
if cachedPackages, ok := locationIndexToPackages[pkgLocationAndIndex]; ok {
121+
oldPackages = cachedPackages
121122
} else if _, err := oldChainLayer.FS().Stat(fileLocation); errors.Is(err, fs.ErrNotExist) {
122123
// Check if file still exist in this layer, if not skip extraction.
123124
// This is both an optimization, and avoids polluting the log output with false file not found errors.
124-
oldInventory = []*extractor.Inventory{}
125-
} else if filesExistInLayer(oldChainLayer, inv.Locations) {
125+
oldPackages = []*extractor.Package{}
126+
} else if filesExistInLayer(oldChainLayer, pkg.Locations) {
126127
// Update the extractor config to use the files from the current layer.
127128
// We only take extract the first location because other locations are derived from the initial
128129
// extraction location. If other locations can no longer be determined from the first location
129130
// they should not be included here, and the trace for those packages stops here.
130-
updateExtractorConfig([]string{fileLocation}, invExtractor, oldChainLayer.FS())
131+
updateExtractorConfig([]string{fileLocation}, pkgExtractor, oldChainLayer.FS())
131132

132-
var err error
133133
// Runs SCALIBR extraction on the file of interest in oldChainLayer.
134-
oldInventory, _, err = filesystem.Run(ctx, config)
134+
oldInv, _, err := filesystem.Run(ctx, config)
135+
oldPackages = oldInv.Packages
135136
if err != nil {
136137
break
137138
}
138139
} else {
139-
// If none of the files from the inventory are present in the underlying layer, then there
140-
// will be no difference in the extracted inventory from oldChainLayer, so extraction can be
141-
// skipped in the chain layer. This is an optimization to avoid extracting the same inventory
140+
// If none of the files from the packages are present in the underlying layer, then there
141+
// will be no difference in the extracted packages from oldChainLayer, so extraction can be
142+
// skipped in the chain layer. This is an optimization to avoid extracting the same package
142143
// multiple times.
143144
continue
144145
}
145146

146-
// Cache the inventory for future use.
147-
locationIndexToInventory[invLocationAndIndex] = oldInventory
147+
// Cache the packages for future use.
148+
locationIndexToPackages[pkgLocationAndIndex] = oldPackages
148149

149150
foundPackage := false
150-
for _, oldInv := range oldInventory {
151-
if areInventoriesEqual(inv, oldInv) {
151+
for _, oldPKG := range oldPackages {
152+
if arePackagesEqual(pkg, oldPKG) {
152153
foundPackage = true
153154
break
154155
}
155156
}
156157

157-
// If the inventory is not present in the old layer, then it was introduced in the previous layer we actually scanned
158+
// If the package is not present in the old layer, then it was introduced in the previous layer we actually scanned
158159
if !foundPackage {
159160
layerDetails = chainLayerDetailsList[lastScannedLayerIndex]
160161
foundOrigin = true
@@ -165,35 +166,35 @@ func PopulateLayerDetails(ctx context.Context, inventory []*extractor.Inventory,
165166
lastScannedLayerIndex = i
166167
}
167168

168-
// If the inventory is present in every layer, then it means it was introduced in the first
169+
// If the package is present in every layer, then it means it was introduced in the first
169170
// layer.
170171
if !foundOrigin {
171172
layerDetails = chainLayerDetailsList[0]
172173
}
173-
inv.LayerDetails = layerDetails
174+
pkg.LayerDetails = layerDetails
174175
}
175176
}
176177

177-
// areInventoriesEqual checks if two inventories are equal. It does this by comparing the PURLs and
178-
// the locations of the inventories.
179-
func areInventoriesEqual(inv1 *extractor.Inventory, inv2 *extractor.Inventory) bool {
180-
if inv1.Extractor == nil || inv2.Extractor == nil {
178+
// arePackagesEqual checks if two packages are equal. It does this by comparing the PURLs and
179+
// the locations of the packages.
180+
func arePackagesEqual(pkg1 *extractor.Package, pkg2 *extractor.Package) bool {
181+
if pkg1.Extractor == nil || pkg2.Extractor == nil {
181182
return false
182183
}
183184

184185
// Check if the PURLs are equal.
185-
purl1 := inv1.Extractor.ToPURL(inv1)
186-
purl2 := inv2.Extractor.ToPURL(inv2)
186+
purl1 := pkg1.Extractor.ToPURL(pkg1)
187+
purl2 := pkg2.Extractor.ToPURL(pkg2)
187188

188189
if purl1.String() != purl2.String() {
189190
return false
190191
}
191192

192193
// Check if the locations are equal.
193-
locations1 := inv1.Locations[:]
194+
locations1 := pkg1.Locations[:]
194195
sort.Strings(locations1)
195196

196-
locations2 := inv2.Locations[:]
197+
locations2 := pkg2.Locations[:]
197198
sort.Strings(locations2)
198199

199200
if !slices.Equal(locations1, locations2) {

0 commit comments

Comments
 (0)