22package config
33
44import (
5- "errors"
6- "fmt"
7- "os"
8- "path/filepath"
95 "slices"
10- "strings"
116 "time"
127
13- "github.com/BurntSushi/toml"
148 "github.com/google/osv-scanner/v2/internal/cmdlogger"
159 "github.com/google/osv-scanner/v2/internal/imodels"
1610)
1711
1812var OSVScannerConfigName = "osv-scanner.toml"
1913
20- type Manager struct {
21- // Override to replace all other configs
22- OverrideConfig * Config
23- // Config to use if no config file is found alongside manifests
24- DefaultConfig Config
25- // Cache to store loaded configs
26- ConfigMap map [string ]Config
27- }
28-
2914type Config struct {
3015 IgnoredVulns []* IgnoreEntry `toml:"IgnoredVulns"`
3116 PackageOverrides []PackageOverrideEntry `toml:"PackageOverrides"`
@@ -35,18 +20,6 @@ type Config struct {
3520 LoadPath string `toml:"-"`
3621}
3722
38- func (c * Config ) UnusedIgnoredVulns () []* IgnoreEntry {
39- unused := make ([]* IgnoreEntry , 0 , len (c .IgnoredVulns ))
40-
41- for _ , entry := range c .IgnoredVulns {
42- if ! entry .Used {
43- unused = append (unused , entry )
44- }
45- }
46-
47- return unused
48- }
49-
5023type IgnoreEntry struct {
5124 ID string `toml:"id"`
5225 IgnoreUntil time.Time `toml:"ignoreUntil"`
@@ -101,6 +74,18 @@ type License struct {
10174 Ignore bool `toml:"ignore"`
10275}
10376
77+ func (c * Config ) UnusedIgnoredVulns () []* IgnoreEntry {
78+ unused := make ([]* IgnoreEntry , 0 , len (c .IgnoredVulns ))
79+
80+ for _ , entry := range c .IgnoredVulns {
81+ if ! entry .Used {
82+ unused = append (unused , entry )
83+ }
84+ }
85+
86+ return unused
87+ }
88+
10489func (c * Config ) ShouldIgnore (vulnID string ) (bool , * IgnoreEntry ) {
10590 index := slices .IndexFunc (c .IgnoredVulns , func (e * IgnoreEntry ) bool { return e .ID == vulnID })
10691 if index == - 1 {
@@ -156,118 +141,6 @@ func shouldIgnoreTimestamp(ignoreUntil time.Time) bool {
156141 return ignoreUntil .After (time .Now ())
157142}
158143
159- // UseOverride updates the Manager to use the config at the given path in place
160- // of any other config files that would be loaded when calling Get
161- func (c * Manager ) UseOverride (configPath string ) error {
162- config , configErr := tryLoadConfig (configPath )
163- if configErr != nil {
164- return configErr
165- }
166- c .OverrideConfig = & config
167-
168- return nil
169- }
170-
171- // Get returns the appropriate config to use based on the targetPath
172- func (c * Manager ) Get (targetPath string ) Config {
173- if c .OverrideConfig != nil {
174- return * c .OverrideConfig
175- }
176-
177- configPath , err := normalizeConfigLoadPath (targetPath )
178- if err != nil {
179- // TODO: This can happen when target is not a file (e.g. Docker container, git hash...etc.)
180- // Figure out a more robust way to load config from non files
181- // r.PrintErrorf("Can't find config path: %s\n", err)
182- return Config {}
183- }
184-
185- config , alreadyExists := c .ConfigMap [configPath ]
186- if alreadyExists {
187- return config
188- }
189-
190- config , configErr := tryLoadConfig (configPath )
191- if configErr == nil {
192- cmdlogger .Infof ("Loaded filter from: %s" , config .LoadPath )
193- } else {
194- // anything other than the config file not existing is most likely due to an invalid config file
195- if ! errors .Is (configErr , os .ErrNotExist ) {
196- cmdlogger .Errorf ("Ignored invalid config file at %s because: %v" , configPath , configErr )
197- }
198- // If config doesn't exist, use the default config
199- config = c .DefaultConfig
200- }
201- c .ConfigMap [configPath ] = config
202-
203- return config
204- }
205-
206- func (c * Manager ) GetUnusedIgnoreEntries () map [string ][]* IgnoreEntry {
207- m := make (map [string ][]* IgnoreEntry )
208-
209- for _ , config := range c .ConfigMap {
210- unusedEntries := config .UnusedIgnoredVulns ()
211-
212- if len (unusedEntries ) > 0 {
213- m [config .LoadPath ] = unusedEntries
214- }
215- }
216-
217- if c .OverrideConfig != nil {
218- unusedEntries := c .OverrideConfig .UnusedIgnoredVulns ()
219-
220- if len (unusedEntries ) > 0 {
221- m [c .OverrideConfig .LoadPath ] = unusedEntries
222- }
223- }
224-
225- return m
226- }
227-
228- // Finds the containing folder of `target`, then appends osvScannerConfigName
229- func normalizeConfigLoadPath (target string ) (string , error ) {
230- stat , err := os .Stat (target )
231- if err != nil {
232- return "" , fmt .Errorf ("failed to stat target: %w" , err )
233- }
234-
235- var containingFolder string
236- if ! stat .IsDir () {
237- containingFolder = filepath .Dir (target )
238- } else {
239- containingFolder = target
240- }
241- configPath := filepath .Join (containingFolder , OSVScannerConfigName )
242-
243- return configPath , nil
244- }
245-
246- // tryLoadConfig attempts to parse the config file at the given path as TOML,
247- // returning the Config object if successful or otherwise the error
248- func tryLoadConfig (configPath string ) (Config , error ) {
249- config := Config {}
250- m , err := toml .DecodeFile (configPath , & config )
251- if err == nil {
252- unknownKeys := m .Undecoded ()
253-
254- if len (unknownKeys ) > 0 {
255- keys := make ([]string , 0 , len (unknownKeys ))
256-
257- for _ , key := range unknownKeys {
258- keys = append (keys , key .String ())
259- }
260-
261- return Config {}, fmt .Errorf ("unknown keys in config file: %s" , strings .Join (keys , ", " ))
262- }
263-
264- config .LoadPath = configPath
265- config .warnAboutDuplicates ()
266- }
267-
268- return config , err
269- }
270-
271144func (c * Config ) warnAboutDuplicates () {
272145 seen := make (map [string ]struct {})
273146
0 commit comments