github.com/devseccon/trivy@v0.47.1-0.20231123133102-bd902a0bd996/pkg/fanal/types/misconf.go (about)

     1  package types
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  
     7  	"github.com/samber/lo"
     8  )
     9  
    10  type Misconfiguration struct {
    11  	FileType   ConfigType     `json:",omitempty"`
    12  	FilePath   string         `json:",omitempty"`
    13  	Successes  MisconfResults `json:",omitempty"`
    14  	Warnings   MisconfResults `json:",omitempty"`
    15  	Failures   MisconfResults `json:",omitempty"`
    16  	Exceptions MisconfResults `json:",omitempty"`
    17  	Layer      Layer          `json:",omitempty"`
    18  }
    19  
    20  type MisconfResult struct {
    21  	Namespace      string `json:",omitempty"`
    22  	Query          string `json:",omitempty"`
    23  	Message        string `json:",omitempty"`
    24  	PolicyMetadata `json:",omitempty"`
    25  	CauseMetadata  `json:",omitempty"`
    26  
    27  	// For debugging
    28  	Traces []string `json:",omitempty"`
    29  }
    30  
    31  type MisconfResults []MisconfResult
    32  
    33  type CauseMetadata struct {
    34  	Resource    string       `json:",omitempty"`
    35  	Provider    string       `json:",omitempty"`
    36  	Service     string       `json:",omitempty"`
    37  	StartLine   int          `json:",omitempty"`
    38  	EndLine     int          `json:",omitempty"`
    39  	Code        Code         `json:",omitempty"`
    40  	Occurrences []Occurrence `json:",omitempty"`
    41  }
    42  
    43  type Occurrence struct {
    44  	Resource string `json:",omitempty"`
    45  	Filename string `json:",omitempty"`
    46  	Location Location
    47  }
    48  
    49  type Code struct {
    50  	Lines []Line
    51  }
    52  
    53  type Line struct {
    54  	Number      int    `json:"Number"`
    55  	Content     string `json:"Content"`
    56  	IsCause     bool   `json:"IsCause"`
    57  	Annotation  string `json:"Annotation"`
    58  	Truncated   bool   `json:"Truncated"`
    59  	Highlighted string `json:"Highlighted,omitempty"`
    60  	FirstCause  bool   `json:"FirstCause"`
    61  	LastCause   bool   `json:"LastCause"`
    62  }
    63  
    64  type PolicyMetadata struct {
    65  	ID                 string   `json:",omitempty"`
    66  	AVDID              string   `json:",omitempty"`
    67  	Type               string   `json:",omitempty"`
    68  	Title              string   `json:",omitempty"`
    69  	Description        string   `json:",omitempty"`
    70  	Severity           string   `json:",omitempty"`
    71  	RecommendedActions string   `json:",omitempty" mapstructure:"recommended_actions"`
    72  	References         []string `json:",omitempty"`
    73  }
    74  
    75  type PolicyInputOption struct {
    76  	Combine   bool                  `mapstructure:"combine"`
    77  	Selectors []PolicyInputSelector `mapstructure:"selector"`
    78  }
    79  
    80  type PolicyInputSelector struct {
    81  	Type string `mapstructure:"type"`
    82  }
    83  
    84  func (r MisconfResults) Len() int {
    85  	return len(r)
    86  }
    87  
    88  func (r MisconfResults) Swap(i, j int) {
    89  	r[i], r[j] = r[j], r[i]
    90  }
    91  
    92  func (r MisconfResults) Less(i, j int) bool {
    93  	switch {
    94  	case r[i].Type != r[j].Type:
    95  		return r[i].Type < r[j].Type
    96  	case r[i].AVDID != r[j].AVDID:
    97  		return r[i].AVDID < r[j].AVDID
    98  	case r[i].ID != r[j].ID:
    99  		return r[i].ID < r[j].ID
   100  	case r[i].Severity != r[j].Severity:
   101  		return r[i].Severity < r[j].Severity
   102  	case r[i].Resource != r[j].Resource:
   103  		return r[i].Resource < r[j].Resource
   104  	}
   105  	return r[i].Message < r[j].Message
   106  }
   107  
   108  func ToMisconfigurations(misconfs map[string]Misconfiguration) []Misconfiguration {
   109  	var results []Misconfiguration
   110  	for _, misconf := range misconfs {
   111  		// Remove duplicates
   112  		misconf.Successes = uniqueResults(misconf.Successes)
   113  		misconf.Warnings = uniqueResults(misconf.Warnings)
   114  		misconf.Failures = uniqueResults(misconf.Failures)
   115  
   116  		// Sort results
   117  		sort.Sort(misconf.Successes)
   118  		sort.Sort(misconf.Warnings)
   119  		sort.Sort(misconf.Failures)
   120  		sort.Sort(misconf.Exceptions)
   121  
   122  		results = append(results, misconf)
   123  	}
   124  
   125  	// Sort misconfigurations
   126  	sort.Slice(results, func(i, j int) bool {
   127  		if results[i].FileType != results[j].FileType {
   128  			return results[i].FileType < results[j].FileType
   129  		}
   130  		return results[i].FilePath < results[j].FilePath
   131  	})
   132  
   133  	return results
   134  }
   135  
   136  func uniqueResults(results []MisconfResult) []MisconfResult {
   137  	if len(results) == 0 {
   138  		return results
   139  	}
   140  	return lo.UniqBy(results, func(result MisconfResult) string {
   141  		return fmt.Sprintf("ID: %s, Namespace: %s, Messsage: %s, Cause: %v",
   142  			result.ID, result.Namespace, result.Message, result.CauseMetadata)
   143  	})
   144  }