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

     1  package types
     2  
     3  import (
     4  	"encoding/json"
     5  	"time"
     6  
     7  	v1 "github.com/google/go-containerregistry/pkg/v1" // nolint: goimports
     8  
     9  	ftypes "github.com/devseccon/trivy/pkg/fanal/types"
    10  )
    11  
    12  // Report represents a scan result
    13  type Report struct {
    14  	SchemaVersion int                 `json:",omitempty"`
    15  	CreatedAt     time.Time           `json:",omitempty"`
    16  	ArtifactName  string              `json:",omitempty"`
    17  	ArtifactType  ftypes.ArtifactType `json:",omitempty"`
    18  	Metadata      Metadata            `json:",omitempty"`
    19  	Results       Results             `json:",omitempty"`
    20  
    21  	// SBOM
    22  	CycloneDX *ftypes.CycloneDX `json:"-"` // Just for internal usage, not exported in JSON
    23  }
    24  
    25  // Metadata represents a metadata of artifact
    26  type Metadata struct {
    27  	Size int64      `json:",omitempty"`
    28  	OS   *ftypes.OS `json:",omitempty"`
    29  
    30  	// Container image
    31  	ImageID     string        `json:",omitempty"`
    32  	DiffIDs     []string      `json:",omitempty"`
    33  	RepoTags    []string      `json:",omitempty"`
    34  	RepoDigests []string      `json:",omitempty"`
    35  	ImageConfig v1.ConfigFile `json:",omitempty"`
    36  }
    37  
    38  // Results to hold list of Result
    39  type Results []Result
    40  
    41  type ResultClass string
    42  type Compliance = string
    43  type Format string
    44  
    45  const (
    46  	ClassUnknown     ResultClass = "unknown"
    47  	ClassOSPkg       ResultClass = "os-pkgs"      // For detected packages and vulnerabilities in OS packages
    48  	ClassLangPkg     ResultClass = "lang-pkgs"    // For detected packages and vulnerabilities in language-specific packages
    49  	ClassConfig      ResultClass = "config"       // For detected misconfigurations
    50  	ClassSecret      ResultClass = "secret"       // For detected secrets
    51  	ClassLicense     ResultClass = "license"      // For detected package licenses
    52  	ClassLicenseFile ResultClass = "license-file" // For detected licenses in files
    53  	ClassCustom      ResultClass = "custom"
    54  
    55  	ComplianceK8sNsa           = Compliance("k8s-nsa")
    56  	ComplianceK8sCIS           = Compliance("k8s-cis")
    57  	ComplianceK8sPSSBaseline   = Compliance("k8s-pss-baseline")
    58  	ComplianceK8sPSSRestricted = Compliance("k8s-pss-restricted")
    59  	ComplianceAWSCIS12         = Compliance("aws-cis-1.2")
    60  	ComplianceAWSCIS14         = Compliance("aws-cis-1.4")
    61  	ComplianceDockerCIS        = Compliance("docker-cis")
    62  
    63  	FormatTable      Format = "table"
    64  	FormatJSON       Format = "json"
    65  	FormatTemplate   Format = "template"
    66  	FormatSarif      Format = "sarif"
    67  	FormatCycloneDX  Format = "cyclonedx"
    68  	FormatSPDX       Format = "spdx"
    69  	FormatSPDXJSON   Format = "spdx-json"
    70  	FormatGitHub     Format = "github"
    71  	FormatCosignVuln Format = "cosign-vuln"
    72  )
    73  
    74  var (
    75  	SupportedFormats = []Format{
    76  		FormatTable,
    77  		FormatJSON,
    78  		FormatTemplate,
    79  		FormatSarif,
    80  		FormatCycloneDX,
    81  		FormatSPDX,
    82  		FormatSPDXJSON,
    83  		FormatGitHub,
    84  		FormatCosignVuln,
    85  	}
    86  	SupportedSBOMFormats = []Format{
    87  		FormatCycloneDX,
    88  		FormatSPDX,
    89  		FormatSPDXJSON,
    90  		FormatGitHub,
    91  	}
    92  	SupportedCompliances = []string{
    93  		ComplianceK8sNsa,
    94  		ComplianceK8sCIS,
    95  		ComplianceK8sPSSBaseline,
    96  		ComplianceK8sPSSRestricted,
    97  		ComplianceAWSCIS12,
    98  		ComplianceAWSCIS14,
    99  		ComplianceDockerCIS,
   100  	}
   101  )
   102  
   103  // Result holds a target and detected vulnerabilities
   104  type Result struct {
   105  	Target            string                     `json:"Target"`
   106  	Class             ResultClass                `json:"Class,omitempty"`
   107  	Type              ftypes.TargetType          `json:"Type,omitempty"`
   108  	Packages          []ftypes.Package           `json:"Packages,omitempty"`
   109  	Vulnerabilities   []DetectedVulnerability    `json:"Vulnerabilities,omitempty"`
   110  	MisconfSummary    *MisconfSummary            `json:"MisconfSummary,omitempty"`
   111  	Misconfigurations []DetectedMisconfiguration `json:"Misconfigurations,omitempty"`
   112  	Secrets           []ftypes.SecretFinding     `json:"Secrets,omitempty"`
   113  	Licenses          []DetectedLicense          `json:"Licenses,omitempty"`
   114  	CustomResources   []ftypes.CustomResource    `json:"CustomResources,omitempty"`
   115  }
   116  
   117  func (r *Result) MarshalJSON() ([]byte, error) {
   118  	// VendorSeverity includes all vendor severities.
   119  	// It would be noisy to users, so it should be removed from the JSON output.
   120  	for i := range r.Vulnerabilities {
   121  		r.Vulnerabilities[i].VendorSeverity = nil
   122  	}
   123  
   124  	// Notice the Alias struct prevents MarshalJSON being called infinitely
   125  	type ResultAlias Result
   126  	return json.Marshal(&struct {
   127  		*ResultAlias
   128  	}{
   129  		ResultAlias: (*ResultAlias)(r),
   130  	})
   131  }
   132  
   133  func (r *Result) IsEmpty() bool {
   134  	return len(r.Packages) == 0 && len(r.Vulnerabilities) == 0 && len(r.Misconfigurations) == 0 &&
   135  		len(r.Secrets) == 0 && len(r.Licenses) == 0 && len(r.CustomResources) == 0
   136  }
   137  
   138  type MisconfSummary struct {
   139  	Successes  int
   140  	Failures   int
   141  	Exceptions int
   142  }
   143  
   144  func (s MisconfSummary) Empty() bool {
   145  	return s.Successes == 0 && s.Failures == 0 && s.Exceptions == 0
   146  }
   147  
   148  // Failed returns whether the result includes any vulnerabilities, misconfigurations or secrets
   149  func (results Results) Failed() bool {
   150  	for _, r := range results {
   151  		if len(r.Vulnerabilities) > 0 {
   152  			return true
   153  		}
   154  		for _, m := range r.Misconfigurations {
   155  			if m.Status == StatusFailure {
   156  				return true
   157  			}
   158  		}
   159  		if len(r.Secrets) > 0 {
   160  			return true
   161  		}
   162  		if len(r.Licenses) > 0 {
   163  			return true
   164  		}
   165  	}
   166  	return false
   167  }