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

     1  package types
     2  
     3  import (
     4  	"time"
     5  
     6  	v1 "github.com/google/go-containerregistry/pkg/v1"
     7  	"github.com/samber/lo"
     8  
     9  	"github.com/devseccon/trivy/pkg/digest"
    10  )
    11  
    12  type OS struct {
    13  	Family OSType
    14  	Name   string
    15  	Eosl   bool `json:"EOSL,omitempty"`
    16  
    17  	// This field is used for enhanced security maintenance programs such as Ubuntu ESM, Debian Extended LTS.
    18  	Extended bool `json:"extended,omitempty"`
    19  }
    20  
    21  func (o *OS) Detected() bool {
    22  	return o.Family != ""
    23  }
    24  
    25  // Merge merges OS version and enhanced security maintenance programs
    26  func (o *OS) Merge(newOS OS) {
    27  	if lo.IsEmpty(newOS) {
    28  		return
    29  	}
    30  
    31  	switch {
    32  	// OLE also has /etc/redhat-release and it detects OLE as RHEL by mistake.
    33  	// In that case, OS must be overwritten with the content of /etc/oracle-release.
    34  	// There is the same problem between Debian and Ubuntu.
    35  	case o.Family == RedHat, o.Family == Debian:
    36  		*o = newOS
    37  	default:
    38  		if o.Family == "" {
    39  			o.Family = newOS.Family
    40  		}
    41  		if o.Name == "" {
    42  			o.Name = newOS.Name
    43  		}
    44  		// Ubuntu has ESM program: https://ubuntu.com/security/esm
    45  		// OS version and esm status are stored in different files.
    46  		// We have to merge OS version after parsing these files.
    47  		if o.Extended || newOS.Extended {
    48  			o.Extended = true
    49  		}
    50  	}
    51  }
    52  
    53  type Repository struct {
    54  	Family  OSType `json:",omitempty"`
    55  	Release string `json:",omitempty"`
    56  }
    57  
    58  type Layer struct {
    59  	Digest    string `json:",omitempty"`
    60  	DiffID    string `json:",omitempty"`
    61  	CreatedBy string `json:",omitempty"`
    62  }
    63  
    64  type Package struct {
    65  	ID         string   `json:",omitempty"`
    66  	Name       string   `json:",omitempty"`
    67  	Version    string   `json:",omitempty"`
    68  	Release    string   `json:",omitempty"`
    69  	Epoch      int      `json:",omitempty"`
    70  	Arch       string   `json:",omitempty"`
    71  	Dev        bool     `json:",omitempty"`
    72  	SrcName    string   `json:",omitempty"`
    73  	SrcVersion string   `json:",omitempty"`
    74  	SrcRelease string   `json:",omitempty"`
    75  	SrcEpoch   int      `json:",omitempty"`
    76  	Licenses   []string `json:",omitempty"`
    77  	Maintainer string   `json:",omitempty"`
    78  
    79  	Modularitylabel string     `json:",omitempty"` // only for Red Hat based distributions
    80  	BuildInfo       *BuildInfo `json:",omitempty"` // only for Red Hat
    81  
    82  	Ref      string `json:",omitempty"` // identifier which can be used to reference the component elsewhere
    83  	Indirect bool   `json:",omitempty"` // this package is direct dependency of the project or not
    84  
    85  	// Dependencies of this package
    86  	// Note: it may have interdependencies, which may lead to infinite loops.
    87  	DependsOn []string `json:",omitempty"`
    88  
    89  	Layer Layer `json:",omitempty"`
    90  
    91  	// Each package metadata have the file path, while the package from lock files does not have.
    92  	FilePath string `json:",omitempty"`
    93  
    94  	// This is required when using SPDX formats. Otherwise, it will be empty.
    95  	Digest digest.Digest `json:",omitempty"`
    96  
    97  	// lines from the lock file where the dependency is written
    98  	Locations []Location `json:",omitempty"`
    99  
   100  	// Files installed by the package
   101  	InstalledFiles []string `json:",omitempty"`
   102  }
   103  
   104  type Location struct {
   105  	StartLine int `json:",omitempty"`
   106  	EndLine   int `json:",omitempty"`
   107  }
   108  
   109  // BuildInfo represents information under /root/buildinfo in RHEL
   110  type BuildInfo struct {
   111  	ContentSets []string `json:",omitempty"`
   112  	Nvr         string   `json:",omitempty"`
   113  	Arch        string   `json:",omitempty"`
   114  }
   115  
   116  func (pkg *Package) Empty() bool {
   117  	return pkg.Name == "" || pkg.Version == ""
   118  }
   119  
   120  type Packages []Package
   121  
   122  func (pkgs Packages) Len() int {
   123  	return len(pkgs)
   124  }
   125  
   126  func (pkgs Packages) Swap(i, j int) {
   127  	pkgs[i], pkgs[j] = pkgs[j], pkgs[i]
   128  }
   129  
   130  func (pkgs Packages) Less(i, j int) bool {
   131  	switch {
   132  	case pkgs[i].Name != pkgs[j].Name:
   133  		return pkgs[i].Name < pkgs[j].Name
   134  	case pkgs[i].Version != pkgs[j].Version:
   135  		return pkgs[i].Version < pkgs[j].Version
   136  	}
   137  	return pkgs[i].FilePath < pkgs[j].FilePath
   138  }
   139  
   140  // ParentDeps returns a map where the keys are package IDs and the values are the packages
   141  // that depend on the respective package ID (parent dependencies).
   142  func (pkgs Packages) ParentDeps() map[string]Packages {
   143  	parents := make(map[string]Packages)
   144  	for _, pkg := range pkgs {
   145  		for _, dependOn := range pkg.DependsOn {
   146  			parents[dependOn] = append(parents[dependOn], pkg)
   147  		}
   148  	}
   149  
   150  	for k, v := range parents {
   151  		parents[k] = lo.UniqBy(v, func(pkg Package) string {
   152  			return pkg.ID
   153  		})
   154  	}
   155  	return parents
   156  }
   157  
   158  type SrcPackage struct {
   159  	Name        string   `json:"name"`
   160  	Version     string   `json:"version"`
   161  	BinaryNames []string `json:"binaryNames"`
   162  }
   163  
   164  type PackageInfo struct {
   165  	FilePath string
   166  	Packages Packages
   167  }
   168  
   169  type Application struct {
   170  	// e.g. bundler and pipenv
   171  	Type LangType
   172  
   173  	// Lock files have the file path here, while each package metadata do not have
   174  	FilePath string `json:",omitempty"`
   175  
   176  	// Libraries is a list of lang-specific packages
   177  	Libraries Packages
   178  }
   179  
   180  type File struct {
   181  	Type    string
   182  	Path    string
   183  	Content []byte
   184  }
   185  
   186  // ArtifactType represents a type of artifact
   187  type ArtifactType string
   188  
   189  const (
   190  	ArtifactContainerImage ArtifactType = "container_image"
   191  	ArtifactFilesystem     ArtifactType = "filesystem"
   192  	ArtifactRepository     ArtifactType = "repository"
   193  	ArtifactCycloneDX      ArtifactType = "cyclonedx"
   194  	ArtifactSPDX           ArtifactType = "spdx"
   195  	ArtifactAWSAccount     ArtifactType = "aws_account"
   196  	ArtifactVM             ArtifactType = "vm"
   197  )
   198  
   199  // ArtifactReference represents a reference of container image, local filesystem and repository
   200  type ArtifactReference struct {
   201  	Name          string // image name, tar file name, directory or repository name
   202  	Type          ArtifactType
   203  	ID            string
   204  	BlobIDs       []string
   205  	ImageMetadata ImageMetadata
   206  
   207  	// SBOM
   208  	CycloneDX *CycloneDX
   209  }
   210  
   211  type ImageMetadata struct {
   212  	ID          string   // image ID
   213  	DiffIDs     []string // uncompressed layer IDs
   214  	RepoTags    []string
   215  	RepoDigests []string
   216  	ConfigFile  v1.ConfigFile
   217  }
   218  
   219  // ArtifactInfo is stored in cache
   220  type ArtifactInfo struct {
   221  	SchemaVersion int
   222  	Architecture  string
   223  	Created       time.Time
   224  	DockerVersion string
   225  	OS            string
   226  
   227  	// Misconfiguration holds misconfiguration in container image config
   228  	Misconfiguration *Misconfiguration `json:",omitempty"`
   229  
   230  	// Secret holds secrets in container image config such as environment variables
   231  	Secret *Secret `json:",omitempty"`
   232  
   233  	// HistoryPackages are packages extracted from RUN instructions
   234  	HistoryPackages Packages `json:",omitempty"`
   235  }
   236  
   237  // BlobInfo is stored in cache
   238  type BlobInfo struct {
   239  	SchemaVersion int
   240  
   241  	// Layer information
   242  	Digest        string   `json:",omitempty"`
   243  	DiffID        string   `json:",omitempty"`
   244  	CreatedBy     string   `json:",omitempty"`
   245  	OpaqueDirs    []string `json:",omitempty"`
   246  	WhiteoutFiles []string `json:",omitempty"`
   247  
   248  	// Analysis result
   249  	OS                OS                 `json:",omitempty"`
   250  	Repository        *Repository        `json:",omitempty"`
   251  	PackageInfos      []PackageInfo      `json:",omitempty"`
   252  	Applications      []Application      `json:",omitempty"`
   253  	Misconfigurations []Misconfiguration `json:",omitempty"`
   254  	Secrets           []Secret           `json:",omitempty"`
   255  	Licenses          []LicenseFile      `json:",omitempty"`
   256  
   257  	// Red Hat distributions have build info per layer.
   258  	// This information will be embedded into packages when applying layers.
   259  	// ref. https://redhat-connect.gitbook.io/partner-guide-for-adopting-red-hat-oval-v2/determining-common-platform-enumeration-cpe
   260  	BuildInfo *BuildInfo `json:",omitempty"`
   261  
   262  	// CustomResources hold analysis results from custom analyzers.
   263  	// It is for extensibility and not used in OSS.
   264  	CustomResources []CustomResource `json:",omitempty"`
   265  }
   266  
   267  // ArtifactDetail represents the analysis result.
   268  type ArtifactDetail struct {
   269  	OS                OS                 `json:",omitempty"`
   270  	Repository        *Repository        `json:",omitempty"`
   271  	Packages          Packages           `json:",omitempty"`
   272  	Applications      []Application      `json:",omitempty"`
   273  	Misconfigurations []Misconfiguration `json:",omitempty"`
   274  	Secrets           []Secret           `json:",omitempty"`
   275  	Licenses          []LicenseFile      `json:",omitempty"`
   276  
   277  	// ImageConfig has information from container image config
   278  	ImageConfig ImageConfigDetail
   279  
   280  	// CustomResources hold analysis results from custom analyzers.
   281  	// It is for extensibility and not used in OSS.
   282  	CustomResources []CustomResource `json:",omitempty"`
   283  }
   284  
   285  // ImageConfigDetail has information from container image config
   286  type ImageConfigDetail struct {
   287  	// Packages are packages extracted from RUN instructions in history
   288  	Packages []Package `json:",omitempty"`
   289  
   290  	// Misconfiguration holds misconfigurations in container image config
   291  	Misconfiguration *Misconfiguration `json:",omitempty"`
   292  
   293  	// Secret holds secrets in container image config
   294  	Secret *Secret `json:",omitempty"`
   295  }
   296  
   297  // ToBlobInfo is used to store a merged layer in cache.
   298  func (a *ArtifactDetail) ToBlobInfo() BlobInfo {
   299  	return BlobInfo{
   300  		SchemaVersion: BlobJSONSchemaVersion,
   301  		OS:            a.OS,
   302  		Repository:    a.Repository,
   303  		PackageInfos: []PackageInfo{
   304  			{
   305  				FilePath: "merged", // Set a dummy file path
   306  				Packages: a.Packages,
   307  			},
   308  		},
   309  		Applications:      a.Applications,
   310  		Misconfigurations: a.Misconfigurations,
   311  		Secrets:           a.Secrets,
   312  		Licenses:          a.Licenses,
   313  		CustomResources:   a.CustomResources,
   314  	}
   315  }
   316  
   317  // CustomResource holds the analysis result from a custom analyzer.
   318  // It is for extensibility and not used in OSS.
   319  type CustomResource struct {
   320  	Type     string
   321  	FilePath string
   322  	Layer    Layer
   323  	Data     interface{}
   324  }