Skip to content

Commit b9f296c

Browse files
authored
refactor(config): use dedicated files for "config" and "manager" code, and rename method receiver (#2551)
While doing some deduplication for #2534, I found having these in the same file when they have the same receiver name to be confusing so I've moved them to different files and renamed the receiver for `Manager` to be `m`
1 parent 4dfa15e commit b9f296c

File tree

2 files changed

+145
-139
lines changed

2 files changed

+145
-139
lines changed

internal/config/config.go

Lines changed: 12 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,15 @@
22
package config
33

44
import (
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

1812
var 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-
2914
type 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-
5023
type 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+
10489
func (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-
271144
func (c *Config) warnAboutDuplicates() {
272145
seen := make(map[string]struct{})
273146

internal/config/manager.go

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
package config
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"os"
7+
"path/filepath"
8+
"strings"
9+
10+
"github.com/BurntSushi/toml"
11+
"github.com/google/osv-scanner/v2/internal/cmdlogger"
12+
)
13+
14+
type Manager struct {
15+
// Override to replace all other configs
16+
OverrideConfig *Config
17+
// Config to use if no config file is found alongside manifests
18+
DefaultConfig Config
19+
// Cache to store loaded configs
20+
ConfigMap map[string]Config
21+
}
22+
23+
// UseOverride updates the Manager to use the config at the given path in place
24+
// of any other config files that would be loaded when calling Get
25+
func (m *Manager) UseOverride(configPath string) error {
26+
config, configErr := tryLoadConfig(configPath)
27+
if configErr != nil {
28+
return configErr
29+
}
30+
m.OverrideConfig = &config
31+
32+
return nil
33+
}
34+
35+
// Get returns the appropriate config to use based on the targetPath
36+
func (m *Manager) Get(targetPath string) Config {
37+
if m.OverrideConfig != nil {
38+
return *m.OverrideConfig
39+
}
40+
41+
configPath, err := normalizeConfigLoadPath(targetPath)
42+
if err != nil {
43+
// TODO: This can happen when target is not a file (e.g. Docker container, git hash...etc.)
44+
// Figure out a more robust way to load config from non files
45+
// r.PrintErrorf("Can't find config path: %s\n", err)
46+
return Config{}
47+
}
48+
49+
config, alreadyExists := m.ConfigMap[configPath]
50+
if alreadyExists {
51+
return config
52+
}
53+
54+
config, configErr := tryLoadConfig(configPath)
55+
if configErr == nil {
56+
cmdlogger.Infof("Loaded filter from: %s", config.LoadPath)
57+
} else {
58+
// anything other than the config file not existing is most likely due to an invalid config file
59+
if !errors.Is(configErr, os.ErrNotExist) {
60+
cmdlogger.Errorf("Ignored invalid config file at %s because: %v", configPath, configErr)
61+
}
62+
// If config doesn't exist, use the default config
63+
config = m.DefaultConfig
64+
}
65+
m.ConfigMap[configPath] = config
66+
67+
return config
68+
}
69+
70+
func (m *Manager) GetUnusedIgnoreEntries() map[string][]*IgnoreEntry {
71+
entries := make(map[string][]*IgnoreEntry)
72+
73+
for _, config := range m.ConfigMap {
74+
unusedEntries := config.UnusedIgnoredVulns()
75+
76+
if len(unusedEntries) > 0 {
77+
entries[config.LoadPath] = unusedEntries
78+
}
79+
}
80+
81+
if m.OverrideConfig != nil {
82+
unusedEntries := m.OverrideConfig.UnusedIgnoredVulns()
83+
84+
if len(unusedEntries) > 0 {
85+
entries[m.OverrideConfig.LoadPath] = unusedEntries
86+
}
87+
}
88+
89+
return entries
90+
}
91+
92+
// Finds the containing folder of `target`, then appends osvScannerConfigName
93+
func normalizeConfigLoadPath(target string) (string, error) {
94+
stat, err := os.Stat(target)
95+
if err != nil {
96+
return "", fmt.Errorf("failed to stat target: %w", err)
97+
}
98+
99+
var containingFolder string
100+
if !stat.IsDir() {
101+
containingFolder = filepath.Dir(target)
102+
} else {
103+
containingFolder = target
104+
}
105+
configPath := filepath.Join(containingFolder, OSVScannerConfigName)
106+
107+
return configPath, nil
108+
}
109+
110+
// tryLoadConfig attempts to parse the config file at the given path as TOML,
111+
// returning the Config object if successful or otherwise the error
112+
func tryLoadConfig(configPath string) (Config, error) {
113+
config := Config{}
114+
c, err := toml.DecodeFile(configPath, &config)
115+
if err == nil {
116+
unknownKeys := c.Undecoded()
117+
118+
if len(unknownKeys) > 0 {
119+
keys := make([]string, 0, len(unknownKeys))
120+
121+
for _, key := range unknownKeys {
122+
keys = append(keys, key.String())
123+
}
124+
125+
return Config{}, fmt.Errorf("unknown keys in config file: %s", strings.Join(keys, ", "))
126+
}
127+
128+
config.LoadPath = configPath
129+
config.warnAboutDuplicates()
130+
}
131+
132+
return config, err
133+
}

0 commit comments

Comments
 (0)