github.com/google/osv-scalibr@v0.4.1/annotator/osduplicate/osduplicate.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 osduplicate implements utility functions for identifying inventory duplicates found in OS packages.
    16  package osduplicate
    17  
    18  import (
    19  	"strings"
    20  
    21  	"github.com/google/osv-scalibr/extractor"
    22  	scalibrfs "github.com/google/osv-scalibr/fs"
    23  	"github.com/google/osv-scalibr/inventory"
    24  )
    25  
    26  // BuildLocationToPKGsMap sets up a map of package locations (relative to the specified scan root)
    27  // to package pointers from the inventory.
    28  func BuildLocationToPKGsMap(results *inventory.Inventory, scanRoot *scalibrfs.ScanRoot) map[string][]*extractor.Package {
    29  	locationToPKGs := map[string][]*extractor.Package{}
    30  
    31  	// Get root prefix to compare absolute package locations with
    32  	rootPrefix := scanRoot.Path
    33  	if !strings.HasSuffix(rootPrefix, "/") {
    34  		rootPrefix += "/"
    35  	}
    36  pkgLoop:
    37  	for _, pkg := range results.Packages {
    38  		if len(pkg.Locations) == 0 {
    39  			continue
    40  		}
    41  		// Skip packages found by OS extractors since those are not OS duplicates.
    42  		for _, p := range pkg.Plugins {
    43  			if strings.HasPrefix(p, "os/") {
    44  				continue pkgLoop
    45  			}
    46  		}
    47  		// The descriptor file (e.g. lockfile) is always stored in the first element.
    48  		// TODO(b/400910349): Separate locations into a dedicated "descriptor file"
    49  		// and "other files" field.
    50  		loc := pkg.Locations[0]
    51  
    52  		// If ScanConfig.StoreAbsolutePath is on, this will be an absolute path.
    53  		// Convert to relative in these cases.
    54  		// Root starts and ends in a slash while relative paths don't, so this will only
    55  		// take effect for absolute paths.
    56  		loc = strings.TrimPrefix(loc, rootPrefix)
    57  
    58  		if prev, ok := locationToPKGs[loc]; ok {
    59  			locationToPKGs[loc] = append(prev, pkg)
    60  		} else {
    61  			locationToPKGs[loc] = []*extractor.Package{pkg}
    62  		}
    63  	}
    64  	return locationToPKGs
    65  }