github.com/google/osv-scalibr@v0.4.1/annotator/osduplicate/apk/apk.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 apk implements an annotator for language packages that have already been found in 16 // APK OS packages. 17 package apk 18 19 import ( 20 "context" 21 "errors" 22 "fmt" 23 "io/fs" 24 "path" 25 26 "github.com/google/osv-scalibr/annotator" 27 "github.com/google/osv-scalibr/annotator/osduplicate" 28 "github.com/google/osv-scalibr/extractor/filesystem/os/apk/apkutil" 29 "github.com/google/osv-scalibr/inventory" 30 "github.com/google/osv-scalibr/inventory/vex" 31 "github.com/google/osv-scalibr/plugin" 32 ) 33 34 const ( 35 // Name of the Annotator. 36 Name = "vex/os-duplicate/apk" 37 apkInstalledDB = "lib/apk/db/installed" 38 ) 39 40 // Annotator adds annotations to language packages that have already been found in APK OS packages. 41 type Annotator struct{} 42 43 // New returns a new Annotator. 44 func New() annotator.Annotator { return &Annotator{} } 45 46 // Name of the annotator. 47 func (Annotator) Name() string { return Name } 48 49 // Version of the annotator. 50 func (Annotator) Version() int { return 0 } 51 52 // Requirements of the annotator. 53 func (Annotator) Requirements() *plugin.Capabilities { 54 return &plugin.Capabilities{OS: plugin.OSLinux} 55 } 56 57 // Annotate adds annotations to language packages that have already been found in APK OS packages. 58 func (a *Annotator) Annotate(ctx context.Context, input *annotator.ScanInput, results *inventory.Inventory) error { 59 locationToPKGs := osduplicate.BuildLocationToPKGsMap(results, input.ScanRoot) 60 61 f, err := input.ScanRoot.FS.Open(apkInstalledDB) 62 if err != nil { 63 if errors.Is(err, fs.ErrNotExist) { 64 // Nothing to annotate if we're not running on Alpine. 65 return nil 66 } 67 return err 68 } 69 defer f.Close() 70 71 errs := []error{} 72 73 scanner := apkutil.NewScanner(f) 74 for scanner.Scan() { 75 // Return if canceled or exceeding deadline. 76 if err := ctx.Err(); err != nil { 77 errs = append(errs, fmt.Errorf("%s halted at %q because of context error: %w", a.Name(), input.ScanRoot.Path, err)) 78 break 79 } 80 81 record := scanner.Record() 82 83 folder := record["F"] 84 filename := record["R"] 85 86 // if the filePath is not retrievable continue to the next package 87 if folder == "" || filename == "" { 88 continue 89 } 90 91 filePath := path.Join(folder, filename) 92 93 if pkgs, ok := locationToPKGs[filePath]; ok { 94 for _, pkg := range pkgs { 95 pkg.ExploitabilitySignals = append(pkg.ExploitabilitySignals, &vex.PackageExploitabilitySignal{ 96 Plugin: Name, 97 Justification: vex.ComponentNotPresent, 98 MatchesAllVulns: true, 99 }) 100 } 101 } 102 } 103 104 if err := scanner.Err(); err != nil { 105 errs = append(errs, err) 106 } 107 return errors.Join(errs...) 108 }