Skip to content

Commit ed37197

Browse files
authored
Merge pull request #1677 from hectorj2f/change_max_allowed_build_age
scan: make max db allowed build age configurable
2 parents b4c3bf9 + aaffeec commit ed37197

File tree

5 files changed

+51
-15
lines changed

5 files changed

+51
-15
lines changed

docs/cmd/wolfictl_scan.md

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -94,18 +94,19 @@ wolfictl scan package1 package2 --remote
9494
### Options
9595

9696
```
97-
-a, --advisories-repo-dir string directory containing the advisories repository
98-
-f, --advisory-filter string exclude vulnerability matches that are referenced from the specified set of advisories (resolved|all|concluded)
99-
--build-log treat input as a package build log file (or a directory that contains a packages.log file)
100-
-D, --disable-sbom-cache don't use the SBOM cache
101-
--distro string distro to use during vulnerability matching (default "wolfi")
102-
-h, --help help for scan
103-
--local-file-grype-db string import a local grype db file
104-
-o, --output string output format (outline|json), defaults to outline
105-
-r, --remote treat input(s) as the name(s) of package(s) in the Wolfi package repository to download and scan the latest versions of
106-
--require-zero exit 1 if any vulnerabilities are found
107-
-s, --sbom treat input(s) as SBOM(s) of APK(s) instead of as actual APK(s)
108-
--use-cpes turn on all CPE matching in Grype
97+
-a, --advisories-repo-dir string directory containing the advisories repository
98+
-f, --advisory-filter string exclude vulnerability matches that are referenced from the specified set of advisories (resolved|all|concluded)
99+
--build-log treat input as a package build log file (or a directory that contains a packages.log file)
100+
-D, --disable-sbom-cache don't use the SBOM cache
101+
--distro string distro to use during vulnerability matching (default "wolfi")
102+
-h, --help help for scan
103+
--local-file-grype-db string import a local grype db file
104+
--max-allowed-built-age duration Max allowed age for vulnerability database, age being the time since it was built. Default max age is 120h (or five days) (default 120h0m0s)
105+
-o, --output string output format (outline|json), defaults to outline
106+
-r, --remote treat input(s) as the name(s) of package(s) in the Wolfi package repository to download and scan the latest versions of
107+
--require-zero exit 1 if any vulnerabilities are found
108+
-s, --sbom treat input(s) as SBOM(s) of APK(s) instead of as actual APK(s)
109+
--use-cpes turn on all CPE matching in Grype
109110
```
110111

111112
### Options inherited from parent commands

docs/man/man1/wolfictl-scan.1

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,10 @@ found and the \-\-require\-zero flag is specified.
134134
\fB\-\-local\-file\-grype\-db\fP=""
135135
import a local grype db file
136136

137+
.PP
138+
\fB\-\-max\-allowed\-built\-age\fP=120h0m0s
139+
Max allowed age for vulnerability database, age being the time since it was built. Default max age is 120h (or five days)
140+
137141
.PP
138142
\fB\-o\fP, \fB\-\-output\fP=""
139143
output format (outline|json), defaults to outline

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ require (
6868
require (
6969
github.com/anchore/go-logger v0.0.0-20250318195838-07ae343dd722
7070
github.com/chainguard-dev/advisory-schema v0.37.12
71+
github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b
7172
github.com/spf13/afero v1.14.0
7273
)
7374

@@ -206,7 +207,6 @@ require (
206207
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
207208
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20210315223345-82c243799c99 // indirect
208209
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect
209-
github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b // indirect
210210
github.com/hashicorp/errwrap v1.1.0 // indirect
211211
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
212212
github.com/hashicorp/go-getter v1.7.8 // indirect

pkg/cli/scan.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"sort"
1515
"strings"
1616
"sync"
17+
"time"
1718

1819
"chainguard.dev/apko/pkg/apk/apk"
1920
"chainguard.dev/apko/pkg/apk/auth"
@@ -235,6 +236,9 @@ func scanEverything(ctx context.Context, p *scanParams, inputs []string, advGett
235236
opts := scan.DefaultOptions
236237
opts.UseCPEs = p.useCPEMatching
237238
opts.PathOfDatabaseArchiveToImport = p.localDBFilePath
239+
if p.dbMaxAllowedBuildAge > 0 {
240+
opts.MaxAllowedBuildAge = p.dbMaxAllowedBuildAge
241+
}
238242

239243
// Immediately start a goroutine, so we can initialize the vulnerability database.
240244
// Once that's finished, we will start to pull sboms off of done as they become ready.
@@ -338,6 +342,7 @@ type scanParams struct {
338342
disableSBOMCache bool
339343
remoteScanning bool
340344
useCPEMatching bool
345+
dbMaxAllowedBuildAge time.Duration
341346
}
342347

343348
func (p *scanParams) addFlagsTo(cmd *cobra.Command) {
@@ -352,6 +357,7 @@ func (p *scanParams) addFlagsTo(cmd *cobra.Command) {
352357
cmd.Flags().BoolVarP(&p.disableSBOMCache, "disable-sbom-cache", "D", false, "don't use the SBOM cache")
353358
cmd.Flags().BoolVarP(&p.remoteScanning, "remote", "r", false, "treat input(s) as the name(s) of package(s) in the Wolfi package repository to download and scan the latest versions of")
354359
cmd.Flags().BoolVar(&p.useCPEMatching, "use-cpes", false, "turn on all CPE matching in Grype")
360+
cmd.Flags().DurationVar(&p.dbMaxAllowedBuildAge, "max-allowed-built-age", 120*time.Hour, "Max allowed age for vulnerability database, age being the time since it was built. Default max age is 120h (or five days)")
355361
}
356362

357363
func (p *scanParams) resolveInputsToScan(ctx context.Context, args []string) (inputs []string, cleanup func() error, err error) {

pkg/scan/apk.go

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,16 @@ import (
3737
sbomSyft "github.com/anchore/syft/syft/sbom"
3838
"github.com/chainguard-dev/clog"
3939
"github.com/charmbracelet/log"
40+
"github.com/hako/durafmt"
4041
"github.com/spf13/afero"
4142
anchorelogger "github.com/wolfi-dev/wolfictl/pkg/anchorelog"
4243
"github.com/wolfi-dev/wolfictl/pkg/sbom"
4344
)
4445

4546
const (
4647
mavenSearchBaseURL = "https://search.maven.org/solrsearch/select"
48+
49+
maxRecommendedBuildAge = 48 * time.Hour
4750
)
4851

4952
var DefaultGrypeDBDir = path.Join(xdg.CacheHome, "wolfictl", "grype", "db")
@@ -166,14 +169,23 @@ type Options struct {
166169
// except for testing purposes.
167170
DisableDatabaseAgeValidation bool
168171

172+
// MaxAllowedBuildAge defines the maximum allowed age for the vulnerability database.
173+
// If the database is older than this duration, it will be considered invalid unless
174+
// DisableDatabaseAgeValidation is set to true. If not specified, the default value
175+
// of 48 hours will be used.
176+
MaxAllowedBuildAge time.Duration
177+
169178
// DisableSBOMCache controls whether the scanner will cache SBOMs generated from
170179
// APKs. If true, the scanner will not cache SBOMs or use existing cached SBOMs.
171180
DisableSBOMCache bool
172181
}
173182

174183
// DefaultOptions is the recommended default configuration for a new Scanner.
175184
// These options are suitable for most use scanning cases.
176-
var DefaultOptions = Options{}
185+
var DefaultOptions = Options{
186+
// TODO(hectorj2f): This is a temporary change to 120h, ideally we recommend to set that maximum built age to 48h.
187+
MaxAllowedBuildAge: 120 * time.Hour,
188+
}
177189

178190
// NewScanner initializes the grype DB for reuse across multiple scans.
179191
func NewScanner(opts Options) (*Scanner, error) {
@@ -182,11 +194,16 @@ func NewScanner(opts Options) (*Scanner, error) {
182194
dbDestDir = DefaultGrypeDBDir
183195
}
184196

197+
maxAllowedBuildAge := opts.MaxAllowedBuildAge
198+
if maxAllowedBuildAge == 0 {
199+
maxAllowedBuildAge = 120 * time.Hour
200+
}
201+
185202
installCfg := installation.Config{
186203
DBRootDir: dbDestDir,
187204
ValidateChecksum: true,
188205
ValidateAge: !opts.DisableDatabaseAgeValidation,
189-
MaxAllowedBuiltAge: 48 * time.Hour,
206+
MaxAllowedBuiltAge: maxAllowedBuildAge,
190207
UpdateCheckMaxFrequency: 1 * time.Hour,
191208
}
192209

@@ -230,6 +247,14 @@ func NewScanner(opts Options) (*Scanner, error) {
230247
return nil, fmt.Errorf("failed to load vulnerability database: %w", err)
231248
}
232249

250+
// built time is defined in UTC,
251+
// we should compare it against UTC
252+
now := time.Now().UTC()
253+
age := now.Sub(dbStatus.Built)
254+
if age > maxRecommendedBuildAge {
255+
fmt.Fprintf(os.Stdout, "WARNING: the vulnerability database was built %s ago (max allowed age is %s but the recommended value is %s)\n", durafmt.ParseShort(age), durafmt.ParseShort(maxAllowedBuildAge), durafmt.ParseShort(maxRecommendedBuildAge))
256+
}
257+
233258
if checksum == "" {
234259
metadata, err := v6.ReadImportMetadata(afero.NewOsFs(), filepath.Dir(dbStatus.Path))
235260
if err != nil {

0 commit comments

Comments
 (0)