mirror of
https://github.com/gocsaf/csaf.git
synced 2025-12-22 18:15:42 +01:00
Implement rule depending error check.
This commit is contained in:
parent
c7453a6448
commit
7501c60bf4
3 changed files with 111 additions and 20 deletions
|
|
@ -149,6 +149,19 @@ func (m *topicMessages) reset() { *m = nil }
|
||||||
// used returns true if we have used this topic.
|
// used returns true if we have used this topic.
|
||||||
func (m *topicMessages) used() bool { return *m != nil }
|
func (m *topicMessages) used() bool { return *m != nil }
|
||||||
|
|
||||||
|
// hasErrors checks if there are any error messages.
|
||||||
|
func (m *topicMessages) hasErrors() bool {
|
||||||
|
if !m.used() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, msg := range *m {
|
||||||
|
if msg.Type == ErrorType {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// newProcessor returns a processor structure after assigning the given options to the opts attribute
|
// newProcessor returns a processor structure after assigning the given options to the opts attribute
|
||||||
// and initializing the "alreadyChecked" and "expr" fields.
|
// and initializing the "alreadyChecked" and "expr" fields.
|
||||||
func newProcessor(opts *options) (*processor, error) {
|
func newProcessor(opts *options) (*processor, error) {
|
||||||
|
|
@ -263,10 +276,13 @@ func (p *processor) run(domains []string) (*Report, error) {
|
||||||
rules = trustedProviderRules
|
rules = trustedProviderRules
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, r := range rules.reporters() {
|
// 18, 19, 20 should always be checked.
|
||||||
|
for _, r := range rules.reporters([]int{18, 19, 20}) {
|
||||||
r.report(p, domain)
|
r.report(p, domain)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
domain.Passed = rules.eval(p)
|
||||||
|
|
||||||
report.Domains = append(report.Domains, domain)
|
report.Domains = append(report.Domains, domain)
|
||||||
p.clean()
|
p.clean()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ type Domain struct {
|
||||||
Publisher *csaf.Publisher `json:"publisher,omitempty"`
|
Publisher *csaf.Publisher `json:"publisher,omitempty"`
|
||||||
Role *csaf.MetadataRole `json:"role,omitempty"`
|
Role *csaf.MetadataRole `json:"role,omitempty"`
|
||||||
Requirements []*Requirement `json:"requirements,omitempty"`
|
Requirements []*Requirement `json:"requirements,omitempty"`
|
||||||
|
Passed bool `json:"passed"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReportTime stores the time of the report.
|
// ReportTime stores the time of the report.
|
||||||
|
|
@ -80,12 +81,7 @@ func (r *Requirement) Append(msgs []Message) {
|
||||||
|
|
||||||
// HasErrors tells if this domain has errors.
|
// HasErrors tells if this domain has errors.
|
||||||
func (d *Domain) HasErrors() bool {
|
func (d *Domain) HasErrors() bool {
|
||||||
for _, r := range d.Requirements {
|
return !d.Passed
|
||||||
if r.HasErrors() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// String implements fmt.Stringer interface.
|
// String implements fmt.Stringer interface.
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/csaf-poc/csaf_distribution/v2/csaf"
|
"github.com/csaf-poc/csaf_distribution/v2/csaf"
|
||||||
|
|
@ -54,6 +55,22 @@ var (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// roleRequirements returns the rules for the given role.
|
||||||
|
func roleRequirements(role csaf.MetadataRole) *requirementRules {
|
||||||
|
switch role {
|
||||||
|
case csaf.MetadataRoleTrustedProvider:
|
||||||
|
return trustedProviderRules
|
||||||
|
case csaf.MetadataRoleProvider:
|
||||||
|
return providerRules
|
||||||
|
case csaf.MetadataRolePublisher:
|
||||||
|
return publisherRules
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ruleAtoms is a helper function to build the leaves of
|
||||||
|
// a rules tree.
|
||||||
func ruleAtoms(nums ...int) []*requirementRules {
|
func ruleAtoms(nums ...int) []*requirementRules {
|
||||||
rules := make([]*requirementRules, len(nums))
|
rules := make([]*requirementRules, len(nums))
|
||||||
for i, num := range nums {
|
for i, num := range nums {
|
||||||
|
|
@ -65,16 +82,17 @@ func ruleAtoms(nums ...int) []*requirementRules {
|
||||||
return rules
|
return rules
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rules *requirementRules) reporters() []reporter {
|
// reporters assembles a list of reporters needed for a given set
|
||||||
|
// of rules. The given nums are mandatory.
|
||||||
|
func (rules *requirementRules) reporters(nums []int) []reporter {
|
||||||
if rules == nil {
|
if rules == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
var nums []int
|
|
||||||
|
|
||||||
var recurse func(*requirementRules)
|
var recurse func(*requirementRules)
|
||||||
recurse = func(rules *requirementRules) {
|
recurse = func(rules *requirementRules) {
|
||||||
if rules.satisfies != 0 {
|
if rules.satisfies != 0 {
|
||||||
// There should not be any dupes
|
// There should not be any dupes.
|
||||||
for _, n := range nums {
|
for _, n := range nums {
|
||||||
if n == rules.satisfies {
|
if n == rules.satisfies {
|
||||||
goto doRecurse
|
goto doRecurse
|
||||||
|
|
@ -99,16 +117,77 @@ func (rules *requirementRules) reporters() []reporter {
|
||||||
return reps
|
return reps
|
||||||
}
|
}
|
||||||
|
|
||||||
// roleRequirements returns the rules for the given role.
|
// eval evalutes a set of rules given a given processor state.
|
||||||
func roleRequirements(role csaf.MetadataRole) *requirementRules {
|
func (rules *requirementRules) eval(p *processor) bool {
|
||||||
switch role {
|
if rules == nil {
|
||||||
case csaf.MetadataRoleTrustedProvider:
|
return false
|
||||||
return trustedProviderRules
|
}
|
||||||
case csaf.MetadataRoleProvider:
|
|
||||||
return providerRules
|
var recurse func(*requirementRules) bool
|
||||||
case csaf.MetadataRolePublisher:
|
|
||||||
return publisherRules
|
recurse = func(rules *requirementRules) bool {
|
||||||
|
if rules.satisfies != 0 {
|
||||||
|
return p.eval(rules.satisfies)
|
||||||
|
}
|
||||||
|
switch rules.cond {
|
||||||
|
case condAll:
|
||||||
|
for _, sub := range rules.subs {
|
||||||
|
if !recurse(sub) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
case condOneOf:
|
||||||
|
for _, sub := range rules.subs {
|
||||||
|
if recurse(sub) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("unexpected cond %v in eval", rules.cond))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return recurse(rules)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *processor) eval(requirement int) bool {
|
||||||
|
|
||||||
|
switch requirement {
|
||||||
|
case 1:
|
||||||
|
return !p.invalidAdvisories.hasErrors()
|
||||||
|
case 2:
|
||||||
|
return !p.badFilenames.hasErrors()
|
||||||
|
case 3:
|
||||||
|
return len(p.noneTLS) == 0
|
||||||
|
|
||||||
|
case 8:
|
||||||
|
return !p.badSecurity.hasErrors()
|
||||||
|
case 9:
|
||||||
|
return !p.badWellknownMetadata.hasErrors()
|
||||||
|
case 10:
|
||||||
|
return !p.badDNSPath.hasErrors()
|
||||||
|
|
||||||
|
case 11:
|
||||||
|
return !p.badFolders.hasErrors()
|
||||||
|
case 12:
|
||||||
|
return !p.badIndices.hasErrors()
|
||||||
|
case 13:
|
||||||
|
return !p.badChanges.hasErrors()
|
||||||
|
case 14:
|
||||||
|
return !p.badDirListings.hasErrors()
|
||||||
|
|
||||||
|
case 15:
|
||||||
|
return !p.badROLIEfeed.hasErrors()
|
||||||
|
case 16:
|
||||||
|
// TODO: Implement me!
|
||||||
|
return true
|
||||||
|
case 17:
|
||||||
|
// TODO: Implement me!
|
||||||
|
return true
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil
|
panic(fmt.Sprintf("testing unexpected requirement %d", requirement))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue