github.com/devseccon/trivy@v0.47.1-0.20231123133102-bd902a0bd996/pkg/compliance/spec/compliance.go (about) 1 package spec 2 3 import ( 4 "fmt" 5 "os" 6 "strings" 7 8 "golang.org/x/exp/maps" 9 "golang.org/x/xerrors" 10 "gopkg.in/yaml.v3" 11 12 defsecTypes "github.com/aquasecurity/defsec/pkg/types" 13 sp "github.com/aquasecurity/trivy-policies/pkg/spec" 14 "github.com/devseccon/trivy/pkg/types" 15 ) 16 17 type Severity string 18 19 // ComplianceSpec represent the compliance specification 20 type ComplianceSpec struct { 21 Spec defsecTypes.Spec `yaml:"spec"` 22 } 23 24 const ( 25 FailStatus defsecTypes.ControlStatus = "FAIL" 26 PassStatus defsecTypes.ControlStatus = "PASS" 27 WarnStatus defsecTypes.ControlStatus = "WARN" 28 ) 29 30 // Scanners reads spec control and determines the scanners by check ID prefix 31 func (cs *ComplianceSpec) Scanners() (types.Scanners, error) { 32 scannerTypes := make(map[types.Scanner]struct{}) 33 for _, control := range cs.Spec.Controls { 34 for _, check := range control.Checks { 35 scannerType := scannerByCheckID(check.ID) 36 if scannerType == types.UnknownScanner { 37 return nil, xerrors.Errorf("unsupported check ID: %s", check.ID) 38 } 39 scannerTypes[scannerType] = struct{}{} 40 } 41 } 42 return maps.Keys(scannerTypes), nil 43 } 44 45 // CheckIDs return list of compliance check IDs 46 func (cs *ComplianceSpec) CheckIDs() map[types.Scanner][]string { 47 checkIDsMap := make(map[types.Scanner][]string) 48 for _, control := range cs.Spec.Controls { 49 for _, check := range control.Checks { 50 scannerType := scannerByCheckID(check.ID) 51 checkIDsMap[scannerType] = append(checkIDsMap[scannerType], check.ID) 52 } 53 } 54 return checkIDsMap 55 } 56 57 func scannerByCheckID(checkID string) types.Scanner { 58 checkID = strings.ToLower(checkID) 59 switch { 60 case strings.HasPrefix(checkID, "cve-") || strings.HasPrefix(checkID, "dla-"): 61 return types.VulnerabilityScanner 62 case strings.HasPrefix(checkID, "avd-"): 63 return types.MisconfigScanner 64 case strings.HasPrefix(checkID, "vuln-"): // custom id for filtering vulnerabilities by severity 65 return types.VulnerabilityScanner 66 case strings.HasPrefix(checkID, "secret-"): // custom id for filtering secrets by severity 67 return types.SecretScanner 68 default: 69 return types.UnknownScanner 70 } 71 } 72 73 // GetComplianceSpec accepct compliance flag name/path and return builtin or file system loaded spec 74 func GetComplianceSpec(specNameOrPath string) (ComplianceSpec, error) { 75 var b []byte 76 var err error 77 if strings.HasPrefix(specNameOrPath, "@") { 78 b, err = os.ReadFile(strings.TrimPrefix(specNameOrPath, "@")) 79 if err != nil { 80 return ComplianceSpec{}, fmt.Errorf("error retrieving compliance spec from path: %w", err) 81 } 82 } else { 83 // TODO: GetSpecByName() should return []byte 84 b = []byte(sp.NewSpecLoader().GetSpecByName(specNameOrPath)) 85 } 86 87 var complianceSpec ComplianceSpec 88 if err = yaml.Unmarshal(b, &complianceSpec); err != nil { 89 return ComplianceSpec{}, xerrors.Errorf("spec yaml decode error: %w", err) 90 } 91 return complianceSpec, nil 92 93 }