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 }