mirror of
https://github.com/gocsaf/csaf.git
synced 2025-12-22 18:15:42 +01:00
Build reporters from role
This commit is contained in:
parent
018a1814f0
commit
bd7831d7c3
2 changed files with 79 additions and 31 deletions
|
|
@ -21,7 +21,9 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"github.com/csaf-poc/csaf_distribution/csaf"
|
||||||
"github.com/csaf-poc/csaf_distribution/util"
|
"github.com/csaf-poc/csaf_distribution/util"
|
||||||
"github.com/jessevdk/go-flags"
|
"github.com/jessevdk/go-flags"
|
||||||
)
|
)
|
||||||
|
|
@ -140,13 +142,12 @@ func writeReport(report *Report, opts *options) error {
|
||||||
return writer(report, w)
|
return writer(report, w)
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildReporters initializes each report by assigning a number and description to it.
|
var reporters = [23]reporter{
|
||||||
// It returns an array of the reporter interface type.
|
|
||||||
func buildReporters() []reporter {
|
|
||||||
return []reporter{
|
|
||||||
&validReporter{baseReporter{num: 1, description: "Valid CSAF documents"}},
|
&validReporter{baseReporter{num: 1, description: "Valid CSAF documents"}},
|
||||||
&filenameReporter{baseReporter{num: 2, description: "Filename"}},
|
&filenameReporter{baseReporter{num: 2, description: "Filename"}},
|
||||||
&tlsReporter{baseReporter{num: 3, description: "TLS"}},
|
&tlsReporter{baseReporter{num: 3, description: "TLS"}},
|
||||||
|
nil, // TODO: Add 4: TLP:WHITE
|
||||||
|
nil, // TODO: Add 5: TLP:AMBER and TLP:RED
|
||||||
&redirectsReporter{baseReporter{num: 6, description: "Redirects"}},
|
&redirectsReporter{baseReporter{num: 6, description: "Redirects"}},
|
||||||
&providerMetadataReport{baseReporter{num: 7, description: "provider-metadata.json"}},
|
&providerMetadataReport{baseReporter{num: 7, description: "provider-metadata.json"}},
|
||||||
&securityReporter{baseReporter{num: 8, description: "security.txt"}},
|
&securityReporter{baseReporter{num: 8, description: "security.txt"}},
|
||||||
|
|
@ -156,10 +157,54 @@ func buildReporters() []reporter {
|
||||||
&indexReporter{baseReporter{num: 12, description: "index.txt"}},
|
&indexReporter{baseReporter{num: 12, description: "index.txt"}},
|
||||||
&changesReporter{baseReporter{num: 13, description: "changes.csv"}},
|
&changesReporter{baseReporter{num: 13, description: "changes.csv"}},
|
||||||
&directoryListingsReporter{baseReporter{num: 14, description: "Directory listings"}},
|
&directoryListingsReporter{baseReporter{num: 14, description: "Directory listings"}},
|
||||||
|
nil, // TODO: Add 15: ROLIE feed
|
||||||
|
nil, // TODO: Add 16: ROLIE service document
|
||||||
|
nil, // TODO: Add 17: ROLIE category document
|
||||||
&integrityReporter{baseReporter{num: 18, description: "Integrity"}},
|
&integrityReporter{baseReporter{num: 18, description: "Integrity"}},
|
||||||
&signaturesReporter{baseReporter{num: 19, description: "Signatures"}},
|
&signaturesReporter{baseReporter{num: 19, description: "Signatures"}},
|
||||||
&publicPGPKeyReporter{baseReporter{num: 20, description: "Public OpenPGP Key"}},
|
&publicPGPKeyReporter{baseReporter{num: 20, description: "Public OpenPGP Key"}},
|
||||||
|
nil, // TODO: Add 21: List of CSAF providers
|
||||||
|
nil, // TODO: Add 22: Two disjoint issuing parties
|
||||||
|
nil, // TODO: Add 23: 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:
|
||||||
|
own = [][2]int{{5, 7}, {8, 10}, {11, 14}, {15, 17}}
|
||||||
|
case csaf.MetadataRolePublisher:
|
||||||
|
own = [][2]int{{1, 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
|
||||||
}
|
}
|
||||||
|
|
||||||
// run uses a processor to check all the given domains or direct urls
|
// run uses a processor to check all the given domains or direct urls
|
||||||
|
|
@ -170,7 +215,7 @@ func run(opts *options, domains []string) (*Report, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer p.close()
|
defer p.close()
|
||||||
return p.run(buildReporters(), domains)
|
return p.run(domains)
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
||||||
|
|
@ -223,7 +223,7 @@ func (p *processor) clean() {
|
||||||
// run calls checkDomain function for each domain in the given "domains" parameter.
|
// run calls checkDomain function for each domain in the given "domains" parameter.
|
||||||
// Then it calls the report method on each report from the given "reporters" parameter for each domain.
|
// Then it calls the report method on each report from the given "reporters" parameter for each domain.
|
||||||
// It returns a pointer to the report and nil, otherwise an error.
|
// It returns a pointer to the report and nil, otherwise an error.
|
||||||
func (p *processor) run(reporters []reporter, domains []string) (*Report, error) {
|
func (p *processor) run(domains []string) (*Report, error) {
|
||||||
|
|
||||||
report := Report{
|
report := Report{
|
||||||
Date: ReportTime{Time: time.Now().UTC()},
|
Date: ReportTime{Time: time.Now().UTC()},
|
||||||
|
|
@ -231,19 +231,24 @@ func (p *processor) run(reporters []reporter, domains []string) (*Report, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, d := range domains {
|
for _, d := range domains {
|
||||||
|
if p.checkProviderMetadata(d) {
|
||||||
if err := p.checkDomain(d); err != nil {
|
if err := p.checkDomain(d); err != nil {
|
||||||
if err == errContinue || err == errStop {
|
if err == errContinue || err == errStop {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
domain := &Domain{Name: d}
|
|
||||||
for _, r := range reporters {
|
|
||||||
r.report(p, domain)
|
|
||||||
}
|
}
|
||||||
|
domain := &Domain{Name: d}
|
||||||
|
|
||||||
if err := p.fillMeta(domain); err != nil {
|
if err := p.fillMeta(domain); err != nil {
|
||||||
log.Printf("Filling meta data failed: %v\n", err)
|
log.Printf("Filling meta data failed: %v\n", err)
|
||||||
|
// reporters depend on role.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, r := range buildReporters(*domain.Role) {
|
||||||
|
r.report(p, domain)
|
||||||
}
|
}
|
||||||
|
|
||||||
report.Domains = append(report.Domains, domain)
|
report.Domains = append(report.Domains, domain)
|
||||||
|
|
@ -287,7 +292,6 @@ func (p *processor) domainChecks(domain string) []func(*processor, string) error
|
||||||
direct := strings.HasPrefix(domain, "https://")
|
direct := strings.HasPrefix(domain, "https://")
|
||||||
|
|
||||||
checks := []func(*processor, string) error{
|
checks := []func(*processor, string) error{
|
||||||
(*processor).checkProviderMetadata,
|
|
||||||
(*processor).checkPGPKeys,
|
(*processor).checkPGPKeys,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1107,8 +1111,7 @@ func (p *processor) checkListing(string) error {
|
||||||
// decodes, and validates against the JSON schema.
|
// decodes, and validates against the JSON schema.
|
||||||
// According to the result, the respective error messages added to
|
// According to the result, the respective error messages added to
|
||||||
// badProviderMetadata.
|
// badProviderMetadata.
|
||||||
// It returns nil if all checks are passed.
|
func (p *processor) checkProviderMetadata(domain string) bool {
|
||||||
func (p *processor) checkProviderMetadata(domain string) error {
|
|
||||||
|
|
||||||
p.badProviderMetadata.use()
|
p.badProviderMetadata.use()
|
||||||
|
|
||||||
|
|
@ -1123,14 +1126,14 @@ func (p *processor) checkProviderMetadata(domain string) error {
|
||||||
if !lpmd.Valid() {
|
if !lpmd.Valid() {
|
||||||
p.badProviderMetadata.error("No valid provider-metadata.json found.")
|
p.badProviderMetadata.error("No valid provider-metadata.json found.")
|
||||||
p.badProviderMetadata.error("STOPPING here - cannot perform other checks.")
|
p.badProviderMetadata.error("STOPPING here - cannot perform other checks.")
|
||||||
return errStop
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
p.pmdURL = lpmd.URL
|
p.pmdURL = lpmd.URL
|
||||||
p.pmd256 = lpmd.Hash
|
p.pmd256 = lpmd.Hash
|
||||||
p.pmd = lpmd.Document
|
p.pmd = lpmd.Document
|
||||||
|
|
||||||
return nil
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkSecurity checks the security.txt file by making HTTP request to fetch it.
|
// checkSecurity checks the security.txt file by making HTTP request to fetch it.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue