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

Merge pull request #530 from oxisto/slog

Added support for structured logging in `csaf_aggregator`
This commit is contained in:
Bernhard Herzog 2024-04-25 13:13:11 +02:00 committed by GitHub
commit 617deb4c17
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 135 additions and 91 deletions

View file

@ -69,7 +69,7 @@ Download the binaries from the most recent release assets on Github.
### Build from sources ### Build from sources
- A recent version of **Go** (1.20+) should be installed. [Go installation](https://go.dev/doc/install) - A recent version of **Go** (1.21+) should be installed. [Go installation](https://go.dev/doc/install)
- Clone the repository `git clone https://github.com/csaf-poc/csaf_distribution.git ` - Clone the repository `git clone https://github.com/csaf-poc/csaf_distribution.git `

View file

@ -12,7 +12,7 @@ import (
"crypto/tls" "crypto/tls"
"errors" "errors"
"fmt" "fmt"
"log" "log/slog"
"net/http" "net/http"
"os" "os"
"runtime" "runtime"
@ -178,9 +178,11 @@ func (p *provider) ageAccept(c *config) func(time.Time) bool {
} }
if c.Verbose { if c.Verbose {
log.Printf( slog.Debug(
"Setting up filter to accept advisories within time range %s to %s\n", "Setting up filter to accept advisories within time range",
r[0].Format(time.RFC3339), r[1].Format(time.RFC3339)) "from", r[0].Format(time.RFC3339),
"to", r[1].Format(time.RFC3339),
)
} }
return r.Contains return r.Contains
} }
@ -393,6 +395,17 @@ func (c *config) setDefaults() {
} }
} }
// prepareLogging sets up the structured logging.
func (c *config) prepareLogging() error {
ho := slog.HandlerOptions{
Level: slog.LevelDebug,
}
handler := slog.NewTextHandler(os.Stdout, &ho)
logger := slog.New(handler)
slog.SetDefault(logger)
return nil
}
// compileIgnorePatterns compiles the configured patterns to be ignored. // compileIgnorePatterns compiles the configured patterns to be ignored.
func (p *provider) compileIgnorePatterns() error { func (p *provider) compileIgnorePatterns() error {
pm, err := filter.NewPatternMatcher(p.IgnorePattern) pm, err := filter.NewPatternMatcher(p.IgnorePattern)

View file

@ -11,7 +11,7 @@ package main
import ( import (
"errors" "errors"
"fmt" "fmt"
"log" "log/slog"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
@ -29,11 +29,13 @@ type fullJob struct {
err error err error
} }
// setupProviderFull fetches the provider-metadate.json for a specific provider. // setupProviderFull fetches the provider-metadata.json for a specific provider.
func (w *worker) setupProviderFull(provider *provider) error { func (w *worker) setupProviderFull(provider *provider) error {
log.Printf("worker #%d: %s (%s)\n", w.log.Info("Setting up provider",
w.num, provider.Name, provider.Domain) "provider", slog.GroupValue(
slog.String("name", provider.Name),
slog.String("domain", provider.Domain),
))
w.dir = "" w.dir = ""
w.provider = provider w.provider = provider
@ -55,7 +57,7 @@ func (w *worker) setupProviderFull(provider *provider) error {
"provider-metadata.json has %d validation issues", len(errors)) "provider-metadata.json has %d validation issues", len(errors))
} }
log.Printf("provider-metadata: %s\n", w.loc) w.log.Info("Using provider-metadata", "url", w.loc)
return nil return nil
} }
@ -79,7 +81,7 @@ func (w *worker) fullWork(wg *sync.WaitGroup, jobs <-chan *fullJob) {
func (p *processor) full() error { func (p *processor) full() error {
if p.cfg.runAsMirror() { if p.cfg.runAsMirror() {
log.Println("Running in aggregator mode") p.log.Info("Running in aggregator mode")
// check if we need to setup a remote validator // check if we need to setup a remote validator
if p.cfg.RemoteValidatorOptions != nil { if p.cfg.RemoteValidatorOptions != nil {
@ -96,16 +98,18 @@ func (p *processor) full() error {
}() }()
} }
} else { } else {
log.Println("Running in lister mode") p.log.Info("Running in lister mode")
} }
queue := make(chan *fullJob) queue := make(chan *fullJob)
var wg sync.WaitGroup var wg sync.WaitGroup
log.Printf("Starting %d workers.\n", p.cfg.Workers) p.log.Info("Starting workers...", "num", p.cfg.Workers)
for i := 1; i <= p.cfg.Workers; i++ { for i := 1; i <= p.cfg.Workers; i++ {
wg.Add(1) wg.Add(1)
w := newWorker(i, p) w := newWorker(i, p)
go w.fullWork(&wg, queue) go w.fullWork(&wg, queue)
} }
@ -135,12 +139,22 @@ func (p *processor) full() error {
for i := range jobs { for i := range jobs {
j := &jobs[i] j := &jobs[i]
if j.err != nil { if j.err != nil {
log.Printf("error: '%s' failed: %v\n", j.provider.Name, j.err) p.log.Error("Job execution failed",
slog.Group("job",
slog.Group("provider"),
"name", j.provider.Name,
),
"err", j.err,
)
continue continue
} }
if j.aggregatorProvider == nil { if j.aggregatorProvider == nil {
log.Printf( p.log.Error("Job did not produce any result",
"error: '%s' does not produce any result.\n", j.provider.Name) slog.Group("job",
slog.Group("provider"),
"name", j.provider.Name,
),
)
continue continue
} }

View file

@ -12,7 +12,6 @@ import (
"bufio" "bufio"
"encoding/csv" "encoding/csv"
"fmt" "fmt"
"log"
"os" "os"
"path/filepath" "path/filepath"
"sort" "sort"
@ -377,7 +376,7 @@ func (w *worker) writeIndices() error {
} }
for label, summaries := range w.summaries { for label, summaries := range w.summaries {
log.Printf("%s: %d\n", label, len(summaries)) w.log.Debug("Writing indices", "label", label, "summaries.num", len(summaries))
if err := w.writeInterims(label, summaries); err != nil { if err := w.writeInterims(label, summaries); err != nil {
return err return err
} }

View file

@ -17,7 +17,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"log"
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
@ -102,12 +101,12 @@ func (w *worker) checkInterims(
// XXX: Should we return an error here? // XXX: Should we return an error here?
for _, e := range errors { for _, e := range errors {
log.Printf("validation error: %s: %v\n", url, e) w.log.Error("validation error", "url", url, "err", e)
} }
// We need to write the changed content. // We need to write the changed content.
// This will start the transcation if not already started. // This will start the transaction if not already started.
dst, err := tx.Dst() dst, err := tx.Dst()
if err != nil { if err != nil {
return nil, err return nil, err
@ -159,8 +158,7 @@ func (w *worker) checkInterims(
// setupProviderInterim prepares the worker for a specific provider. // setupProviderInterim prepares the worker for a specific provider.
func (w *worker) setupProviderInterim(provider *provider) { func (w *worker) setupProviderInterim(provider *provider) {
log.Printf("worker #%d: %s (%s)\n", w.log.Info("Setting up worker", provider.Name, provider.Domain)
w.num, provider.Name, provider.Domain)
w.dir = "" w.dir = ""
w.provider = provider w.provider = provider
@ -262,7 +260,7 @@ func (p *processor) interim() error {
queue := make(chan *interimJob) queue := make(chan *interimJob)
var wg sync.WaitGroup var wg sync.WaitGroup
log.Printf("Starting %d workers.\n", p.cfg.Workers) p.log.Info("Starting workers...", "num", p.cfg.Workers)
for i := 1; i <= p.cfg.Workers; i++ { for i := 1; i <= p.cfg.Workers; i++ {
wg.Add(1) wg.Add(1)
w := newWorker(i, p) w := newWorker(i, p)

View file

@ -9,7 +9,7 @@
package main package main
import ( import (
"log" "log/slog"
"os" "os"
"path/filepath" "path/filepath"
@ -85,7 +85,8 @@ func (lt *lazyTransaction) commit() error {
os.RemoveAll(lt.dst) os.RemoveAll(lt.dst)
return err return err
} }
log.Printf("Move %q -> %q\n", symlink, lt.src)
slog.Debug("Moving directory", "from", symlink, "to", lt.src)
if err := os.Rename(symlink, lt.src); err != nil { if err := os.Rename(symlink, lt.src); err != nil {
os.RemoveAll(lt.dst) os.RemoveAll(lt.dst)
return err return err

View file

@ -11,10 +11,12 @@ package main
import ( import (
"fmt" "fmt"
"log/slog"
"os" "os"
"path/filepath" "path/filepath"
"github.com/csaf-poc/csaf_distribution/v3/internal/options" "github.com/csaf-poc/csaf_distribution/v3/internal/options"
"github.com/gofrs/flock" "github.com/gofrs/flock"
) )
@ -44,8 +46,9 @@ func lock(lockFile *string, fn func() error) error {
func main() { func main() {
_, cfg, err := parseArgsConfig() _, cfg, err := parseArgsConfig()
options.ErrorCheck(err) cfg.prepareLogging()
options.ErrorCheck(cfg.prepare()) options.ErrorCheckStructured(err)
p := processor{cfg: cfg} options.ErrorCheckStructured(cfg.prepare())
options.ErrorCheck(lock(cfg.LockFile, p.process)) p := processor{cfg: cfg, log: slog.Default()}
options.ErrorCheckStructured(lock(cfg.LockFile, p.process))
} }

View file

@ -16,7 +16,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"log" "log/slog"
"net/http" "net/http"
"net/url" "net/url"
"os" "os"
@ -47,7 +47,7 @@ func (w *worker) mirror() (*csaf.AggregatorCSAFProvider, error) {
if err != nil && w.dir != "" { if err != nil && w.dir != "" {
// If something goes wrong remove the debris. // If something goes wrong remove the debris.
if err := os.RemoveAll(w.dir); err != nil { if err := os.RemoveAll(w.dir); err != nil {
log.Printf("error: %v\n", err) w.log.Error("Could not remove directory", "path", w.dir, "err", err)
} }
} }
return result, err return result, err
@ -166,7 +166,7 @@ func (w *worker) writeProviderMetadata() error {
{Expr: `$.public_openpgp_keys`, Action: util.ReMarshalMatcher(&pm.PGPKeys)}, {Expr: `$.public_openpgp_keys`, Action: util.ReMarshalMatcher(&pm.PGPKeys)},
}, w.metadataProvider); err != nil { }, w.metadataProvider); err != nil {
// only log the errors // only log the errors
log.Printf("extracting data from orignal provider failed: %v\n", err) w.log.Error("Extracting data from original provider failed", "err", err)
} }
// We are mirroring the remote public keys, too. // We are mirroring the remote public keys, too.
@ -196,11 +196,11 @@ func (w *worker) mirrorPGPKeys(pm *csaf.ProviderMetadata) error {
for i := range pm.PGPKeys { for i := range pm.PGPKeys {
pgpKey := &pm.PGPKeys[i] pgpKey := &pm.PGPKeys[i]
if pgpKey.URL == nil { if pgpKey.URL == nil {
log.Printf("ignoring PGP key without URL: %s\n", pgpKey.Fingerprint) w.log.Warn("Ignoring PGP key without URL", "fingerprint", pgpKey.Fingerprint)
continue continue
} }
if _, err := hex.DecodeString(string(pgpKey.Fingerprint)); err != nil { if _, err := hex.DecodeString(string(pgpKey.Fingerprint)); err != nil {
log.Printf("ignoring PGP with invalid fingerprint: %s\n", *pgpKey.URL) w.log.Warn("Ignoring PGP key with invalid fingerprint", "url", *pgpKey.URL)
continue continue
} }
@ -344,7 +344,7 @@ func (w *worker) doMirrorTransaction() error {
// Check if there is a sysmlink already. // Check if there is a sysmlink already.
target := filepath.Join(w.processor.cfg.Folder, w.provider.Name) target := filepath.Join(w.processor.cfg.Folder, w.provider.Name)
log.Printf("target: '%s'\n", target) w.log.Debug("Checking for path existance", "path", target)
exists, err := util.PathExists(target) exists, err := util.PathExists(target)
if err != nil { if err != nil {
@ -359,7 +359,7 @@ func (w *worker) doMirrorTransaction() error {
} }
} }
log.Printf("sym link: %s -> %s\n", w.dir, target) w.log.Debug("Creating sym link", "from", w.dir, "to", target)
// Create a new symlink // Create a new symlink
if err := os.Symlink(w.dir, target); err != nil { if err := os.Symlink(w.dir, target); err != nil {
@ -368,7 +368,7 @@ func (w *worker) doMirrorTransaction() error {
} }
// Move the symlink // Move the symlink
log.Printf("Move: %s -> %s\n", target, webTarget) w.log.Debug("Moving sym link", "from", target, "to", webTarget)
if err := os.Rename(target, webTarget); err != nil { if err := os.Rename(target, webTarget); err != nil {
os.RemoveAll(w.dir) os.RemoveAll(w.dir)
return err return err
@ -499,14 +499,14 @@ func (w *worker) mirrorFiles(tlpLabel csaf.TLPLabel, files []csaf.AdvisoryFile)
u, err := url.Parse(file.URL()) u, err := url.Parse(file.URL())
if err != nil { if err != nil {
log.Printf("error: %s\n", err) w.log.Error("Could not parse advisory file URL", "err", err)
continue continue
} }
// Should we ignore this advisory? // Should we ignore this advisory?
if w.provider.ignoreURL(file.URL(), w.processor.cfg) { if w.provider.ignoreURL(file.URL(), w.processor.cfg) {
if w.processor.cfg.Verbose { if w.processor.cfg.Verbose {
log.Printf("Ignoring %s: %q\n", w.provider.Name, file.URL()) w.log.Info("Ignoring advisory", slog.Group("provider", "name", w.provider.Name), "file", file)
} }
continue continue
} }
@ -514,7 +514,7 @@ func (w *worker) mirrorFiles(tlpLabel csaf.TLPLabel, files []csaf.AdvisoryFile)
// Ignore not conforming filenames. // Ignore not conforming filenames.
filename := filepath.Base(u.Path) filename := filepath.Base(u.Path)
if !util.ConformingFileName(filename) { if !util.ConformingFileName(filename) {
log.Printf("Not conforming filename %q. Ignoring.\n", filename) w.log.Warn("Ignoring advisory because of non-conforming filename", "filename", filename)
continue continue
} }
@ -531,19 +531,18 @@ func (w *worker) mirrorFiles(tlpLabel csaf.TLPLabel, files []csaf.AdvisoryFile)
} }
if err := downloadJSON(w.client, file.URL(), download); err != nil { if err := downloadJSON(w.client, file.URL(), download); err != nil {
log.Printf("error: %v\n", err) w.log.Error("Error while downloading JSON", "err", err)
continue continue
} }
// Check against CSAF schema. // Check against CSAF schema.
errors, err := csaf.ValidateCSAF(advisory) errors, err := csaf.ValidateCSAF(advisory)
if err != nil { if err != nil {
log.Printf("error: %s: %v", file, err) w.log.Error("Error while validating CSAF schema", "err", err)
continue continue
} }
if len(errors) > 0 { if len(errors) > 0 {
log.Printf("CSAF file %s has %d validation errors.\n", w.log.Error("CSAF file has validation errors", "num.errors", len(errors), "file", file)
file, len(errors))
continue continue
} }
@ -551,29 +550,27 @@ func (w *worker) mirrorFiles(tlpLabel csaf.TLPLabel, files []csaf.AdvisoryFile)
if rmv := w.processor.remoteValidator; rmv != nil { if rmv := w.processor.remoteValidator; rmv != nil {
rvr, err := rmv.Validate(advisory) rvr, err := rmv.Validate(advisory)
if err != nil { if err != nil {
log.Printf("Calling remote validator failed: %s\n", err) w.log.Error("Calling remote validator failed", "err", err)
continue continue
} }
if !rvr.Valid { if !rvr.Valid {
log.Printf( w.log.Error("CSAF file does not validate remotely", "file", file.URL())
"CSAF file %s does not validate remotely.\n", file)
continue continue
} }
} }
sum, err := csaf.NewAdvisorySummary(w.expr, advisory) sum, err := csaf.NewAdvisorySummary(w.expr, advisory)
if err != nil { if err != nil {
log.Printf("error: %s: %v\n", file, err) w.log.Error("Error while creating new advisory", "file", file, "err", err)
continue continue
} }
if util.CleanFileName(sum.ID) != filename { if util.CleanFileName(sum.ID) != filename {
log.Printf("ID %q does not match filename %s", w.log.Error("ID mismatch", "id", sum.ID, "filename", filename)
sum.ID, filename)
} }
if err := w.extractCategories(label, advisory); err != nil { if err := w.extractCategories(label, advisory); err != nil {
log.Printf("error: %s: %v\n", file, err) w.log.Error("Could not extract categories", "file", file, "err", err)
continue continue
} }
@ -624,7 +621,7 @@ func (w *worker) downloadSignatureOrSign(url, fname string, data []byte) error {
if err != nil { if err != nil {
if err != errNotFound { if err != errNotFound {
log.Printf("error: %s: %v\n", url, err) w.log.Error("Could not find signature URL", "url", url, "err", err)
} }
// Sign it our self. // Sign it our self.
if sig, err = w.sign(data); err != nil { if sig, err = w.sign(data); err != nil {

View file

@ -10,14 +10,14 @@ package main
import ( import (
"fmt" "fmt"
"log" "log/slog"
"os" "os"
"path/filepath" "path/filepath"
"github.com/ProtonMail/gopenpgp/v2/crypto"
"github.com/csaf-poc/csaf_distribution/v3/csaf" "github.com/csaf-poc/csaf_distribution/v3/csaf"
"github.com/csaf-poc/csaf_distribution/v3/util" "github.com/csaf-poc/csaf_distribution/v3/util"
"github.com/ProtonMail/gopenpgp/v2/crypto"
) )
type processor struct { type processor struct {
@ -26,6 +26,9 @@ type processor struct {
// remoteValidator is a globally configured remote validator. // remoteValidator is a globally configured remote validator.
remoteValidator csaf.RemoteValidator remoteValidator csaf.RemoteValidator
// log is the structured logger for the whole processor.
log *slog.Logger
} }
type summary struct { type summary struct {
@ -48,6 +51,7 @@ type worker struct {
dir string // Directory to store data to. dir string // Directory to store data to.
summaries map[string][]summary // the summaries of the advisories. summaries map[string][]summary // the summaries of the advisories.
categories map[string]util.Set[string] // the categories per label. categories map[string]util.Set[string] // the categories per label.
log *slog.Logger // the structured logger, supplied with the worker number.
} }
func newWorker(num int, processor *processor) *worker { func newWorker(num int, processor *processor) *worker {
@ -55,6 +59,7 @@ func newWorker(num int, processor *processor) *worker {
num: num, num: num,
processor: processor, processor: processor,
expr: util.NewPathEval(), expr: util.NewPathEval(),
log: processor.log.With(slog.Int("worker", num)),
} }
} }
@ -86,9 +91,10 @@ func (w *worker) locateProviderMetadata(domain string) error {
if w.processor.cfg.Verbose { if w.processor.cfg.Verbose {
for i := range lpmd.Messages { for i := range lpmd.Messages {
log.Printf( w.log.Info(
"Loading provider-metadata.json of %q: %s\n", "Loading provider-metadata.json",
domain, lpmd.Messages[i].Message) "domain", domain,
"message", lpmd.Messages[i].Message)
} }
} }
@ -141,7 +147,7 @@ func (p *processor) removeOrphans() error {
fi, err := entry.Info() fi, err := entry.Info()
if err != nil { if err != nil {
log.Printf("error: %v\n", err) p.log.Error("Could not retrieve file info", "err", err)
continue continue
} }
@ -153,13 +159,13 @@ func (p *processor) removeOrphans() error {
d := filepath.Join(path, entry.Name()) d := filepath.Join(path, entry.Name())
r, err := filepath.EvalSymlinks(d) r, err := filepath.EvalSymlinks(d)
if err != nil { if err != nil {
log.Printf("error: %v\n", err) p.log.Error("Could not evaluate symlink", "err", err)
continue continue
} }
fd, err := os.Stat(r) fd, err := os.Stat(r)
if err != nil { if err != nil {
log.Printf("error: %v\n", err) p.log.Error("Could not retrieve file stats", "err", err)
continue continue
} }
@ -169,18 +175,18 @@ func (p *processor) removeOrphans() error {
} }
// Remove the link. // Remove the link.
log.Printf("removing link %s -> %s\n", d, r) p.log.Info("Removing link", "path", fmt.Sprintf("%s -> %s", d, r))
if err := os.Remove(d); err != nil { if err := os.Remove(d); err != nil {
log.Printf("error: %v\n", err) p.log.Error("Could not remove symlink", "err", err)
continue continue
} }
// Only remove directories which are in our folder. // Only remove directories which are in our folder.
if rel, err := filepath.Rel(prefix, r); err == nil && if rel, err := filepath.Rel(prefix, r); err == nil &&
rel == filepath.Base(r) { rel == filepath.Base(r) {
log.Printf("removing directory %s\n", r) p.log.Info("Remove directory", "path", r)
if err := os.RemoveAll(r); err != nil { if err := os.RemoveAll(r); err != nil {
log.Printf("error: %v\n", err) p.log.Error("Could not remove directory", "err", err)
} }
} }
} }

View file

@ -13,13 +13,12 @@ import (
"fmt" "fmt"
"io" "io"
"log" "log"
"log/slog"
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
"time" "time"
"golang.org/x/exp/slog"
"github.com/csaf-poc/csaf_distribution/v3/internal/certs" "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/filter"
"github.com/csaf-poc/csaf_distribution/v3/internal/models" "github.com/csaf-poc/csaf_distribution/v3/internal/models"

View file

@ -19,6 +19,7 @@ import (
"fmt" "fmt"
"hash" "hash"
"io" "io"
"log/slog"
"net/http" "net/http"
"net/url" "net/url"
"os" "os"
@ -29,8 +30,6 @@ import (
"sync" "sync"
"time" "time"
"golang.org/x/exp/slog"
"github.com/ProtonMail/gopenpgp/v2/crypto" "github.com/ProtonMail/gopenpgp/v2/crypto"
"golang.org/x/time/rate" "golang.org/x/time/rate"

View file

@ -12,14 +12,13 @@ import (
"bytes" "bytes"
"crypto/tls" "crypto/tls"
"io" "io"
"log/slog"
"mime/multipart" "mime/multipart"
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"golang.org/x/exp/slog"
"github.com/csaf-poc/csaf_distribution/v3/internal/misc" "github.com/csaf-poc/csaf_distribution/v3/internal/misc"
"github.com/csaf-poc/csaf_distribution/v3/util" "github.com/csaf-poc/csaf_distribution/v3/util"
) )

View file

@ -14,6 +14,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"io" "io"
"log/slog"
"mime" "mime"
"mime/multipart" "mime/multipart"
"net/http" "net/http"
@ -22,8 +23,6 @@ import (
"strings" "strings"
"testing" "testing"
"golang.org/x/exp/slog"
"github.com/csaf-poc/csaf_distribution/v3/internal/options" "github.com/csaf-poc/csaf_distribution/v3/internal/options"
"github.com/csaf-poc/csaf_distribution/v3/util" "github.com/csaf-poc/csaf_distribution/v3/util"
) )

View file

@ -11,11 +11,10 @@ package main
import ( import (
"context" "context"
"log/slog"
"os" "os"
"os/signal" "os/signal"
"golang.org/x/exp/slog"
"github.com/csaf-poc/csaf_distribution/v3/internal/options" "github.com/csaf-poc/csaf_distribution/v3/internal/options"
) )

View file

@ -8,7 +8,7 @@
package main package main
import "golang.org/x/exp/slog" import "log/slog"
// stats contains counters of the downloads. // stats contains counters of the downloads.
type stats struct { type stats struct {

View file

@ -11,9 +11,8 @@ package main
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"log/slog"
"testing" "testing"
"golang.org/x/exp/slog"
) )
func TestStatsAdd(t *testing.T) { func TestStatsAdd(t *testing.T) {

View file

@ -13,6 +13,7 @@ import (
"fmt" "fmt"
"io" "io"
"log" "log"
"log/slog"
"net/http" "net/http"
"net/url" "net/url"
"strings" "strings"
@ -23,6 +24,7 @@ import (
// AdvisoryFile constructs the urls of a remote file. // AdvisoryFile constructs the urls of a remote file.
type AdvisoryFile interface { type AdvisoryFile interface {
slog.LogValuer
URL() string URL() string
SHA256URL() string SHA256URL() string
SHA512URL() string SHA512URL() string
@ -46,6 +48,11 @@ func (paf PlainAdvisoryFile) SHA512URL() string { return string(paf) + ".sha512"
// SignURL returns the URL of signature file of this advisory. // SignURL returns the URL of signature file of this advisory.
func (paf PlainAdvisoryFile) SignURL() string { return string(paf) + ".asc" } func (paf PlainAdvisoryFile) SignURL() string { return string(paf) + ".asc" }
// LogValue implements [slog.LogValuer]
func (paf PlainAdvisoryFile) LogValue() slog.Value {
return slog.GroupValue(slog.String("url", paf.URL()))
}
// HashedAdvisoryFile is a more involed version of checkFile. // HashedAdvisoryFile is a more involed version of checkFile.
// Here each component can be given explicitly. // Here each component can be given explicitly.
// If a component is not given it is constructed by // If a component is not given it is constructed by
@ -71,6 +78,11 @@ func (haf HashedAdvisoryFile) SHA512URL() string { return haf.name(2, ".sha512")
// SignURL returns the URL of signature file of this advisory. // SignURL returns the URL of signature file of this advisory.
func (haf HashedAdvisoryFile) SignURL() string { return haf.name(3, ".asc") } func (haf HashedAdvisoryFile) SignURL() string { return haf.name(3, ".asc") }
// LogValue implements [slog.LogValuer]
func (haf HashedAdvisoryFile) LogValue() slog.Value {
return slog.GroupValue(slog.String("url", haf.URL()))
}
// AdvisoryFileProcessor implements the extraction of // AdvisoryFileProcessor implements the extraction of
// advisory file names from a given provider metadata. // advisory file names from a given provider metadata.
type AdvisoryFileProcessor struct { type AdvisoryFileProcessor struct {

View file

@ -3,7 +3,7 @@
## Supported Go versions ## Supported Go versions
We support the latest version and the one before We support the latest version and the one before
the latest version of Go (currently 1.21 and 1.20). the latest version of Go (currently 1.22 and 1.21).
## Generated files ## Generated files

3
go.mod
View file

@ -1,6 +1,6 @@
module github.com/csaf-poc/csaf_distribution/v3 module github.com/csaf-poc/csaf_distribution/v3
go 1.20 go 1.21
require ( require (
github.com/BurntSushi/toml v1.3.2 github.com/BurntSushi/toml v1.3.2
@ -14,7 +14,6 @@ require (
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 github.com/santhosh-tekuri/jsonschema/v5 v5.3.1
go.etcd.io/bbolt v1.3.8 go.etcd.io/bbolt v1.3.8
golang.org/x/crypto v0.14.0 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/term v0.13.0
golang.org/x/time v0.3.0 golang.org/x/time v0.3.0
) )

3
go.sum
View file

@ -42,6 +42,7 @@ 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/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.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= 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= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA= go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA=
go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
@ -51,8 +52,6 @@ golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2Uz
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= 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.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/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= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=

View file

@ -9,9 +9,8 @@
package options package options
import ( import (
"log/slog"
"strings" "strings"
"golang.org/x/exp/slog"
) )
// LogLevel implements a helper type to be used in configurations. // LogLevel implements a helper type to be used in configurations.

View file

@ -9,9 +9,8 @@
package options package options
import ( import (
"log/slog"
"testing" "testing"
"golang.org/x/exp/slog"
) )
func TestMarshalFlag(t *testing.T) { func TestMarshalFlag(t *testing.T) {

View file

@ -12,13 +12,14 @@ package options
import ( import (
"fmt" "fmt"
"log" "log"
"log/slog"
"os" "os"
"github.com/csaf-poc/csaf_distribution/v3/util"
"github.com/BurntSushi/toml" "github.com/BurntSushi/toml"
"github.com/jessevdk/go-flags" "github.com/jessevdk/go-flags"
"github.com/mitchellh/go-homedir" "github.com/mitchellh/go-homedir"
"github.com/csaf-poc/csaf_distribution/v3/util"
) )
// Parser helps parsing command line arguments and loading // Parser helps parsing command line arguments and loading
@ -147,3 +148,13 @@ func ErrorCheck(err error) {
log.Fatalf("error: %v\n", err) log.Fatalf("error: %v\n", err)
} }
} }
// ErrorCheckStructured checks if err is not nil and terminates the program if
// so. This is similar to [ErrorCheck], but uses [slog] instead of the
// non-structured Go logging.
func ErrorCheckStructured(err error) {
if err != nil {
slog.Error("Error while executing program", "err", err)
os.Exit(1)
}
}