mirror of
https://github.com/gocsaf/csaf.git
synced 2025-12-22 18:15:42 +01:00
Add type to checker messages
* Add a type to checker messages, so the results can be interpreted better. Especially the difference between warning and errors can be used.
This commit is contained in:
parent
19d39b85d3
commit
c09e5f66f3
5 changed files with 182 additions and 110 deletions
|
|
@ -53,11 +53,11 @@ func (pgs pages) listed(path string, pro *processor) (bool, error) {
|
||||||
pro.badDirListings.use()
|
pro.badDirListings.use()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pro.badDirListings.add("Fetching %s failed: %v", base, err)
|
pro.badDirListings.error("Fetching %s failed: %v", base, err)
|
||||||
return false, errContinue
|
return false, errContinue
|
||||||
}
|
}
|
||||||
if res.StatusCode != http.StatusOK {
|
if res.StatusCode != http.StatusOK {
|
||||||
pro.badDirListings.add("Fetching %s failed. Status code %d (%s)",
|
pro.badDirListings.error("Fetching %s failed. Status code %d (%s)",
|
||||||
base, res.StatusCode, res.Status)
|
base, res.StatusCode, res.Status)
|
||||||
return false, errContinue
|
return false, errContinue
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// topicMessages stores the collected topicMessages for a specific topic.
|
// topicMessages stores the collected topicMessages for a specific topic.
|
||||||
type topicMessages []string
|
type topicMessages []Message
|
||||||
|
|
||||||
type processor struct {
|
type processor struct {
|
||||||
opts *options
|
opts *options
|
||||||
|
|
@ -120,14 +120,29 @@ func (wt whereType) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// add adds a message to this topic.
|
// add adds a message to this topic.
|
||||||
func (m *topicMessages) add(format string, args ...interface{}) {
|
func (m *topicMessages) add(typ MessageType, format string, args ...interface{}) {
|
||||||
*m = append(*m, fmt.Sprintf(format, args...))
|
*m = append(*m, Message{Type: typ, Text: fmt.Sprintf(format, args...)})
|
||||||
|
}
|
||||||
|
|
||||||
|
// error adds an error message to this topic.
|
||||||
|
func (m *topicMessages) error(format string, args ...interface{}) {
|
||||||
|
m.add(ErrorType, format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// warn adds a warning message to this topic.
|
||||||
|
func (m *topicMessages) warn(format string, args ...interface{}) {
|
||||||
|
m.add(WarnType, format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// info adds an info message to this topic.
|
||||||
|
func (m *topicMessages) info(format string, args ...interface{}) {
|
||||||
|
m.add(InfoType, format, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// use signals that we going to use this topic.
|
// use signals that we going to use this topic.
|
||||||
func (m *topicMessages) use() {
|
func (m *topicMessages) use() {
|
||||||
if *m == nil {
|
if *m == nil {
|
||||||
*m = []string{}
|
*m = []Message{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -318,7 +333,7 @@ func (p *processor) integrity(
|
||||||
files []string,
|
files []string,
|
||||||
base string,
|
base string,
|
||||||
mask whereType,
|
mask whereType,
|
||||||
lg func(string, ...interface{}),
|
lg func(MessageType, string, ...interface{}),
|
||||||
) error {
|
) error {
|
||||||
b, err := url.Parse(base)
|
b, err := url.Parse(base)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -331,7 +346,7 @@ func (p *processor) integrity(
|
||||||
for _, f := range files {
|
for _, f := range files {
|
||||||
fp, err := url.Parse(f)
|
fp, err := url.Parse(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lg("Bad URL %s: %v", f, err)
|
lg(ErrorType, "Bad URL %s: %v", f, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
u := b.ResolveReference(fp).String()
|
u := b.ResolveReference(fp).String()
|
||||||
|
|
@ -341,11 +356,11 @@ func (p *processor) integrity(
|
||||||
p.checkTLS(u)
|
p.checkTLS(u)
|
||||||
res, err := client.Get(u)
|
res, err := client.Get(u)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lg("Fetching %s failed: %v.", u, err)
|
lg(ErrorType, "Fetching %s failed: %v.", u, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if res.StatusCode != http.StatusOK {
|
if res.StatusCode != http.StatusOK {
|
||||||
lg("Fetching %s failed: Status code %d (%s)",
|
lg(ErrorType, "Fetching %s failed: Status code %d (%s)",
|
||||||
u, res.StatusCode, res.Status)
|
u, res.StatusCode, res.Status)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -362,17 +377,17 @@ func (p *processor) integrity(
|
||||||
tee := io.TeeReader(res.Body, hasher)
|
tee := io.TeeReader(res.Body, hasher)
|
||||||
return json.NewDecoder(tee).Decode(&doc)
|
return json.NewDecoder(tee).Decode(&doc)
|
||||||
}(); err != nil {
|
}(); err != nil {
|
||||||
lg("Reading %s failed: %v", u, err)
|
lg(ErrorType, "Reading %s failed: %v", u, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
errors, err := csaf.ValidateCSAF(doc)
|
errors, err := csaf.ValidateCSAF(doc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lg("Failed to validate %s: %v", u, err)
|
lg(ErrorType, "Failed to validate %s: %v", u, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if len(errors) > 0 {
|
if len(errors) > 0 {
|
||||||
lg("CSAF file %s has %d validation errors.", u, len(errors))
|
lg(ErrorType, "CSAF file %s has %d validation errors.", u, len(errors))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if file is in the right folder.
|
// Check if file is in the right folder.
|
||||||
|
|
@ -380,17 +395,17 @@ func (p *processor) integrity(
|
||||||
|
|
||||||
if date, err := p.expr.Eval(
|
if date, err := p.expr.Eval(
|
||||||
`$.document.tracking.initial_release_date`, doc); err != nil {
|
`$.document.tracking.initial_release_date`, doc); err != nil {
|
||||||
p.badFolders.add(
|
p.badFolders.error(
|
||||||
"Extracting 'initial_release_date' from %s failed: %v", u, err)
|
"Extracting 'initial_release_date' from %s failed: %v", u, err)
|
||||||
} else if text, ok := date.(string); !ok {
|
} else if text, ok := date.(string); !ok {
|
||||||
p.badFolders.add("'initial_release_date' is not a string in %s", u)
|
p.badFolders.error("'initial_release_date' is not a string in %s", u)
|
||||||
} else if d, err := time.Parse(time.RFC3339, text); err != nil {
|
} else if d, err := time.Parse(time.RFC3339, text); err != nil {
|
||||||
p.badFolders.add(
|
p.badFolders.error(
|
||||||
"Parsing 'initial_release_date' as RFC3339 failed in %s: %v", u, err)
|
"Parsing 'initial_release_date' as RFC3339 failed in %s: %v", u, err)
|
||||||
} else if m := yearFromURL.FindStringSubmatch(u); m == nil {
|
} else if m := yearFromURL.FindStringSubmatch(u); m == nil {
|
||||||
p.badFolders.add("No year folder found in %s", u)
|
p.badFolders.error("No year folder found in %s", u)
|
||||||
} else if year, _ := strconv.Atoi(m[1]); d.UTC().Year() != year {
|
} else if year, _ := strconv.Atoi(m[1]); d.UTC().Year() != year {
|
||||||
p.badFolders.add("%s should be in folder %d", u, d.UTC().Year())
|
p.badFolders.error("%s should be in folder %d", u, d.UTC().Year())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check hashes
|
// Check hashes
|
||||||
|
|
@ -406,11 +421,11 @@ func (p *processor) integrity(
|
||||||
hashFile := u + "." + x.ext
|
hashFile := u + "." + x.ext
|
||||||
p.checkTLS(hashFile)
|
p.checkTLS(hashFile)
|
||||||
if res, err = client.Get(hashFile); err != nil {
|
if res, err = client.Get(hashFile); err != nil {
|
||||||
p.badIntegrities.add("Fetching %s failed: %v.", hashFile, err)
|
p.badIntegrities.error("Fetching %s failed: %v.", hashFile, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if res.StatusCode != http.StatusOK {
|
if res.StatusCode != http.StatusOK {
|
||||||
p.badIntegrities.add("Fetching %s failed: Status code %d (%s)",
|
p.badIntegrities.error("Fetching %s failed: Status code %d (%s)",
|
||||||
hashFile, res.StatusCode, res.Status)
|
hashFile, res.StatusCode, res.Status)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -419,15 +434,15 @@ func (p *processor) integrity(
|
||||||
return util.HashFromReader(res.Body)
|
return util.HashFromReader(res.Body)
|
||||||
}()
|
}()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.badIntegrities.add("Reading %s failed: %v.", hashFile, err)
|
p.badIntegrities.error("Reading %s failed: %v.", hashFile, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if len(h) == 0 {
|
if len(h) == 0 {
|
||||||
p.badIntegrities.add("No hash found in %s.", hashFile)
|
p.badIntegrities.error("No hash found in %s.", hashFile)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !bytes.Equal(h, x.hash) {
|
if !bytes.Equal(h, x.hash) {
|
||||||
p.badIntegrities.add("%s hash of %s does not match %s.",
|
p.badIntegrities.error("%s hash of %s does not match %s.",
|
||||||
strings.ToUpper(x.ext), u, hashFile)
|
strings.ToUpper(x.ext), u, hashFile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -439,11 +454,11 @@ func (p *processor) integrity(
|
||||||
p.badSignatures.use()
|
p.badSignatures.use()
|
||||||
|
|
||||||
if res, err = client.Get(sigFile); err != nil {
|
if res, err = client.Get(sigFile); err != nil {
|
||||||
p.badSignatures.add("Fetching %s failed: %v.", sigFile, err)
|
p.badSignatures.error("Fetching %s failed: %v.", sigFile, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if res.StatusCode != http.StatusOK {
|
if res.StatusCode != http.StatusOK {
|
||||||
p.badSignatures.add("Fetching %s failed: status code %d (%s)",
|
p.badSignatures.error("Fetching %s failed: status code %d (%s)",
|
||||||
sigFile, res.StatusCode, res.Status)
|
sigFile, res.StatusCode, res.Status)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -457,7 +472,7 @@ func (p *processor) integrity(
|
||||||
return crypto.NewPGPSignatureFromArmored(string(all))
|
return crypto.NewPGPSignatureFromArmored(string(all))
|
||||||
}()
|
}()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.badSignatures.add("Loading signature from %s failed: %v.",
|
p.badSignatures.error("Loading signature from %s failed: %v.",
|
||||||
sigFile, err)
|
sigFile, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -473,7 +488,7 @@ func (p *processor) integrity(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !verified {
|
if !verified {
|
||||||
p.badSignatures.add("Signature of %s could not be verified.", u)
|
p.badSignatures.error("Signature of %s could not be verified.", u)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -484,11 +499,11 @@ func (p *processor) processROLIEFeed(feed string) error {
|
||||||
client := p.httpClient()
|
client := p.httpClient()
|
||||||
res, err := client.Get(feed)
|
res, err := client.Get(feed)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.badProviderMetadata.add("Cannot fetch feed %s: %v", feed, err)
|
p.badProviderMetadata.error("Cannot fetch feed %s: %v", feed, err)
|
||||||
return errContinue
|
return errContinue
|
||||||
}
|
}
|
||||||
if res.StatusCode != http.StatusOK {
|
if res.StatusCode != http.StatusOK {
|
||||||
p.badProviderMetadata.add("Fetching %s failed. Status code %d (%s)",
|
p.badProviderMetadata.error("Fetching %s failed. Status code %d (%s)",
|
||||||
feed, res.StatusCode, res.Status)
|
feed, res.StatusCode, res.Status)
|
||||||
return errContinue
|
return errContinue
|
||||||
}
|
}
|
||||||
|
|
@ -509,7 +524,7 @@ func (p *processor) processROLIEFeed(feed string) error {
|
||||||
|
|
||||||
}()
|
}()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.badProviderMetadata.add("Loading ROLIE feed failed: %v.", err)
|
p.badProviderMetadata.error("Loading ROLIE feed failed: %v.", err)
|
||||||
return errContinue
|
return errContinue
|
||||||
}
|
}
|
||||||
errors, err := csaf.ValidateROLIE(rolieDoc)
|
errors, err := csaf.ValidateROLIE(rolieDoc)
|
||||||
|
|
@ -517,15 +532,15 @@ func (p *processor) processROLIEFeed(feed string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(errors) > 0 {
|
if len(errors) > 0 {
|
||||||
p.badProviderMetadata.add("%s: Validating against JSON schema failed:", feed)
|
p.badProviderMetadata.error("%s: Validating against JSON schema failed:", feed)
|
||||||
for _, msg := range errors {
|
for _, msg := range errors {
|
||||||
p.badProviderMetadata.add(strings.ReplaceAll(msg, `%`, `%%`))
|
p.badProviderMetadata.error(strings.ReplaceAll(msg, `%`, `%%`))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
base, err := util.BaseURL(feed)
|
base, err := util.BaseURL(feed)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.badProviderMetadata.add("Bad base path: %v", err)
|
p.badProviderMetadata.error("Bad base path: %v", err)
|
||||||
return errContinue
|
return errContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -561,13 +576,13 @@ func (p *processor) checkIndex(base string, mask whereType) error {
|
||||||
|
|
||||||
res, err := client.Get(index)
|
res, err := client.Get(index)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.badIndices.add("Fetching %s failed: %v", index, err)
|
p.badIndices.error("Fetching %s failed: %v", index, err)
|
||||||
return errContinue
|
return errContinue
|
||||||
}
|
}
|
||||||
if res.StatusCode != http.StatusOK {
|
if res.StatusCode != http.StatusOK {
|
||||||
// It's optional
|
// It's optional
|
||||||
if res.StatusCode != http.StatusNotFound {
|
if res.StatusCode != http.StatusNotFound {
|
||||||
p.badIndices.add("Fetching %s failed. Status code %d (%s)",
|
p.badIndices.error("Fetching %s failed. Status code %d (%s)",
|
||||||
index, res.StatusCode, res.Status)
|
index, res.StatusCode, res.Status)
|
||||||
}
|
}
|
||||||
return errContinue
|
return errContinue
|
||||||
|
|
@ -583,7 +598,7 @@ func (p *processor) checkIndex(base string, mask whereType) error {
|
||||||
return files, scanner.Err()
|
return files, scanner.Err()
|
||||||
}()
|
}()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.badIndices.add("Reading %s failed: %v", index, err)
|
p.badIndices.error("Reading %s failed: %v", index, err)
|
||||||
return errContinue
|
return errContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -603,13 +618,13 @@ func (p *processor) checkChanges(base string, mask whereType) error {
|
||||||
p.badChanges.use()
|
p.badChanges.use()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.badChanges.add("Fetching %s failed: %v", changes, err)
|
p.badChanges.error("Fetching %s failed: %v", changes, err)
|
||||||
return errContinue
|
return errContinue
|
||||||
}
|
}
|
||||||
if res.StatusCode != http.StatusOK {
|
if res.StatusCode != http.StatusOK {
|
||||||
if res.StatusCode != http.StatusNotFound {
|
if res.StatusCode != http.StatusNotFound {
|
||||||
// It's optional
|
// It's optional
|
||||||
p.badChanges.add("Fetching %s failed. Status code %d (%s)",
|
p.badChanges.error("Fetching %s failed. Status code %d (%s)",
|
||||||
changes, res.StatusCode, res.Status)
|
changes, res.StatusCode, res.Status)
|
||||||
}
|
}
|
||||||
return errContinue
|
return errContinue
|
||||||
|
|
@ -640,14 +655,14 @@ func (p *processor) checkChanges(base string, mask whereType) error {
|
||||||
return times, files, nil
|
return times, files, nil
|
||||||
}()
|
}()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.badChanges.add("Reading %s failed: %v", changes, err)
|
p.badChanges.error("Reading %s failed: %v", changes, err)
|
||||||
return errContinue
|
return errContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
if !sort.SliceIsSorted(times, func(i, j int) bool {
|
if !sort.SliceIsSorted(times, func(i, j int) bool {
|
||||||
return times[j].Before(times[i])
|
return times[j].Before(times[i])
|
||||||
}) {
|
}) {
|
||||||
p.badChanges.add("%s is not sorted in descending order", changes)
|
p.badChanges.error("%s is not sorted in descending order", changes)
|
||||||
}
|
}
|
||||||
|
|
||||||
return p.integrity(files, base, mask, p.badChanges.add)
|
return p.integrity(files, base, mask, p.badChanges.add)
|
||||||
|
|
@ -667,7 +682,7 @@ func (p *processor) processROLIEFeeds(domain string, feeds [][]csaf.Feed) error
|
||||||
}
|
}
|
||||||
up, err := url.Parse(string(*feed.URL))
|
up, err := url.Parse(string(*feed.URL))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.badProviderMetadata.add("Invalid URL %s in feed: %v.", *feed.URL, err)
|
p.badProviderMetadata.error("Invalid URL %s in feed: %v.", *feed.URL, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
feedURL := base.ResolveReference(up).String()
|
feedURL := base.ResolveReference(up).String()
|
||||||
|
|
@ -693,7 +708,7 @@ func (p *processor) checkCSAFs(domain string) error {
|
||||||
if hasRolie {
|
if hasRolie {
|
||||||
var feeds [][]csaf.Feed
|
var feeds [][]csaf.Feed
|
||||||
if err := util.ReMarshalJSON(&feeds, rolie); err != nil {
|
if err := util.ReMarshalJSON(&feeds, rolie); err != nil {
|
||||||
p.badProviderMetadata.add("ROLIE feeds are not compatible: %v.", err)
|
p.badProviderMetadata.error("ROLIE feeds are not compatible: %v.", err)
|
||||||
} else if err := p.processROLIEFeeds(domain, feeds); err != nil {
|
} else if err := p.processROLIEFeeds(domain, feeds); err != nil {
|
||||||
if err != errContinue {
|
if err != errContinue {
|
||||||
return err
|
return err
|
||||||
|
|
@ -747,7 +762,7 @@ func (p *processor) checkMissing(string) error {
|
||||||
where = append(where, in+" "+mask.String())
|
where = append(where, in+" "+mask.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p.badIntegrities.add("%s %s", f, strings.Join(where, ", "))
|
p.badIntegrities.error("%s %s", f, strings.Join(where, ", "))
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -767,7 +782,7 @@ func (p *processor) checkInvalid(string) error {
|
||||||
|
|
||||||
if len(invalids) > 0 {
|
if len(invalids) > 0 {
|
||||||
sort.Strings(invalids)
|
sort.Strings(invalids)
|
||||||
p.badDirListings.add("advisories with invalid file names: %s",
|
p.badDirListings.error("advisories with invalid file names: %s",
|
||||||
strings.Join(invalids, ", "))
|
strings.Join(invalids, ", "))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -796,7 +811,7 @@ func (p *processor) checkListing(string) error {
|
||||||
|
|
||||||
if len(unlisted) > 0 {
|
if len(unlisted) > 0 {
|
||||||
sort.Strings(unlisted)
|
sort.Strings(unlisted)
|
||||||
p.badDirListings.add("Not listed advisories: %s",
|
p.badDirListings.error("Not listed advisories: %s",
|
||||||
strings.Join(unlisted, ", "))
|
strings.Join(unlisted, ", "))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -814,11 +829,11 @@ func (p *processor) checkProviderMetadata(domain string) error {
|
||||||
|
|
||||||
client := p.httpClient()
|
client := p.httpClient()
|
||||||
|
|
||||||
lpmd := csaf.LoadProviderMetadataForDomain(client, domain, p.badProviderMetadata.add)
|
lpmd := csaf.LoadProviderMetadataForDomain(client, domain, p.badProviderMetadata.warn)
|
||||||
|
|
||||||
if lpmd == nil {
|
if lpmd == nil {
|
||||||
p.badProviderMetadata.add("No valid provider-metadata.json found.")
|
p.badProviderMetadata.error("No valid provider-metadata.json found.")
|
||||||
p.badProviderMetadata.add("STOPPING here - cannot perform other checks.")
|
p.badProviderMetadata.error("STOPPING here - cannot perform other checks.")
|
||||||
return errStop
|
return errStop
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -842,12 +857,12 @@ func (p *processor) checkSecurity(domain string) error {
|
||||||
path := "https://" + domain + "/.well-known/security.txt"
|
path := "https://" + domain + "/.well-known/security.txt"
|
||||||
res, err := client.Get(path)
|
res, err := client.Get(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.badSecurity.add("Fetching %s failed: %v", path, err)
|
p.badSecurity.error("Fetching %s failed: %v", path, err)
|
||||||
return errContinue
|
return errContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
if res.StatusCode != http.StatusOK {
|
if res.StatusCode != http.StatusOK {
|
||||||
p.badSecurity.add("Fetching %s failed. Status code %d (%s)",
|
p.badSecurity.error("Fetching %s failed. Status code %d (%s)",
|
||||||
path, res.StatusCode, res.Status)
|
path, res.StatusCode, res.Status)
|
||||||
return errContinue
|
return errContinue
|
||||||
}
|
}
|
||||||
|
|
@ -864,18 +879,18 @@ func (p *processor) checkSecurity(domain string) error {
|
||||||
return "", lines.Err()
|
return "", lines.Err()
|
||||||
}()
|
}()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.badSecurity.add("Error while reading security.txt: %v", err)
|
p.badSecurity.error("Error while reading security.txt: %v", err)
|
||||||
return errContinue
|
return errContinue
|
||||||
}
|
}
|
||||||
if u == "" {
|
if u == "" {
|
||||||
p.badSecurity.add("No CSAF line found in security.txt.")
|
p.badSecurity.error("No CSAF line found in security.txt.")
|
||||||
return errContinue
|
return errContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to load
|
// Try to load
|
||||||
up, err := url.Parse(u)
|
up, err := url.Parse(u)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.badSecurity.add("CSAF URL '%s' invalid: %v", u, err)
|
p.badSecurity.error("CSAF URL '%s' invalid: %v", u, err)
|
||||||
return errContinue
|
return errContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -887,11 +902,11 @@ func (p *processor) checkSecurity(domain string) error {
|
||||||
u = base.ResolveReference(up).String()
|
u = base.ResolveReference(up).String()
|
||||||
p.checkTLS(u)
|
p.checkTLS(u)
|
||||||
if res, err = client.Get(u); err != nil {
|
if res, err = client.Get(u); err != nil {
|
||||||
p.badSecurity.add("Cannot fetch %s from security.txt: %v", u, err)
|
p.badSecurity.error("Cannot fetch %s from security.txt: %v", u, err)
|
||||||
return errContinue
|
return errContinue
|
||||||
}
|
}
|
||||||
if res.StatusCode != http.StatusOK {
|
if res.StatusCode != http.StatusOK {
|
||||||
p.badSecurity.add("Fetching %s failed. Status code %d (%s)",
|
p.badSecurity.error("Fetching %s failed. Status code %d (%s)",
|
||||||
u, res.StatusCode, res.Status)
|
u, res.StatusCode, res.Status)
|
||||||
return errContinue
|
return errContinue
|
||||||
}
|
}
|
||||||
|
|
@ -899,12 +914,12 @@ func (p *processor) checkSecurity(domain string) error {
|
||||||
// Compare checksums to already read provider-metadata.json.
|
// Compare checksums to already read provider-metadata.json.
|
||||||
h := sha256.New()
|
h := sha256.New()
|
||||||
if _, err := io.Copy(h, res.Body); err != nil {
|
if _, err := io.Copy(h, res.Body); err != nil {
|
||||||
p.badSecurity.add("Reading %s failed: %v", u, err)
|
p.badSecurity.error("Reading %s failed: %v", u, err)
|
||||||
return errContinue
|
return errContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
if !bytes.Equal(h.Sum(nil), p.pmd256) {
|
if !bytes.Equal(h.Sum(nil), p.pmd256) {
|
||||||
p.badSecurity.add("Content of %s from security.txt is not "+
|
p.badSecurity.error("Content of %s from security.txt is not "+
|
||||||
"identical to .well-known/csaf/provider-metadata.json", u)
|
"identical to .well-known/csaf/provider-metadata.json", u)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -921,18 +936,18 @@ func (p *processor) checkPGPKeys(domain string) error {
|
||||||
|
|
||||||
src, err := p.expr.Eval("$.public_openpgp_keys", p.pmd)
|
src, err := p.expr.Eval("$.public_openpgp_keys", p.pmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.badPGPs.add("No public OpenPGP keys found: %v.", err)
|
p.badPGPs.warn("No public OpenPGP keys found: %v.", err)
|
||||||
return errContinue
|
return errContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
var keys []csaf.PGPKey
|
var keys []csaf.PGPKey
|
||||||
if err := util.ReMarshalJSON(&keys, src); err != nil {
|
if err := util.ReMarshalJSON(&keys, src); err != nil {
|
||||||
p.badPGPs.add("Invalid public OpenPGP keys: %v.", err)
|
p.badPGPs.error("Invalid public OpenPGP keys: %v.", err)
|
||||||
return errContinue
|
return errContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(keys) == 0 {
|
if len(keys) == 0 {
|
||||||
p.badPGPs.add("No public OpenPGP keys found.")
|
p.badPGPs.info("No public OpenPGP keys found.")
|
||||||
return errContinue
|
return errContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -948,12 +963,12 @@ func (p *processor) checkPGPKeys(domain string) error {
|
||||||
for i := range keys {
|
for i := range keys {
|
||||||
key := &keys[i]
|
key := &keys[i]
|
||||||
if key.URL == nil {
|
if key.URL == nil {
|
||||||
p.badPGPs.add("Missing URL for fingerprint %x.", key.Fingerprint)
|
p.badPGPs.error("Missing URL for fingerprint %x.", key.Fingerprint)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
up, err := url.Parse(*key.URL)
|
up, err := url.Parse(*key.URL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.badPGPs.add("Invalid URL '%s': %v", *key.URL, err)
|
p.badPGPs.error("Invalid URL '%s': %v", *key.URL, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -962,11 +977,11 @@ func (p *processor) checkPGPKeys(domain string) error {
|
||||||
|
|
||||||
res, err := client.Get(u)
|
res, err := client.Get(u)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.badPGPs.add("Fetching public OpenPGP key %s failed: %v.", u, err)
|
p.badPGPs.error("Fetching public OpenPGP key %s failed: %v.", u, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if res.StatusCode != http.StatusOK {
|
if res.StatusCode != http.StatusOK {
|
||||||
p.badPGPs.add("Fetching public OpenPGP key %s status code: %d (%s)",
|
p.badPGPs.error("Fetching public OpenPGP key %s status code: %d (%s)",
|
||||||
u, res.StatusCode, res.Status)
|
u, res.StatusCode, res.Status)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -977,24 +992,24 @@ func (p *processor) checkPGPKeys(domain string) error {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.badPGPs.add("Reading public OpenPGP key %s failed: %v", u, err)
|
p.badPGPs.error("Reading public OpenPGP key %s failed: %v", u, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if ckey.GetFingerprint() != string(key.Fingerprint) {
|
if ckey.GetFingerprint() != string(key.Fingerprint) {
|
||||||
p.badPGPs.add("Fingerprint of public OpenPGP key %s does not match remotely loaded.", u)
|
p.badPGPs.error("Fingerprint of public OpenPGP key %s does not match remotely loaded.", u)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
keyring, err := crypto.NewKeyRing(ckey)
|
keyring, err := crypto.NewKeyRing(ckey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.badPGPs.add("Creating store for public OpenPGP key %s failed: %v.", u, err)
|
p.badPGPs.error("Creating store for public OpenPGP key %s failed: %v.", u, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
p.keys = append(p.keys, keyring)
|
p.keys = append(p.keys, keyring)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(p.keys) == 0 {
|
if len(p.keys) == 0 {
|
||||||
p.badPGPs.add("No OpenPGP keys loaded.")
|
p.badPGPs.info("No OpenPGP keys loaded.")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -1012,11 +1027,11 @@ func (p *processor) checkWellknownMetadataReporter(domain string) error {
|
||||||
|
|
||||||
res, err := client.Get(path)
|
res, err := client.Get(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.badWellknownMetadata.add("Fetching %s failed: %v", path, err)
|
p.badWellknownMetadata.error("Fetching %s failed: %v", path, err)
|
||||||
return errContinue
|
return errContinue
|
||||||
}
|
}
|
||||||
if res.StatusCode != http.StatusOK {
|
if res.StatusCode != http.StatusOK {
|
||||||
p.badWellknownMetadata.add("Fetching %s failed. Status code %d (%s)",
|
p.badWellknownMetadata.error("Fetching %s failed. Status code %d (%s)",
|
||||||
path, res.StatusCode, res.Status)
|
path, res.StatusCode, res.Status)
|
||||||
return errContinue
|
return errContinue
|
||||||
}
|
}
|
||||||
|
|
@ -1036,11 +1051,11 @@ func (p *processor) checkDNSPathReporter(domain string) error {
|
||||||
path := "https://csaf.data.security." + domain
|
path := "https://csaf.data.security." + domain
|
||||||
res, err := client.Get(path)
|
res, err := client.Get(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.badDNSPath.add("Fetching %s failed: %v", path, err)
|
p.badDNSPath.error("Fetching %s failed: %v", path, err)
|
||||||
return errContinue
|
return errContinue
|
||||||
}
|
}
|
||||||
if res.StatusCode != http.StatusOK {
|
if res.StatusCode != http.StatusOK {
|
||||||
p.badDNSPath.add("Fetching %s failed. Status code %d (%s)",
|
p.badDNSPath.error("Fetching %s failed. Status code %d (%s)",
|
||||||
path, res.StatusCode, res.Status)
|
path, res.StatusCode, res.Status)
|
||||||
return errContinue
|
return errContinue
|
||||||
}
|
}
|
||||||
|
|
@ -1048,12 +1063,12 @@ func (p *processor) checkDNSPathReporter(domain string) error {
|
||||||
defer res.Body.Close()
|
defer res.Body.Close()
|
||||||
content, err := io.ReadAll(res.Body)
|
content, err := io.ReadAll(res.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.badDNSPath.add("Error while reading the response from %s", path)
|
p.badDNSPath.error("Error while reading the response from %s", path)
|
||||||
return errContinue
|
return errContinue
|
||||||
}
|
}
|
||||||
hash.Write(content)
|
hash.Write(content)
|
||||||
if !bytes.Equal(hash.Sum(nil), p.pmd256) {
|
if !bytes.Equal(hash.Sum(nil), p.pmd256) {
|
||||||
p.badDNSPath.add("%s does not serve the same provider-metadata.json as previously found", path)
|
p.badDNSPath.error("%s does not serve the same provider-metadata.json as previously found", path)
|
||||||
return errContinue
|
return errContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,31 @@
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// MessageType is the kind of the message.
|
||||||
|
type MessageType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// InfoType represents an info message.
|
||||||
|
InfoType MessageType = iota
|
||||||
|
// WarnType represents a warning message.
|
||||||
|
WarnType
|
||||||
|
// ErrorType represents an error message.
|
||||||
|
ErrorType
|
||||||
|
)
|
||||||
|
|
||||||
|
// Message is a typed text message.
|
||||||
|
type Message struct {
|
||||||
|
Type MessageType `json:"type"`
|
||||||
|
Text string `json:"text"`
|
||||||
|
}
|
||||||
|
|
||||||
// Requirement a single requirement report of a domain.
|
// Requirement a single requirement report of a domain.
|
||||||
type Requirement struct {
|
type Requirement struct {
|
||||||
Num int `json:"num"`
|
Num int `json:"num"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Messages []string `json:"messages,omitempty"`
|
Messages []Message `json:"messages,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Domain are the results of a domain.
|
// Domain are the results of a domain.
|
||||||
|
|
@ -28,6 +48,43 @@ type Report struct {
|
||||||
Date string `json:"date,omitempty"`
|
Date string `json:"date,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Requirement) message(msg ...string) {
|
// HasErrors tells if this requirement has errors.
|
||||||
r.Messages = append(r.Messages, msg...)
|
func (r *Requirement) HasErrors() bool {
|
||||||
|
for i := range r.Messages {
|
||||||
|
if r.Messages[i].Type == ErrorType {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasErrors tells if this domain has errors.
|
||||||
|
func (d *Domain) HasErrors() bool {
|
||||||
|
for _, r := range d.Requirements {
|
||||||
|
if r.HasErrors() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// String implements fmt.Stringer interface.
|
||||||
|
func (mt MessageType) String() string {
|
||||||
|
switch mt {
|
||||||
|
case InfoType:
|
||||||
|
return "INFO"
|
||||||
|
case WarnType:
|
||||||
|
return "WARN"
|
||||||
|
case ErrorType:
|
||||||
|
return "ERROR"
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("MessageType (%d)", int(mt))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// message appends typed messages to a requirement.
|
||||||
|
func (r *Requirement) message(typ MessageType, texts ...string) {
|
||||||
|
for _, text := range texts {
|
||||||
|
r.Messages = append(r.Messages, Message{Type: typ, Text: text})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,11 +48,11 @@ func (bc *baseReporter) requirement(domain *Domain) *Requirement {
|
||||||
func (r *tlsReporter) report(p *processor, domain *Domain) {
|
func (r *tlsReporter) report(p *processor, domain *Domain) {
|
||||||
req := r.requirement(domain)
|
req := r.requirement(domain)
|
||||||
if p.noneTLS == nil {
|
if p.noneTLS == nil {
|
||||||
req.message("No TLS checks performed.")
|
req.message(InfoType, "No TLS checks performed.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(p.noneTLS) == 0 {
|
if len(p.noneTLS) == 0 {
|
||||||
req.message("All tested URLs were HTTPS.")
|
req.message(InfoType, "All tested URLs were HTTPS.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -63,8 +63,8 @@ func (r *tlsReporter) report(p *processor, domain *Domain) {
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
sort.Strings(urls)
|
sort.Strings(urls)
|
||||||
req.message("Following non-HTTPS URLs were used:")
|
req.message(ErrorType, "Following non-HTTPS URLs were used:")
|
||||||
req.message(urls...)
|
req.message(ErrorType, urls...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// report tests if redirects are used and sets the "message" field value
|
// report tests if redirects are used and sets the "message" field value
|
||||||
|
|
@ -72,7 +72,7 @@ func (r *tlsReporter) report(p *processor, domain *Domain) {
|
||||||
func (r *redirectsReporter) report(p *processor, domain *Domain) {
|
func (r *redirectsReporter) report(p *processor, domain *Domain) {
|
||||||
req := r.requirement(domain)
|
req := r.requirement(domain)
|
||||||
if len(p.redirects) == 0 {
|
if len(p.redirects) == 0 {
|
||||||
req.message("No redirections found.")
|
req.message(InfoType, "No redirections found.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -86,7 +86,7 @@ func (r *redirectsReporter) report(p *processor, domain *Domain) {
|
||||||
for i, k := range keys {
|
for i, k := range keys {
|
||||||
keys[i] = fmt.Sprintf("Redirect %s: %s", k, p.redirects[k])
|
keys[i] = fmt.Sprintf("Redirect %s: %s", k, p.redirects[k])
|
||||||
}
|
}
|
||||||
req.Messages = keys
|
req.message(WarnType, keys...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// report tests if an provider-metadata.json are available and sets the
|
// report tests if an provider-metadata.json are available and sets the
|
||||||
|
|
@ -94,11 +94,11 @@ func (r *redirectsReporter) report(p *processor, domain *Domain) {
|
||||||
func (r *providerMetadataReport) report(p *processor, domain *Domain) {
|
func (r *providerMetadataReport) report(p *processor, domain *Domain) {
|
||||||
req := r.requirement(domain)
|
req := r.requirement(domain)
|
||||||
if !p.badProviderMetadata.used() {
|
if !p.badProviderMetadata.used() {
|
||||||
req.message("No provider-metadata.json checked.")
|
req.message(InfoType, "No provider-metadata.json checked.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(p.badProviderMetadata) == 0 {
|
if len(p.badProviderMetadata) == 0 {
|
||||||
req.message("Found good provider metadata.")
|
req.message(InfoType, "Found good provider metadata.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
req.Messages = p.badProviderMetadata
|
req.Messages = p.badProviderMetadata
|
||||||
|
|
@ -109,11 +109,11 @@ func (r *providerMetadataReport) report(p *processor, domain *Domain) {
|
||||||
func (r *securityReporter) report(p *processor, domain *Domain) {
|
func (r *securityReporter) report(p *processor, domain *Domain) {
|
||||||
req := r.requirement(domain)
|
req := r.requirement(domain)
|
||||||
if !p.badSecurity.used() {
|
if !p.badSecurity.used() {
|
||||||
req.message("No security.txt checked.")
|
req.message(InfoType, "No security.txt checked.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(p.badSecurity) == 0 {
|
if len(p.badSecurity) == 0 {
|
||||||
req.message("Found good security.txt.")
|
req.message(InfoType, "Found good security.txt.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
req.Messages = p.badSecurity
|
req.Messages = p.badSecurity
|
||||||
|
|
@ -123,11 +123,11 @@ func (r *securityReporter) report(p *processor, domain *Domain) {
|
||||||
func (r *wellknownMetadataReporter) report(p *processor, domain *Domain) {
|
func (r *wellknownMetadataReporter) report(p *processor, domain *Domain) {
|
||||||
req := r.requirement(domain)
|
req := r.requirement(domain)
|
||||||
if !p.badWellknownMetadata.used() {
|
if !p.badWellknownMetadata.used() {
|
||||||
req.message("No check if provider-metadata.json is under /.well-known/csaf/ was done.")
|
req.message(InfoType, "No check if provider-metadata.json is under /.well-known/csaf/ was done.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(p.badWellknownMetadata) == 0 {
|
if len(p.badWellknownMetadata) == 0 {
|
||||||
req.message("Found /.well-known/csaf/provider-metadata.json")
|
req.message(InfoType, "Found /.well-known/csaf/provider-metadata.json")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
req.Messages = p.badWellknownMetadata
|
req.Messages = p.badWellknownMetadata
|
||||||
|
|
@ -137,11 +137,11 @@ func (r *wellknownMetadataReporter) report(p *processor, domain *Domain) {
|
||||||
func (r *dnsPathReporter) report(p *processor, domain *Domain) {
|
func (r *dnsPathReporter) report(p *processor, domain *Domain) {
|
||||||
req := r.requirement(domain)
|
req := r.requirement(domain)
|
||||||
if !p.badDNSPath.used() {
|
if !p.badDNSPath.used() {
|
||||||
req.message("No download from https://csaf.data.security.DOMAIN attempted.")
|
req.message(InfoType, "No download from https://csaf.data.security.DOMAIN attempted.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(p.badDNSPath) == 0 {
|
if len(p.badDNSPath) == 0 {
|
||||||
req.message("https://csaf.data.security.DOMAIN is available and serves the provider-metadata.json.")
|
req.message(InfoType, "https://csaf.data.security.DOMAIN is available and serves the provider-metadata.json.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
req.Messages = p.badDNSPath
|
req.Messages = p.badDNSPath
|
||||||
|
|
@ -150,11 +150,11 @@ func (r *dnsPathReporter) report(p *processor, domain *Domain) {
|
||||||
func (r *oneFolderPerYearReport) report(p *processor, domain *Domain) {
|
func (r *oneFolderPerYearReport) report(p *processor, domain *Domain) {
|
||||||
req := r.requirement(domain)
|
req := r.requirement(domain)
|
||||||
if !p.badFolders.used() {
|
if !p.badFolders.used() {
|
||||||
req.message("No checks if files are in right folders were performed.")
|
req.message(InfoType, "No checks if files are in right folders were performed.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(p.badFolders) == 0 {
|
if len(p.badFolders) == 0 {
|
||||||
req.message("All CSAF files are in the right folders.")
|
req.message(InfoType, "All CSAF files are in the right folders.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
req.Messages = p.badFolders
|
req.Messages = p.badFolders
|
||||||
|
|
@ -163,11 +163,11 @@ func (r *oneFolderPerYearReport) report(p *processor, domain *Domain) {
|
||||||
func (r *indexReporter) report(p *processor, domain *Domain) {
|
func (r *indexReporter) report(p *processor, domain *Domain) {
|
||||||
req := r.requirement(domain)
|
req := r.requirement(domain)
|
||||||
if !p.badIndices.used() {
|
if !p.badIndices.used() {
|
||||||
req.message("No index.txt checked.")
|
req.message(InfoType, "No index.txt checked.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(p.badIndices) == 0 {
|
if len(p.badIndices) == 0 {
|
||||||
req.message("Found good index.txt.")
|
req.message(InfoType, "Found good index.txt.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
req.Messages = p.badIndices
|
req.Messages = p.badIndices
|
||||||
|
|
@ -176,11 +176,11 @@ func (r *indexReporter) report(p *processor, domain *Domain) {
|
||||||
func (r *changesReporter) report(p *processor, domain *Domain) {
|
func (r *changesReporter) report(p *processor, domain *Domain) {
|
||||||
req := r.requirement(domain)
|
req := r.requirement(domain)
|
||||||
if !p.badChanges.used() {
|
if !p.badChanges.used() {
|
||||||
req.message("No changes.csv checked.")
|
req.message(InfoType, "No changes.csv checked.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(p.badChanges) == 0 {
|
if len(p.badChanges) == 0 {
|
||||||
req.message("Found good changes.csv.")
|
req.message(InfoType, "Found good changes.csv.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
req.Messages = p.badChanges
|
req.Messages = p.badChanges
|
||||||
|
|
@ -189,11 +189,11 @@ func (r *changesReporter) report(p *processor, domain *Domain) {
|
||||||
func (r *directoryListingsReporter) report(p *processor, domain *Domain) {
|
func (r *directoryListingsReporter) report(p *processor, domain *Domain) {
|
||||||
req := r.requirement(domain)
|
req := r.requirement(domain)
|
||||||
if !p.badDirListings.used() {
|
if !p.badDirListings.used() {
|
||||||
req.message("No directory listings checked.")
|
req.message(InfoType, "No directory listings checked.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(p.badDirListings) == 0 {
|
if len(p.badDirListings) == 0 {
|
||||||
req.message("All directory listings are valid.")
|
req.message(InfoType, "All directory listings are valid.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
req.Messages = p.badDirListings
|
req.Messages = p.badDirListings
|
||||||
|
|
@ -202,11 +202,11 @@ func (r *directoryListingsReporter) report(p *processor, domain *Domain) {
|
||||||
func (r *integrityReporter) report(p *processor, domain *Domain) {
|
func (r *integrityReporter) report(p *processor, domain *Domain) {
|
||||||
req := r.requirement(domain)
|
req := r.requirement(domain)
|
||||||
if !p.badIntegrities.used() {
|
if !p.badIntegrities.used() {
|
||||||
req.message("No checksums checked.")
|
req.message(InfoType, "No checksums checked.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(p.badIntegrities) == 0 {
|
if len(p.badIntegrities) == 0 {
|
||||||
req.message("All checksums match.")
|
req.message(InfoType, "All checksums match.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
req.Messages = p.badIntegrities
|
req.Messages = p.badIntegrities
|
||||||
|
|
@ -215,23 +215,23 @@ func (r *integrityReporter) report(p *processor, domain *Domain) {
|
||||||
func (r *signaturesReporter) report(p *processor, domain *Domain) {
|
func (r *signaturesReporter) report(p *processor, domain *Domain) {
|
||||||
req := r.requirement(domain)
|
req := r.requirement(domain)
|
||||||
if !p.badSignatures.used() {
|
if !p.badSignatures.used() {
|
||||||
req.message("No signatures checked.")
|
req.message(InfoType, "No signatures checked.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
req.Messages = p.badSignatures
|
req.Messages = p.badSignatures
|
||||||
if len(p.badSignatures) == 0 {
|
if len(p.badSignatures) == 0 {
|
||||||
req.message("All signatures verified.")
|
req.message(InfoType, "All signatures verified.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *publicPGPKeyReporter) report(p *processor, domain *Domain) {
|
func (r *publicPGPKeyReporter) report(p *processor, domain *Domain) {
|
||||||
req := r.requirement(domain)
|
req := r.requirement(domain)
|
||||||
if !p.badPGPs.used() {
|
if !p.badPGPs.used() {
|
||||||
req.message("No public OpenPGP keys loaded.")
|
req.message(InfoType, "No public OpenPGP keys loaded.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
req.Messages = p.badPGPs
|
req.Messages = p.badPGPs
|
||||||
if len(p.keys) > 0 {
|
if len(p.keys) > 0 {
|
||||||
req.message(fmt.Sprintf("%d public OpenPGP key(s) loaded.", len(p.keys)))
|
req.message(InfoType, fmt.Sprintf("%d public OpenPGP key(s) loaded.", len(p.keys)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,13 @@
|
||||||
<body>
|
<body>
|
||||||
<h1>CSAF-Checker - Report</h1>
|
<h1>CSAF-Checker - Report</h1>
|
||||||
{{- range .Domains }}
|
{{- range .Domains }}
|
||||||
<h2>{{ .Name }}</h2>
|
<h2>{{ .Name }}{{ if .HasErrors }} (failed){{ end }}</h2>
|
||||||
|
|
||||||
<dl>
|
<dl>
|
||||||
{{ range .Requirements }}
|
{{ range .Requirements }}
|
||||||
<dt><strong>Requirement {{ .Num }}: {{ .Description }}</strong></dt>
|
<dt><strong>Requirement {{ .Num }}: {{ .Description }}{{ if .HasErrors }} (failed){{ end }}</strong></dt>
|
||||||
{{ range .Messages }}
|
{{ range .Messages }}
|
||||||
<dd>- {{ . }}</dd>
|
<dd>- {{ .Type }}: {{ .Text }}</dd>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</dl>
|
</dl>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue