From c7453a644825ddbb1a5c81a8934a82f2af521630 Mon Sep 17 00:00:00 2001 From: "Sascha L. Teichmann" Date: Tue, 13 Jun 2023 12:25:19 +0200 Subject: [PATCH] Be more precise with conditional rules. --- cmd/csaf_checker/processor.go | 11 +++- cmd/csaf_checker/reporters.go | 42 ------------- cmd/csaf_checker/rules.go | 114 ++++++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+), 43 deletions(-) create mode 100644 cmd/csaf_checker/rules.go diff --git a/cmd/csaf_checker/processor.go b/cmd/csaf_checker/processor.go index 38644c9..6d1374d 100644 --- a/cmd/csaf_checker/processor.go +++ b/cmd/csaf_checker/processor.go @@ -254,7 +254,16 @@ func (p *processor) run(domains []string) (*Report, error) { continue } - for _, r := range buildReporters(*domain.Role) { + rules := roleRequirements(*domain.Role) + // TODO: store error base on rules eval in report. + if rules == nil { + log.Printf( + "WARN: Cannot find requirement rules for role %q. Assuming trusted provider.\n", + *domain.Role) + rules = trustedProviderRules + } + + for _, r := range rules.reporters() { r.report(p, domain) } diff --git a/cmd/csaf_checker/reporters.go b/cmd/csaf_checker/reporters.go index 493732e..41b8b96 100644 --- a/cmd/csaf_checker/reporters.go +++ b/cmd/csaf_checker/reporters.go @@ -12,8 +12,6 @@ import ( "fmt" "sort" "strings" - - "github.com/csaf-poc/csaf_distribution/v2/csaf" ) type ( @@ -72,46 +70,6 @@ var reporters = [23]reporter{ &mirrorReporter{baseReporter{num: 23, description: "Mirror"}}, } -var roleImplies = map[csaf.MetadataRole][]csaf.MetadataRole{ - csaf.MetadataRoleProvider: {csaf.MetadataRolePublisher}, - csaf.MetadataRoleTrustedProvider: {csaf.MetadataRoleProvider}, -} - -func requirements(role csaf.MetadataRole) [][2]int { - var own [][2]int - switch role { - case csaf.MetadataRoleTrustedProvider: - own = [][2]int{{18, 20}} - case csaf.MetadataRoleProvider: - // TODO: use commented numbers when TLPs should be checked. - own = [][2]int{{6 /* 5 */, 7}, {8, 10}, {11, 14}, {15, 17}} - case csaf.MetadataRolePublisher: - own = [][2]int{{1, 3 /* 4 */}} - } - for _, base := range roleImplies[role] { - own = append(own, requirements(base)...) - } - return own -} - -// buildReporters initializes each report by assigning a number and description to it. -// It returns an array of the reporter interface type. -func buildReporters(role csaf.MetadataRole) []reporter { - var reps []reporter - reqs := requirements(role) - // sort to have them ordered by there number. - sort.Slice(reqs, func(i, j int) bool { return reqs[i][0] < reqs[j][0] }) - for _, req := range reqs { - from, to := req[0]-1, req[1]-1 - for i := from; i <= to; i++ { - if rep := reporters[i]; rep != nil { - reps = append(reps, rep) - } - } - } - return reps -} - func (bc *baseReporter) requirement(domain *Domain) *Requirement { req := &Requirement{ Num: bc.num, diff --git a/cmd/csaf_checker/rules.go b/cmd/csaf_checker/rules.go new file mode 100644 index 0000000..91a596c --- /dev/null +++ b/cmd/csaf_checker/rules.go @@ -0,0 +1,114 @@ +// 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: 2023 German Federal Office for Information Security (BSI) +// Software-Engineering: 2023 Intevation GmbH + +package main + +import ( + "sort" + + "github.com/csaf-poc/csaf_distribution/v2/csaf" +) + +type ruleCondition int + +const ( + condAll ruleCondition = iota + condOneOf +) + +type requirementRules struct { + cond ruleCondition + satisfies int + subs []*requirementRules +} + +var ( + publisherRules = &requirementRules{ + cond: condAll, + subs: ruleAtoms(1, 2, 3 /* 4 */), + } + + providerRules = &requirementRules{ + cond: condAll, + subs: []*requirementRules{ + publisherRules, + {cond: condOneOf, subs: ruleAtoms(8, 9, 10)}, + {cond: condOneOf, subs: []*requirementRules{ + {cond: condAll, subs: ruleAtoms(11, 12, 13, 14)}, + {cond: condAll, subs: ruleAtoms(15, 16, 17)}, + }}, + }, + } + + trustedProviderRules = &requirementRules{ + cond: condAll, + subs: []*requirementRules{ + providerRules, + {cond: condAll, subs: ruleAtoms(18, 19, 20)}, + }, + } +) + +func ruleAtoms(nums ...int) []*requirementRules { + rules := make([]*requirementRules, len(nums)) + for i, num := range nums { + rules[i] = &requirementRules{ + cond: condAll, + satisfies: num, + } + } + return rules +} + +func (rules *requirementRules) reporters() []reporter { + if rules == nil { + return nil + } + var nums []int + + var recurse func(*requirementRules) + recurse = func(rules *requirementRules) { + if rules.satisfies != 0 { + // There should not be any dupes + for _, n := range nums { + if n == rules.satisfies { + goto doRecurse + } + } + nums = append(nums, rules.satisfies) + } + doRecurse: + for _, sub := range rules.subs { + recurse(sub) + } + } + recurse(rules) + + sort.Ints(nums) + + reps := make([]reporter, len(nums)) + + for i, n := range nums { + reps[i] = reporters[n] + } + return reps +} + +// 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 + } +}