1
0
Fork 0
mirror of https://github.com/gocsaf/csaf.git synced 2025-12-22 18:15:42 +01:00

Merge pull request #414 from csaf-poc/checker-interval

Checker: Make time range configurable to check advisories from
This commit is contained in:
JanHoefelmeyer 2023-07-28 09:53:41 +02:00 committed by GitHub
commit 8aed2c034e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 85 additions and 28 deletions

View file

@ -13,7 +13,9 @@ import (
"errors"
"fmt"
"net/http"
"time"
"github.com/csaf-poc/csaf_distribution/v2/internal/models"
"github.com/csaf-poc/csaf_distribution/v2/internal/options"
)
@ -35,6 +37,7 @@ type config struct {
Verbose bool `long:"verbose" short:"v" description:"Verbose output" toml:"verbose"`
Rate *float64 `long:"rate" short:"r" description:"The average upper limit of https operations per second (defaults to unlimited)" toml:"rate"`
Years *uint `long:"years" short:"y" description:"Number of years to look back from now" value-name:"YEARS" toml:"years"`
Range *models.TimeRange `long:"timerange" short:"t" description:"RANGE of time from which advisories to download" value-name:"RANGE" toml:"timerange"`
ExtraHeader http.Header `long:"header" short:"H" description:"One or more extra HTTP header fields" toml:"header"`
RemoteValidator string `long:"validator" description:"URL to validate documents remotely" value-name:"URL" toml:"validator"`
@ -44,6 +47,7 @@ type config struct {
Config string `short:"c" long:"config" description:"Path to config TOML file" value-name:"TOML-FILE" toml:"-"`
clientCerts []tls.Certificate
ageAccept func(time.Time) bool
}
// configPaths are the potential file locations of the config file.
@ -102,6 +106,16 @@ func (cfg *config) protectedAccess() bool {
// prepare prepares internal state of a loaded configuration.
func (cfg *config) prepare() error {
// Load client certs.
if err := cfg.prepareCertificates(); err != nil {
return err
}
return cfg.prepareTimeRangeFilter()
}
// prepareCertificates loads the client side certificates used by the HTTP client.
func (cfg *config) prepareCertificates() error {
switch hasCert, hasKey := cfg.ClientCert != nil, cfg.ClientKey != nil; {
case hasCert && !hasKey || !hasCert && hasKey:
@ -116,3 +130,27 @@ func (cfg *config) prepare() error {
}
return nil
}
// acceptYears returns a filter that accepts advisories from the last years.
func acceptYears(years uint) func(time.Time) bool {
good := time.Now().AddDate(-int(years), 0, 0)
return func(t time.Time) bool {
return !t.Before(good)
}
}
// prepareTimeRangeFilter sets up the filter in which time range
// advisory should be considered for checking.
func (cfg *config) prepareTimeRangeFilter() error {
switch {
case cfg.Years != nil && cfg.Range != nil:
return errors.New(`"timerange" and "years" are both configured: only one allowed`)
case cfg.Years != nil:
cfg.ageAccept = acceptYears(*cfg.Years)
case cfg.Range != nil:
cfg.ageAccept = cfg.Range.Contains
}
return nil
}

View file

@ -44,7 +44,6 @@ type processor struct {
validator csaf.RemoteValidator
client util.Client
unauthClient util.Client
ageAccept func(time.Time) bool
redirects map[string][]string
noneTLS util.Set[string]
@ -187,7 +186,6 @@ func newProcessor(cfg *config) (*processor, error) {
cfg: cfg,
alreadyChecked: map[string]whereType{},
expr: util.NewPathEval(),
ageAccept: ageAccept(cfg),
validator: validator,
labelChecker: labelChecker{
advisories: map[csaf.TLPLabel]util.Set[string]{},
@ -204,16 +202,6 @@ func (p *processor) close() {
}
}
func ageAccept(cfg *config) func(time.Time) bool {
if cfg.Years == nil {
return nil
}
good := time.Now().AddDate(-int(*cfg.Years), 0, 0)
return func(t time.Time) bool {
return !t.Before(good)
}
}
// clean clears the fields values of the given processor.
func (p *processor) clean() {
p.redirects = nil
@ -557,8 +545,8 @@ func (p *processor) rolieFeedEntries(feed string) ([]csaf.AdvisoryFile, error) {
rfeed.Entries(func(entry *csaf.Entry) {
// Filter if we have date checking.
if p.ageAccept != nil {
if pub := time.Time(entry.Published); !pub.IsZero() && !p.ageAccept(pub) {
if p.cfg.ageAccept != nil {
if pub := time.Time(entry.Published); !pub.IsZero() && !p.cfg.ageAccept(pub) {
return
}
}
@ -669,7 +657,7 @@ func (p *processor) integrity(
if m := yearFromURL.FindStringSubmatch(u); m != nil {
year, _ := strconv.Atoi(m[1])
// Check if we are in checking time interval.
if p.ageAccept != nil && !p.ageAccept(
if p.cfg.ageAccept != nil && !p.cfg.ageAccept(
time.Date(
year, 12, 31, // Assume last day of year.
23, 59, 59, 0, // 23:59:59
@ -975,7 +963,7 @@ func (p *processor) checkChanges(base string, mask whereType) error {
return nil, nil, err
}
// Apply date range filtering.
if p.ageAccept != nil && !p.ageAccept(t) {
if p.cfg.ageAccept != nil && !p.cfg.ageAccept(t) {
continue
}
path := r[pathColumn]
@ -992,7 +980,7 @@ func (p *processor) checkChanges(base string, mask whereType) error {
if len(files) == 0 {
var filtered string
if p.ageAccept != nil {
if p.cfg.ageAccept != nil {
filtered = " (maybe filtered out by time interval)"
}
p.badChanges.warn("no entries in changes.csv found" + filtered)

View file

@ -16,10 +16,11 @@ Application Options:
-v, --verbose Verbose output
-r, --rate= The average upper limit of https operations per second (defaults to unlimited)
-y, --years=YEARS Number of years to look back from now
-t, --timerange=RANGE RANGE of time from which advisories to download
-H, --header= One or more extra HTTP header fields
--validator=URL URL to validate documents remotely
--validatorcache=FILE FILE to cache remote validations
--validatorpreset= One or more presets to validate remotely (default: mandatory)
--validatorpreset= One or more presets to validate remotely (default: [mandatory])
-c, --config=TOML-FILE Path to config TOML file
Help Options:
@ -48,6 +49,7 @@ insecure = false
verbose = false
# rate # not set by default
# years # not set by default
# timerange # not set by default
# header # not set by default
# validator # not set by default
# validatorcache # not set by default
@ -66,6 +68,35 @@ type 2: error
The checker result is a success if no checks resulted in type 2, and a failure otherwise.
The options `years` and `timerange` allow to only check advisories from a given time interval.
It is only allowed to specify one off them.
`years` looks number of years back from now. `timerange` values allow finer controls:
1. Relative. If the given string follows the rules of being a [Go duration](https://pkg.go.dev/time@go1.20.6#ParseDuration)
the time interval from now minus that duration till now is used.
E.g. `"3h"` means checking the advisories that have changed in the last three hours.
2. Absolute. If the given string is an RFC 3339 date timestamp the time interval between
this date and now is used.
E.g. `"2006-01-02"` means that all files between 2006 January 2nd and now going to be
checked.
Accepted patterns are:
- `"2006-01-02T15:04:05Z"`
- `"2006-01-02T15:04:05+07:00"`
- `"2006-01-02T15:04:05-07:00"`
- `"2006-01-02T15:04:05"`
- `"2006-01-02T15:04"`
- `"2006-01-02T15"`
- `"2006-01-02"`
- `"2006-01"`
- `"2006"`
Missing parts are set to the smallest value possible in that field.
3. Range. Same as 2 but separated by a `,` to span an interval. e.g `2019,2024`
spans an interval from 1st January 2019 to the 1st January of 2024.
All interval boundaries are inclusive.
### Remarks