diff --git a/cmd/csaf_aggregator/config.go b/cmd/csaf_aggregator/config.go index 3943a44..a389704 100644 --- a/cmd/csaf_aggregator/config.go +++ b/cmd/csaf_aggregator/config.go @@ -26,11 +26,12 @@ import ( ) const ( - defaultConfigPath = "aggregator.toml" - defaultWorkers = 10 - defaultFolder = "/var/www" - defaultWeb = "/var/www/html" - defaultDomain = "https://example.com" + defaultConfigPath = "aggregator.toml" + defaultWorkers = 10 + defaultFolder = "/var/www" + defaultWeb = "/var/www/html" + defaultDomain = "https://example.com" + defaultUpdateInterval = "on best effort" ) type provider struct { @@ -44,6 +45,9 @@ type provider struct { // ServiceDocument incidates if we should create a service.json document. ServiceDocument *bool `toml:"create_service_document"` AggregatoryCategory *csaf.AggregatorCategory `toml:"category"` + + // UpdateInterval is as the mandatory `update_interval` if this is a publisher. + UpdateInterval *string `toml:"update_interval"` } type config struct { @@ -81,6 +85,10 @@ type config struct { // ServiceDocument incidates if we should create a service.json document. ServiceDocument bool `toml:"create_service_document"` + // UpdateInterval is used for publishers a the mandatory field + // 'update_interval'. + UpdateInterval *string + keyMu sync.Mutex key *crypto.Key keyErr error @@ -96,6 +104,17 @@ func (c *config) tooOldForInterims() func(time.Time) bool { return func(t time.Time) bool { return t.Before(from) } } +// updateInterval returns the update interval of a publisher. +func (p *provider) updateInterval(c *config) string { + if p.UpdateInterval != nil { + return *p.UpdateInterval + } + if c.UpdateInterval != nil { + return *c.UpdateInterval + } + return defaultUpdateInterval +} + // serviceDocument tells if we should generate a service document for a // given provider. func (p *provider) serviceDocument(c *config) bool { diff --git a/cmd/csaf_aggregator/full.go b/cmd/csaf_aggregator/full.go index fef169c..6f3b86a 100644 --- a/cmd/csaf_aggregator/full.go +++ b/cmd/csaf_aggregator/full.go @@ -14,6 +14,7 @@ import ( "log" "os" "path/filepath" + "strings" "sync" "time" @@ -128,8 +129,8 @@ func (p *processor) full() error { wg.Wait() // Assemble aggregator data structure. - - csafProviders := make([]*csaf.AggregatorCSAFProvider, 0, len(jobs)) + var providers []*csaf.AggregatorCSAFProvider + var publishers []*csaf.AggregatorCSAFPublisher for i := range jobs { j := &jobs[i] @@ -142,10 +143,22 @@ func (p *processor) full() error { "error: '%s' does not produce any result.\n", j.provider.Name) continue } - csafProviders = append(csafProviders, j.aggregatorProvider) + + // "https://" signals a publisher. + if strings.HasPrefix(j.provider.Domain, "https://") { + + var pub csaf.AggregatorCSAFPublisher + + pub.FromProvider(j.aggregatorProvider) + pub.UpdateInterval = j.provider.updateInterval(p.cfg) + + publishers = append(publishers, &pub) + } else { + providers = append(providers, j.aggregatorProvider) + } } - if len(csafProviders) == 0 { + if len(providers)+len(publishers) == 0 { return errors.New("all jobs failed, stopping") } @@ -156,11 +169,12 @@ func (p *processor) full() error { lastUpdated := csaf.TimeStamp(time.Now().UTC()) agg := csaf.Aggregator{ - Aggregator: &p.cfg.Aggregator, - Version: &version, - CanonicalURL: &canonicalURL, - CSAFProviders: csafProviders, - LastUpdated: &lastUpdated, + Aggregator: &p.cfg.Aggregator, + Version: &version, + CanonicalURL: &canonicalURL, + CSAFProviders: providers, + CSAFPublishers: publishers, + LastUpdated: &lastUpdated, } web := filepath.Join(p.cfg.Web, ".well-known", "csaf-aggregator")