github.com/google/osv-scalibr@v0.4.1/annotator/ffa/unknownbinariesanno/filterknownbinaries.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 unknownbinariesanno removes all packages extracted by unknown binaries
    16  // filters out the known binaries, and records the remaining as a finding.
    17  package unknownbinariesanno
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"slices"
    23  
    24  	"github.com/google/osv-scalibr/annotator"
    25  	"github.com/google/osv-scalibr/annotator/ffa/unknownbinariesanno/internal/apkfilter"
    26  	"github.com/google/osv-scalibr/annotator/ffa/unknownbinariesanno/internal/dpkgfilter"
    27  	"github.com/google/osv-scalibr/annotator/ffa/unknownbinariesanno/internal/filter"
    28  	"github.com/google/osv-scalibr/extractor"
    29  	"github.com/google/osv-scalibr/extractor/filesystem/ffa/unknownbinariesextr"
    30  	"github.com/google/osv-scalibr/inventory"
    31  	"github.com/google/osv-scalibr/plugin"
    32  )
    33  
    34  // Name of the plugin
    35  const Name = "ffa/unknownbinaries"
    36  
    37  // List of filters to apply to exclude known binaries
    38  var filters = []filter.Filter{
    39  	dpkgfilter.DpkgFilter{},
    40  	apkfilter.ApkFilter{},
    41  }
    42  
    43  // Annotator further processes the UnknownBinaryExtractor
    44  type Annotator struct {
    45  }
    46  
    47  // New returns a new Annotator.
    48  func New() annotator.Annotator {
    49  	return &Annotator{}
    50  }
    51  
    52  // Annotate filters out binaries extracted by unknwonbinaries extractor that can be accounted for by other
    53  // inventories or metadata on the FS.
    54  func (anno *Annotator) Annotate(ctx context.Context, input *annotator.ScanInput, inv *inventory.Inventory) error {
    55  	unknownBinariesSet := map[string]*extractor.Package{}
    56  	filteredPackages := make([]*extractor.Package, 0, len(inv.Packages))
    57  	for _, e := range inv.Packages {
    58  		if !slices.Contains(e.Plugins, unknownbinariesextr.Name) {
    59  			filteredPackages = append(filteredPackages, e)
    60  			continue
    61  		}
    62  
    63  		unknownBinariesSet[e.Locations[0]] = e
    64  	}
    65  
    66  	// First account for all the files we have successfully extracted.
    67  	for _, e := range filteredPackages {
    68  		for _, location := range e.Locations {
    69  			delete(unknownBinariesSet, location)
    70  		}
    71  	}
    72  
    73  	// Remove all unknown binary packages from output packages
    74  	inv.Packages = filteredPackages
    75  
    76  	// Two sets of filters, one with a hashset that gets elements deleted out of, and another with a simple loop
    77  
    78  	// Hash set filter
    79  	for _, f := range filters {
    80  		err := f.HashSetFilter(ctx, input.ScanRoot.FS, unknownBinariesSet)
    81  		if err != nil {
    82  			return fmt.Errorf("%s halted at %q (%q) because %w", anno.Name(), input.ScanRoot.Path, f.Name(), err)
    83  		}
    84  	}
    85  
    86  	// Loop Filter
    87  RemainingPathsLoop:
    88  	for p, val := range unknownBinariesSet {
    89  		for _, f := range filters {
    90  			if f.ShouldExclude(ctx, input.ScanRoot.FS, p) {
    91  				continue RemainingPathsLoop
    92  			}
    93  		}
    94  
    95  		// TODO(b/400910349): We are currently readding it as packages, but eventually we would want a separate type
    96  		// as this information does not behave like packages.
    97  		inv.Packages = append(inv.Packages, val)
    98  	}
    99  
   100  	return nil
   101  }
   102  
   103  var _ annotator.Annotator = &Annotator{}
   104  
   105  // Name returns the name of the enricher.
   106  func (*Annotator) Name() string {
   107  	return Name
   108  }
   109  
   110  // Version returns the version of the enricher.
   111  func (*Annotator) Version() int {
   112  	return 0
   113  }
   114  
   115  // Requirements returns the requirements of the enricher.
   116  func (*Annotator) Requirements() *plugin.Capabilities {
   117  	return &plugin.Capabilities{}
   118  }
   119  
   120  // RequiredPlugins returns the names of the plugins required by the enricher.
   121  func (*Annotator) RequiredPlugins() []string {
   122  	return []string{unknownbinariesextr.Name}
   123  }