From e2ab1903e745f3b6642ff97f22457d87f3b4aeb3 Mon Sep 17 00:00:00 2001 From: "Sascha L. Teichmann" Date: Sun, 12 Nov 2023 10:17:28 +0100 Subject: [PATCH 01/12] Support legacy security.txt location as fallback. --- csaf/providermetaloader.go | 96 ++++++++++++++++++++------------------ 1 file changed, 51 insertions(+), 45 deletions(-) diff --git a/csaf/providermetaloader.go b/csaf/providermetaloader.go index 4e4eb494..62e88766 100644 --- a/csaf/providermetaloader.go +++ b/csaf/providermetaloader.go @@ -132,8 +132,7 @@ func (pmdl *ProviderMetadataLoader) Load(domain string) *LoadedProviderMetadata } // Next load the PMDs from security.txt - secURL := "https://" + domain + "/.well-known/security.txt" - secResults := pmdl.loadFromSecurity(secURL) + secResults := pmdl.loadFromSecurity(domain) // Filter out the results which are valid. var secGoods []*LoadedProviderMetadata @@ -199,56 +198,63 @@ func (pmdl *ProviderMetadataLoader) Load(domain string) *LoadedProviderMetadata } // loadFromSecurity loads the PMDs mentioned in the security.txt. -func (pmdl *ProviderMetadataLoader) loadFromSecurity(path string) []*LoadedProviderMetadata { - - res, err := pmdl.client.Get(path) - if err != nil { - pmdl.messages.Add( - HTTPFailed, - fmt.Sprintf("Fetching %q failed: %v", path, err)) - return nil - } - if res.StatusCode != http.StatusOK { - pmdl.messages.Add( - HTTPFailed, - fmt.Sprintf("Fetching %q failed: %s (%d)", path, res.Status, res.StatusCode)) - return nil - } - - // Extract all potential URLs from CSAF. - urls, err := func() ([]string, error) { - defer res.Body.Close() - return ExtractProviderURL(res.Body, true) - }() - - if err != nil { - pmdl.messages.Add( - HTTPFailed, - fmt.Sprintf("Loading %q failed: %v", path, err)) - return nil - } +func (pmdl *ProviderMetadataLoader) loadFromSecurity(domain string) []*LoadedProviderMetadata { + + // If .well-known fails try legacy location. + for _, path := range []string{ + "https://" + domain + "/.well-known/security.txt", + "https://" + domain + "/security.txt", + } { + res, err := pmdl.client.Get(path) + if err != nil { + pmdl.messages.Add( + HTTPFailed, + fmt.Sprintf("Fetching %q failed: %v", path, err)) + continue + } + if res.StatusCode != http.StatusOK { + pmdl.messages.Add( + HTTPFailed, + fmt.Sprintf("Fetching %q failed: %s (%d)", path, res.Status, res.StatusCode)) + continue + } - var loaded []*LoadedProviderMetadata + // Extract all potential URLs from CSAF. + urls, err := func() ([]string, error) { + defer res.Body.Close() + return ExtractProviderURL(res.Body, true) + }() - // Load the URLs -nextURL: - for _, url := range urls { - lpmd := pmdl.loadFromURL(url) - // If loading failed note it down. - if !lpmd.Valid() { - pmdl.messages.AppendUnique(lpmd.Messages) + if err != nil { + pmdl.messages.Add( + HTTPFailed, + fmt.Sprintf("Loading %q failed: %v", path, err)) continue } - // Check for duplicates - for _, l := range loaded { - if l == lpmd { - continue nextURL + + var loaded []*LoadedProviderMetadata + + // Load the URLs + nextURL: + for _, url := range urls { + lpmd := pmdl.loadFromURL(url) + // If loading failed note it down. + if !lpmd.Valid() { + pmdl.messages.AppendUnique(lpmd.Messages) + continue + } + // Check for duplicates + for _, l := range loaded { + if l == lpmd { + continue nextURL + } } + loaded = append(loaded, lpmd) } - loaded = append(loaded, lpmd) - } - return loaded + return loaded + } + return nil } // loadFromURL loads a provider metadata from a given URL. From 0a2b69bd5510ec7b4f6d9489a9b1b1590dd71226 Mon Sep 17 00:00:00 2001 From: "Sascha L. Teichmann" Date: Mon, 13 Nov 2023 09:59:12 +0100 Subject: [PATCH 02/12] Adjust checker, too. --- cmd/csaf_checker/processor.go | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/cmd/csaf_checker/processor.go b/cmd/csaf_checker/processor.go index 8eb64046..39bd1416 100644 --- a/cmd/csaf_checker/processor.go +++ b/cmd/csaf_checker/processor.go @@ -1263,9 +1263,26 @@ func (p *processor) checkProviderMetadata(domain string) bool { // the value of this field. Returns an empty string if no error was encountered, // the errormessage otherwise. func (p *processor) checkSecurity(domain string) string { + var msgs []string + // Try well-known first and fall back to legacy when it fails. + for _, folder := range []string{ + "https://" + domain + "/.well-known/", + "https://" + domain + "/", + } { + msg := p.checkSecurityFolder(folder) + if msg == "" { + break + } + msgs = append(msgs, msg) + } + return strings.Join(msgs, "; ") +} + +// checkSecurityFolder checks the security.txt in a given folder. +func (p *processor) checkSecurityFolder(folder string) string { client := p.httpClient() - path := "https://" + domain + "/.well-known/security.txt" + path := folder + "security.txt" res, err := client.Get(path) if err != nil { return fmt.Sprintf("Fetching %s failed: %v", path, err) @@ -1298,7 +1315,7 @@ func (p *processor) checkSecurity(domain string) string { return fmt.Sprintf("CSAF URL '%s' invalid: %v", u, err) } - base, err := url.Parse("https://" + domain + "/.well-known/") + base, err := url.Parse(folder) if err != nil { return err.Error() } From e27d64e42c09445d0037a2c44de51e05bb7e6a11 Mon Sep 17 00:00:00 2001 From: JanHoefelmeyer Date: Tue, 14 Nov 2023 07:55:53 +0100 Subject: [PATCH 03/12] Add path of offending security.txt to error message since now multiple paths are checked --- cmd/csaf_checker/processor.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmd/csaf_checker/processor.go b/cmd/csaf_checker/processor.go index 39bd1416..f32c6186 100644 --- a/cmd/csaf_checker/processor.go +++ b/cmd/csaf_checker/processor.go @@ -1273,7 +1273,9 @@ func (p *processor) checkSecurity(domain string) string { if msg == "" { break } - msgs = append(msgs, msg) + // Show which security.txt caused this message + lmsg := folder + "security.txt:" + msg + msgs = append(msgs, lmsg) } return strings.Join(msgs, "; ") } From 3935d9aa7ae13b693a62c8221b88a89892eb8168 Mon Sep 17 00:00:00 2001 From: "Sascha L. Teichmann" Date: Mon, 20 Nov 2023 21:53:51 +0100 Subject: [PATCH 04/12] Update cmd/csaf_checker/processor.go Co-authored-by: tschmidtb51 <65305130+tschmidtb51@users.noreply.github.com> --- cmd/csaf_checker/processor.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/csaf_checker/processor.go b/cmd/csaf_checker/processor.go index f32c6186..304d68fd 100644 --- a/cmd/csaf_checker/processor.go +++ b/cmd/csaf_checker/processor.go @@ -1274,7 +1274,7 @@ func (p *processor) checkSecurity(domain string) string { break } // Show which security.txt caused this message - lmsg := folder + "security.txt:" + msg + lmsg := folder + "security.txt: " + msg msgs = append(msgs, lmsg) } return strings.Join(msgs, "; ") From 318c898a83e2f261b4c66961404110e45c3508d3 Mon Sep 17 00:00:00 2001 From: JanHoefelmeyer Date: Tue, 21 Nov 2023 12:09:37 +0100 Subject: [PATCH 05/12] Change: cmd/csaf_checker/processor.go: Seperate check of security.txt under .well-known and legacy location into different messages to improve readability --- cmd/csaf_checker/processor.go | 57 +++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/cmd/csaf_checker/processor.go b/cmd/csaf_checker/processor.go index 304d68fd..ac9cca49 100644 --- a/cmd/csaf_checker/processor.go +++ b/cmd/csaf_checker/processor.go @@ -1262,22 +1262,20 @@ func (p *processor) checkProviderMetadata(domain string) bool { // It checks the existence of the CSAF field in the file content and tries to fetch // the value of this field. Returns an empty string if no error was encountered, // the errormessage otherwise. -func (p *processor) checkSecurity(domain string) string { - var msgs []string - // Try well-known first and fall back to legacy when it fails. - for _, folder := range []string{ - "https://" + domain + "/.well-known/", - "https://" + domain + "/", - } { - msg := p.checkSecurityFolder(folder) - if msg == "" { - break - } - // Show which security.txt caused this message - lmsg := folder + "security.txt: " + msg - msgs = append(msgs, lmsg) - } - return strings.Join(msgs, "; ") +func (p *processor) checkSecurity(domain string, legacy bool) (int, string) { + folder := "https://" + domain + "/" + if !legacy { + folder = folder + ".well-known/" + } + msg := p.checkSecurityFolder(folder) + if msg == "" { + if !legacy { + return 0, "Found valid security.txt within the well-known directory" + } else { + return 2, "Found valid security.txt in the legacy location" + } + } + return 1, folder + "security.txt: " + msg } // checkSecurityFolder checks the security.txt in a given folder. @@ -1410,7 +1408,13 @@ func (p *processor) checkWellknown(domain string) string { func (p *processor) checkWellknownSecurityDNS(domain string) error { warningsW := p.checkWellknown(domain) - warningsS := p.checkSecurity(domain) + // Security check for well known (default) and legacy location + warningsS, sDMessage := p.checkSecurity(domain, false) + // if the security.txt under .well-known was not okay + sLMessage := "" + if warningsS == 1 { + warningsS, sLMessage = p.checkSecurity(domain, true) + } warningsD := p.checkDNS(domain) p.badWellknownMetadata.use() @@ -1418,17 +1422,30 @@ func (p *processor) checkWellknownSecurityDNS(domain string) error { p.badDNSPath.use() var kind MessageType - if warningsS == "" || warningsD == "" || warningsW == "" { + if warningsS != 1 || warningsD == "" || warningsW == "" { kind = WarnType } else { kind = ErrorType } + // Info, Warning or Error depending on kind and warningS + kindSD := kind + if warningsS == 0 { + kindSD = InfoType + } + kindSL := kind + if warningsS == 2 { + kindSL = InfoType + } + if warningsW != "" { p.badWellknownMetadata.add(kind, warningsW) } - if warningsS != "" { - p.badSecurity.add(kind, warningsS) + p.badSecurity.add(kindSD, sDMessage) + // only if the well-known security.txt was not successful: + // report about the legacy location + if warningsS != 0 { + p.badSecurity.add(kindSL, sLMessage) } if warningsD != "" { p.badDNSPath.add(kind, warningsD) From 4a9f8a6f031240cd50b12a4fbff4526cfa9dc792 Mon Sep 17 00:00:00 2001 From: JanHoefelmeyer Date: Tue, 21 Nov 2023 12:14:45 +0100 Subject: [PATCH 06/12] Change: cmd/csaf_checker/processor.go: Improve comment --- cmd/csaf_checker/processor.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/csaf_checker/processor.go b/cmd/csaf_checker/processor.go index ac9cca49..2e61ae8d 100644 --- a/cmd/csaf_checker/processor.go +++ b/cmd/csaf_checker/processor.go @@ -1411,6 +1411,7 @@ func (p *processor) checkWellknownSecurityDNS(domain string) error { // Security check for well known (default) and legacy location warningsS, sDMessage := p.checkSecurity(domain, false) // if the security.txt under .well-known was not okay + // check for a security.txt within its legacy location sLMessage := "" if warningsS == 1 { warningsS, sLMessage = p.checkSecurity(domain, true) From fb7c77b419099c8c215f1d0c432b6417b41dbcc4 Mon Sep 17 00:00:00 2001 From: JanHoefelmeyer Date: Tue, 21 Nov 2023 13:45:46 +0100 Subject: [PATCH 07/12] Remove unnecessary else block --- cmd/csaf_checker/processor.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmd/csaf_checker/processor.go b/cmd/csaf_checker/processor.go index 2e61ae8d..2a5161ce 100644 --- a/cmd/csaf_checker/processor.go +++ b/cmd/csaf_checker/processor.go @@ -1271,9 +1271,8 @@ func (p *processor) checkSecurity(domain string, legacy bool) (int, string) { if msg == "" { if !legacy { return 0, "Found valid security.txt within the well-known directory" - } else { - return 2, "Found valid security.txt in the legacy location" } + return 2, "Found valid security.txt in the legacy location" } return 1, folder + "security.txt: " + msg } From a6bf44f7cced151123b1b47111d958276e1a40c7 Mon Sep 17 00:00:00 2001 From: JanHoefelmeyer Date: Wed, 22 Nov 2023 08:17:05 +0100 Subject: [PATCH 08/12] Removed impossible to achieve condition in reporters --- cmd/csaf_checker/reporters.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/cmd/csaf_checker/reporters.go b/cmd/csaf_checker/reporters.go index 51731e1e..c707a144 100644 --- a/cmd/csaf_checker/reporters.go +++ b/cmd/csaf_checker/reporters.go @@ -251,10 +251,6 @@ func (r *securityReporter) report(p *processor, domain *Domain) { req.message(WarnType, "Performed no in-depth test of security.txt.") return } - if len(p.badSecurity) == 0 { - req.message(InfoType, "Found CSAF entry in security.txt.") - return - } req.Messages = p.badSecurity } From 91ab7f6b1cbc0160457dcd92cfe4ae62997a7cde Mon Sep 17 00:00:00 2001 From: "Sascha L. Teichmann" Date: Tue, 28 Nov 2023 10:37:16 +0100 Subject: [PATCH 09/12] Chance supported minimal Go version back to 1.20 (#514) --- README.md | 2 +- cmd/csaf_downloader/config.go | 3 ++- cmd/csaf_downloader/downloader.go | 3 ++- cmd/csaf_downloader/forwarder.go | 8 ++++++-- cmd/csaf_downloader/forwarder_test.go | 3 ++- cmd/csaf_downloader/main.go | 3 ++- cmd/csaf_downloader/stats.go | 2 +- cmd/csaf_downloader/stats_test.go | 3 ++- docs/Development.md | 5 +++++ examples/purls_searcher/main.go | 7 +++++-- go.mod | 5 +++-- go.sum | 21 +++++---------------- internal/options/log.go | 3 ++- internal/options/log_test.go | 3 ++- 14 files changed, 40 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 022b1497..54daf872 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ Download the binaries from the most recent release assets on Github. ### Build from sources -- A recent version of **Go** (1.21+) should be installed. [Go installation](https://go.dev/doc/install) +- A recent version of **Go** (1.20+) should be installed. [Go installation](https://go.dev/doc/install) - Clone the repository `git clone https://github.com/csaf-poc/csaf_distribution.git ` diff --git a/cmd/csaf_downloader/config.go b/cmd/csaf_downloader/config.go index 1761d758..367780f3 100644 --- a/cmd/csaf_downloader/config.go +++ b/cmd/csaf_downloader/config.go @@ -13,12 +13,13 @@ import ( "fmt" "io" "log" - "log/slog" "net/http" "os" "path/filepath" "time" + "golang.org/x/exp/slog" + "github.com/csaf-poc/csaf_distribution/v3/internal/certs" "github.com/csaf-poc/csaf_distribution/v3/internal/filter" "github.com/csaf-poc/csaf_distribution/v3/internal/models" diff --git a/cmd/csaf_downloader/downloader.go b/cmd/csaf_downloader/downloader.go index 1799a845..7fa0c7cf 100644 --- a/cmd/csaf_downloader/downloader.go +++ b/cmd/csaf_downloader/downloader.go @@ -19,7 +19,6 @@ import ( "fmt" "hash" "io" - "log/slog" "net/http" "net/url" "os" @@ -30,6 +29,8 @@ import ( "sync" "time" + "golang.org/x/exp/slog" + "github.com/ProtonMail/gopenpgp/v2/crypto" "golang.org/x/time/rate" diff --git a/cmd/csaf_downloader/forwarder.go b/cmd/csaf_downloader/forwarder.go index 8ceb0e57..eda6595f 100644 --- a/cmd/csaf_downloader/forwarder.go +++ b/cmd/csaf_downloader/forwarder.go @@ -12,13 +12,14 @@ import ( "bytes" "crypto/tls" "io" - "log/slog" "mime/multipart" "net/http" "os" "path/filepath" "strings" + "golang.org/x/exp/slog" + "github.com/csaf-poc/csaf_distribution/v3/internal/misc" "github.com/csaf-poc/csaf_distribution/v3/util" ) @@ -57,7 +58,10 @@ type forwarder struct { // newForwarder creates a new forwarder. func newForwarder(cfg *config) *forwarder { - queue := max(1, cfg.ForwardQueue) + queue := cfg.ForwardQueue + if queue < 1 { + queue = 1 + } return &forwarder{ cfg: cfg, cmds: make(chan func(*forwarder), queue), diff --git a/cmd/csaf_downloader/forwarder_test.go b/cmd/csaf_downloader/forwarder_test.go index c7f8634e..dc515ad0 100644 --- a/cmd/csaf_downloader/forwarder_test.go +++ b/cmd/csaf_downloader/forwarder_test.go @@ -14,7 +14,6 @@ import ( "encoding/json" "errors" "io" - "log/slog" "mime" "mime/multipart" "net/http" @@ -23,6 +22,8 @@ import ( "strings" "testing" + "golang.org/x/exp/slog" + "github.com/csaf-poc/csaf_distribution/v3/internal/options" "github.com/csaf-poc/csaf_distribution/v3/util" ) diff --git a/cmd/csaf_downloader/main.go b/cmd/csaf_downloader/main.go index 7c0e564f..daff1633 100644 --- a/cmd/csaf_downloader/main.go +++ b/cmd/csaf_downloader/main.go @@ -11,10 +11,11 @@ package main import ( "context" - "log/slog" "os" "os/signal" + "golang.org/x/exp/slog" + "github.com/csaf-poc/csaf_distribution/v3/internal/options" ) diff --git a/cmd/csaf_downloader/stats.go b/cmd/csaf_downloader/stats.go index 6bafbf7b..237420aa 100644 --- a/cmd/csaf_downloader/stats.go +++ b/cmd/csaf_downloader/stats.go @@ -8,7 +8,7 @@ package main -import "log/slog" +import "golang.org/x/exp/slog" // stats contains counters of the downloads. type stats struct { diff --git a/cmd/csaf_downloader/stats_test.go b/cmd/csaf_downloader/stats_test.go index 69567ab4..b3ab9142 100644 --- a/cmd/csaf_downloader/stats_test.go +++ b/cmd/csaf_downloader/stats_test.go @@ -11,8 +11,9 @@ package main import ( "bytes" "encoding/json" - "log/slog" "testing" + + "golang.org/x/exp/slog" ) func TestStatsAdd(t *testing.T) { diff --git a/docs/Development.md b/docs/Development.md index 0a7004a8..218cb7eb 100644 --- a/docs/Development.md +++ b/docs/Development.md @@ -1,5 +1,10 @@ # Development +## Supported Go versions + +We support the latest version and the one before +the latest version of Go (currently 1.21 and 1.20). + ## Generated files Some source code files are machine generated. At the moment these are only diff --git a/examples/purls_searcher/main.go b/examples/purls_searcher/main.go index b01e671a..a91470bd 100644 --- a/examples/purls_searcher/main.go +++ b/examples/purls_searcher/main.go @@ -7,9 +7,10 @@ import ( "fmt" "log" "os" - "slices" "strings" + "golang.org/x/exp/slices" + "github.com/csaf-poc/csaf_distribution/v3/csaf" ) @@ -70,7 +71,9 @@ func newURLFinder(ids []string) *urlFinder { // clear resets the url finder after a run on an advisory. func (uf *urlFinder) clear() { - clear(uf.urls) + for i := range uf.urls { + uf.urls[i] = uf.urls[i][:0] + } } // dumpURLs dumps the found URLs to stdout. diff --git a/go.mod b/go.mod index 82a20c5e..469c8a3a 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/csaf-poc/csaf_distribution/v3 -go 1.21 +go 1.20 require ( github.com/BurntSushi/toml v1.3.2 @@ -14,6 +14,7 @@ require ( github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 go.etcd.io/bbolt v1.3.8 golang.org/x/crypto v0.14.0 + golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa golang.org/x/term v0.13.0 golang.org/x/time v0.3.0 ) @@ -26,6 +27,6 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/shopspring/decimal v1.3.1 // indirect golang.org/x/net v0.17.0 // indirect - golang.org/x/sys v0.13.0 // indirect + golang.org/x/sys v0.14.0 // indirect golang.org/x/text v0.13.0 // indirect ) diff --git a/go.sum b/go.sum index c2643b9e..3a101d4e 100644 --- a/go.sum +++ b/go.sum @@ -9,8 +9,6 @@ github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c h1:kMFnB0vCcX github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f h1:tCbYj7/299ekTTXpdwKYF8eBlsYsDVoggDAuAjoK66k= github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f/go.mod h1:gcr0kNtGBqin9zDW9GOHcVntrwnjrK+qdJ06mWYBybw= -github.com/ProtonMail/gopenpgp/v2 v2.7.3 h1:AJu1OI/1UWVYZl6QcCLKGu9OTngS2r52618uGlje84I= -github.com/ProtonMail/gopenpgp/v2 v2.7.3/go.mod h1:IhkNEDaxec6NyzSI0PlxapinnwPVIESk8/76da3Ct3g= github.com/ProtonMail/gopenpgp/v2 v2.7.4 h1:Vz/8+HViFFnf2A6XX8JOvZMrA6F5puwNvvF21O1mRlo= github.com/ProtonMail/gopenpgp/v2 v2.7.4/go.mod h1:IhkNEDaxec6NyzSI0PlxapinnwPVIESk8/76da3Ct3g= github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM= @@ -19,7 +17,6 @@ github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEq github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss= github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU= github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= -github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cloudflare/circl v1.3.6 h1:/xbKIqSHbZXHwkhbrhrt2YOHIwYJlXH94E3tI/gDlUg= github.com/cloudflare/circl v1.3.6/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= @@ -28,6 +25,7 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= @@ -44,20 +42,17 @@ github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFR github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= -go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA= go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= -golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -69,8 +64,6 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= -golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= -golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -88,18 +81,14 @@ golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= -golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU= -golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/internal/options/log.go b/internal/options/log.go index c8e828dc..226072ea 100644 --- a/internal/options/log.go +++ b/internal/options/log.go @@ -9,8 +9,9 @@ package options import ( - "log/slog" "strings" + + "golang.org/x/exp/slog" ) // LogLevel implements a helper type to be used in configurations. diff --git a/internal/options/log_test.go b/internal/options/log_test.go index 6c938651..2272f0f1 100644 --- a/internal/options/log_test.go +++ b/internal/options/log_test.go @@ -9,8 +9,9 @@ package options import ( - "log/slog" "testing" + + "golang.org/x/exp/slog" ) func TestMarshalFlag(t *testing.T) { From b457dc872fa4f8031731509ba2ee31e49cba6a3c Mon Sep 17 00:00:00 2001 From: "Sascha L. Teichmann" Date: Fri, 1 Dec 2023 11:45:09 +0100 Subject: [PATCH 10/12] Remove usage of slices in enum generator. (#516) --- csaf/generate_cvss_enums.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/csaf/generate_cvss_enums.go b/csaf/generate_cvss_enums.go index 911b64df..eaa2cb95 100644 --- a/csaf/generate_cvss_enums.go +++ b/csaf/generate_cvss_enums.go @@ -17,7 +17,7 @@ import ( "go/format" "log" "os" - "slices" + "sort" "strings" "text/template" ) @@ -135,7 +135,7 @@ func main() { defs = append(defs, k) } } - slices.Sort(defs) + sort.Strings(defs) var source bytes.Buffer From 9073a8a282a4efd149acd88aeb23b3d1004cf1c7 Mon Sep 17 00:00:00 2001 From: Juan Ariza Toledano Date: Fri, 1 Dec 2023 15:31:25 +0100 Subject: [PATCH 11/12] feat: Add function to find product identification helpers inspecting the tree (#505) * feat: Add function to find product identification helpers inspecting the tree Signed-off-by: juan131 * fix: simplify unit tests Signed-off-by: juan131 * fix: also iterate over relationships Signed-off-by: juan131 * fix: adapt example to use new library function Signed-off-by: juan131 * Separate collecting and visiting of the product id helpers. --------- Signed-off-by: juan131 Co-authored-by: Sascha L. Teichmann --- csaf/util.go | 61 +++++++++++ csaf/util_test.go | 182 ++++++++++++++++++++++++++++++++ examples/purls_searcher/main.go | 109 +++---------------- 3 files changed, 257 insertions(+), 95 deletions(-) create mode 100644 csaf/util_test.go diff --git a/csaf/util.go b/csaf/util.go index f192f097..f8e34be6 100644 --- a/csaf/util.go +++ b/csaf/util.go @@ -36,3 +36,64 @@ func ExtractProviderURL(r io.Reader, all bool) ([]string, error) { } return urls, nil } + +// CollectProductIdentificationHelpers returns a slice of all ProductIdentificationHelper +// for a given ProductID. +func (pt *ProductTree) CollectProductIdentificationHelpers(id ProductID) []*ProductIdentificationHelper { + var helpers []*ProductIdentificationHelper + pt.FindProductIdentificationHelpers( + id, func(helper *ProductIdentificationHelper) { + helpers = append(helpers, helper) + }) + return helpers +} + +// FindProductIdentificationHelpers calls visit on all ProductIdentificationHelper +// for a given ProductID by iterating over all full product names and branches +// recursively available in the ProductTree. +func (pt *ProductTree) FindProductIdentificationHelpers( + id ProductID, + visit func(*ProductIdentificationHelper), +) { + // Iterate over all full product names + if fpns := pt.FullProductNames; fpns != nil { + for _, fpn := range *fpns { + if fpn != nil && + fpn.ProductID != nil && *fpn.ProductID == id && + fpn.ProductIdentificationHelper != nil { + visit(fpn.ProductIdentificationHelper) + } + } + } + + // Iterate over branches recursively + var recBranch func(b *Branch) + recBranch = func(b *Branch) { + if b == nil { + return + } + if fpn := b.Product; fpn != nil && + fpn.ProductID != nil && *fpn.ProductID == id && + fpn.ProductIdentificationHelper != nil { + visit(fpn.ProductIdentificationHelper) + } + for _, c := range b.Branches { + recBranch(c) + } + } + for _, b := range pt.Branches { + recBranch(b) + } + + // Iterate over relationships + if rels := pt.RelationShips; rels != nil { + for _, rel := range *rels { + if rel != nil { + if fpn := rel.FullProductName; fpn != nil && fpn.ProductID != nil && + *fpn.ProductID == id && fpn.ProductIdentificationHelper != nil { + visit(fpn.ProductIdentificationHelper) + } + } + } + } +} diff --git a/csaf/util_test.go b/csaf/util_test.go new file mode 100644 index 00000000..0d5ff496 --- /dev/null +++ b/csaf/util_test.go @@ -0,0 +1,182 @@ +// This file is Free Software under the MIT License +// without warranty, see README.md and LICENSES/MIT.txt for details. +// +// SPDX-License-Identifier: MIT +// +// SPDX-FileCopyrightText: 2022 German Federal Office for Information Security (BSI) +// Software-Engineering: 2022 Intevation GmbH + +package csaf + +import ( + "reflect" + "testing" +) + +func TestProductTree_FindProductIdentificationHelpers(t *testing.T) { + type fields struct { + Branches Branches + FullProductNames *FullProductNames + RelationShips *Relationships + } + type args struct { + id ProductID + } + tests := []struct { + name string + fields fields + args args + want []*ProductIdentificationHelper + }{ + { + name: "empty product tree", + args: args{ + id: "CSAFPID-0001", + }, + want: nil, + }, + { + name: "product tree with matching full product names", + fields: fields{ + FullProductNames: &FullProductNames{{ + ProductID: &[]ProductID{"CSAFPID-0001"}[0], + ProductIdentificationHelper: &ProductIdentificationHelper{ + CPE: &[]CPE{"cpe:2.3:a:microsoft:internet_explorer:1.0.0:beta:*:*:*:*:*:*"}[0], + }, + }}, + }, + args: args{ + id: "CSAFPID-0001", + }, + want: []*ProductIdentificationHelper{{ + CPE: &[]CPE{"cpe:2.3:a:microsoft:internet_explorer:1.0.0:beta:*:*:*:*:*:*"}[0], + }}, + }, + { + name: "product tree with no matching full product names", + fields: fields{ + FullProductNames: &FullProductNames{{ + ProductID: &[]ProductID{"CSAFPID-0001"}[0], + ProductIdentificationHelper: &ProductIdentificationHelper{ + CPE: &[]CPE{"cpe:2.3:a:microsoft:internet_explorer:1.0.0:beta:*:*:*:*:*:*"}[0], + }, + }}, + }, + args: args{ + id: "CSAFPID-0002", + }, + want: nil, + }, + { + name: "product tree with matching branches", + fields: fields{ + Branches: Branches{{ + Name: &[]string{"beta"}[0], + Product: &FullProductName{ + ProductID: &[]ProductID{"CSAFPID-0001"}[0], + ProductIdentificationHelper: &ProductIdentificationHelper{ + CPE: &[]CPE{"cpe:2.3:a:microsoft:internet_explorer:1.0.0:beta:*:*:*:*:*:*"}[0], + }, + }, + Branches: Branches{{ + Name: &[]string{"beta-2"}[0], + Product: &FullProductName{ + ProductID: &[]ProductID{"CSAFPID-0001"}[0], + ProductIdentificationHelper: &ProductIdentificationHelper{ + CPE: &[]CPE{"cpe:2.3:a:microsoft:internet_explorer:1.0.0:beta-2:*:*:*:*:*:*"}[0], + }, + }, + }}, + }}, + }, + args: args{ + id: "CSAFPID-0001", + }, + want: []*ProductIdentificationHelper{{ + CPE: &[]CPE{"cpe:2.3:a:microsoft:internet_explorer:1.0.0:beta:*:*:*:*:*:*"}[0], + }, { + CPE: &[]CPE{"cpe:2.3:a:microsoft:internet_explorer:1.0.0:beta-2:*:*:*:*:*:*"}[0], + }}, + }, + { + name: "product tree with no matching branches", + fields: fields{ + Branches: Branches{{ + Name: &[]string{"beta"}[0], + Product: &FullProductName{ + ProductID: &[]ProductID{"CSAFPID-0001"}[0], + ProductIdentificationHelper: &ProductIdentificationHelper{ + CPE: &[]CPE{"cpe:2.3:a:microsoft:internet_explorer:1.0.0:beta:*:*:*:*:*:*"}[0], + }, + }, + Branches: Branches{{ + Name: &[]string{"beta-2"}[0], + Product: &FullProductName{ + ProductID: &[]ProductID{"CSAFPID-0001"}[0], + ProductIdentificationHelper: &ProductIdentificationHelper{ + CPE: &[]CPE{"cpe:2.3:a:microsoft:internet_explorer:1.0.0:beta-2:*:*:*:*:*:*"}[0], + }, + }, + }}, + }}, + }, + args: args{ + id: "CSAFPID-0002", + }, + want: nil, + }, + { + name: "product tree with matching relationships", + fields: fields{ + RelationShips: &Relationships{{ + FullProductName: &FullProductName{ + ProductID: &[]ProductID{"CSAFPID-0001"}[0], + ProductIdentificationHelper: &ProductIdentificationHelper{ + CPE: &[]CPE{"cpe:2.3:a:microsoft:internet_explorer:1.0.0:beta:*:*:*:*:*:*"}[0], + }, + }, + }}, + }, + args: args{ + id: "CSAFPID-0001", + }, + want: []*ProductIdentificationHelper{{ + CPE: &[]CPE{"cpe:2.3:a:microsoft:internet_explorer:1.0.0:beta:*:*:*:*:*:*"}[0], + }}, + }, + { + name: "product tree with no matching relationships", + fields: fields{ + RelationShips: &Relationships{{ + FullProductName: &FullProductName{ + ProductID: &[]ProductID{"CSAFPID-0001"}[0], + ProductIdentificationHelper: &ProductIdentificationHelper{ + CPE: &[]CPE{"cpe:2.3:a:microsoft:internet_explorer:1.0.0:beta:*:*:*:*:*:*"}[0], + }, + }, + }}, + }, + args: args{ + id: "CSAFPID-0002", + }, + want: nil, + }, + } + + t.Parallel() + for _, testToRun := range tests { + test := testToRun + t.Run(test.name, func(tt *testing.T) { + tt.Parallel() + pt := &ProductTree{ + Branches: test.fields.Branches, + FullProductNames: test.fields.FullProductNames, + RelationShips: test.fields.RelationShips, + } + if got := pt.CollectProductIdentificationHelpers(test.args.id); !reflect.DeepEqual(got, test.want) { + tt.Errorf("ProductTree.FindProductIdentificationHelpers() = %v, want %v", + got, test.want) + } + }) + } +} diff --git a/examples/purls_searcher/main.go b/examples/purls_searcher/main.go index a91470bd..c1ec3e19 100644 --- a/examples/purls_searcher/main.go +++ b/examples/purls_searcher/main.go @@ -9,9 +9,8 @@ import ( "os" "strings" - "golang.org/x/exp/slices" - "github.com/csaf-poc/csaf_distribution/v3/csaf" + "github.com/csaf-poc/csaf_distribution/v3/util" ) func main() { @@ -35,106 +34,26 @@ func main() { // run prints PURLs belonging to the given Product IDs. func run(files []string, ids string) error { - - uf := newURLFinder(strings.Split(ids, ",")) - for _, file := range files { adv, err := csaf.LoadAdvisory(file) if err != nil { return fmt.Errorf("loading %q failed: %w", file, err) } - uf.findURLs(adv) - uf.dumpURLs() - uf.clear() - } - - return nil -} - -// urlFinder helps to find the URLs of a set of product ids in advisories. -type urlFinder struct { - ids []csaf.ProductID - urls [][]csaf.PURL -} -// newURLFinder creates a new urlFinder for given ids. -func newURLFinder(ids []string) *urlFinder { - uf := &urlFinder{ - ids: make([]csaf.ProductID, len(ids)), - urls: make([][]csaf.PURL, len(ids)), - } - for i := range uf.ids { - uf.ids[i] = csaf.ProductID(ids[i]) - } - return uf -} - -// clear resets the url finder after a run on an advisory. -func (uf *urlFinder) clear() { - for i := range uf.urls { - uf.urls[i] = uf.urls[i][:0] - } -} - -// dumpURLs dumps the found URLs to stdout. -func (uf *urlFinder) dumpURLs() { - for i, urls := range uf.urls { - if len(urls) == 0 { - continue - } - fmt.Printf("Found URLs for %s:\n", uf.ids[i]) - for j, url := range urls { - fmt.Printf("%d. %s\n", j+1, url) + for _, id := range strings.Split(ids, ",") { + already := util.Set[csaf.PURL]{} + i := 0 + adv.ProductTree.FindProductIdentificationHelpers( + csaf.ProductID(id), + func(h *csaf.ProductIdentificationHelper) { + if h.PURL != nil && !already.Contains(*h.PURL) { + already.Add(*h.PURL) + i++ + fmt.Printf("%d. %s\n", i, *h.PURL) + } + }) } } -} -// findURLs find the URLs in an advisory. -func (uf *urlFinder) findURLs(adv *csaf.Advisory) { - tree := adv.ProductTree - if tree == nil { - return - } - - // If we have found it and we have a valid URL add unique. - add := func(idx int, h *csaf.ProductIdentificationHelper) { - if idx != -1 && h != nil && h.PURL != nil && - !slices.Contains(uf.urls[idx], *h.PURL) { - uf.urls[idx] = append(uf.urls[idx], *h.PURL) - } - } - - // First iterate over full product names. - if names := tree.FullProductNames; names != nil { - for _, name := range *names { - if name != nil && name.ProductID != nil { - add(slices.Index(uf.ids, *name.ProductID), name.ProductIdentificationHelper) - } - } - } - - // Second traverse the branches recursively. - var recBranch func(*csaf.Branch) - recBranch = func(b *csaf.Branch) { - if p := b.Product; p != nil && p.ProductID != nil { - add(slices.Index(uf.ids, *p.ProductID), p.ProductIdentificationHelper) - } - for _, c := range b.Branches { - recBranch(c) - } - } - for _, b := range tree.Branches { - recBranch(b) - } - - // Third iterate over relationships. - if tree.RelationShips != nil { - for _, rel := range *tree.RelationShips { - if rel != nil { - if fpn := rel.FullProductName; fpn != nil && fpn.ProductID != nil { - add(slices.Index(uf.ids, *fpn.ProductID), fpn.ProductIdentificationHelper) - } - } - } - } + return nil } From 03e418182d76d36a309912fd6694136f123d9007 Mon Sep 17 00:00:00 2001 From: "Sascha L. Teichmann" Date: Mon, 4 Dec 2023 11:31:14 +0100 Subject: [PATCH 12/12] Advisories: Time filter download by 'updated' field in ROLIE entries. (#519) * Use 'updated' field of ROLIE field entries to time filter downloads. * More suited variable naming --- cmd/csaf_checker/processor.go | 8 +------- csaf/advisories.go | 2 +- internal/models/models.go | 8 -------- internal/models/models_test.go | 24 ------------------------ 4 files changed, 2 insertions(+), 40 deletions(-) diff --git a/cmd/csaf_checker/processor.go b/cmd/csaf_checker/processor.go index 2a5161ce..7eaefefe 100644 --- a/cmd/csaf_checker/processor.go +++ b/cmd/csaf_checker/processor.go @@ -33,7 +33,6 @@ import ( "golang.org/x/time/rate" "github.com/csaf-poc/csaf_distribution/v3/csaf" - "github.com/csaf-poc/csaf_distribution/v3/internal/models" "github.com/csaf-poc/csaf_distribution/v3/util" ) @@ -548,7 +547,7 @@ func (p *processor) rolieFeedEntries(feed string) ([]csaf.AdvisoryFile, error) { // Filter if we have date checking. if accept := p.cfg.Range; accept != nil { - if pub := time.Time(entry.Published); !pub.IsZero() && !accept.Contains(pub) { + if t := time.Time(entry.Updated); !t.IsZero() && !accept.Contains(t) { return } } @@ -667,11 +666,6 @@ func (p *processor) integrity( var folderYear *int if m := yearFromURL.FindStringSubmatch(u); m != nil { year, _ := strconv.Atoi(m[1]) - // Check if the year is in the accepted time interval. - if accept := p.cfg.Range; accept != nil && - !accept.Intersects(models.Year(year)) { - continue - } folderYear = &year } diff --git a/csaf/advisories.go b/csaf/advisories.go index 9c22ed3f..5b856909 100644 --- a/csaf/advisories.go +++ b/csaf/advisories.go @@ -316,7 +316,7 @@ func (afp *AdvisoryFileProcessor) processROLIE( // Filter if we have date checking. if afp.AgeAccept != nil { - if pub := time.Time(entry.Published); !pub.IsZero() && !afp.AgeAccept(pub) { + if t := time.Time(entry.Updated); !t.IsZero() && !afp.AgeAccept(t) { return } } diff --git a/internal/models/models.go b/internal/models/models.go index 00fead38..520cd9c3 100644 --- a/internal/models/models.go +++ b/internal/models/models.go @@ -31,14 +31,6 @@ func NewTimeInterval(a, b time.Time) TimeRange { return TimeRange{a, b} } -// Year returns the time range for a given year. -func Year(year int) TimeRange { - return TimeRange{ - time.Date(year, time.January, 1, 0, 0, 0, 0, time.UTC), - time.Date(year, time.December, 31, 23, 59, 59, int(time.Second-time.Nanosecond), time.UTC), - } -} - // guessDate tries to guess an RFC 3339 date time from a given string. func guessDate(s string) (time.Time, bool) { for _, layout := range []string{ diff --git a/internal/models/models_test.go b/internal/models/models_test.go index 0217bf77..a40100f1 100644 --- a/internal/models/models_test.go +++ b/internal/models/models_test.go @@ -173,27 +173,3 @@ func TestTimeRangeIntersects(t *testing.T) { } } } - -// TestTimeRangeYear checks if the Year construction works. -func TestTimeRangeYear(t *testing.T) { - var ( - year = Year(1984) - first = time.Date(1984, time.January, 1, 0, 0, 0, 0, time.UTC) - before = first.Add(-time.Nanosecond) - after = time.Date(1984+1, time.January, 1, 0, 0, 0, 0, time.UTC) - last = after.Add(-time.Nanosecond) - ) - for _, x := range []struct { - t time.Time - expected bool - }{ - {t: first, expected: true}, - {t: before, expected: false}, - {t: last, expected: true}, - {t: after, expected: false}, - } { - if got := year.Contains(x.t); got != x.expected { - t.Fatalf("%v: got %t expected %t", x.t, got, x.expected) - } - } -}