1package rpc 2 3import ( 4 "github.com/golang/protobuf/ptypes" 5 6 ftypes "github.com/aquasecurity/fanal/types" 7 deptypes "github.com/aquasecurity/go-dep-parser/pkg/types" 8 dbTypes "github.com/aquasecurity/trivy-db/pkg/types" 9 "github.com/aquasecurity/trivy/pkg/log" 10 "github.com/aquasecurity/trivy/pkg/report" 11 "github.com/aquasecurity/trivy/pkg/types" 12 "github.com/aquasecurity/trivy/rpc/cache" 13 "github.com/aquasecurity/trivy/rpc/common" 14 "github.com/aquasecurity/trivy/rpc/scanner" 15) 16 17func ConvertToRpcPkgs(pkgs []ftypes.Package) []*common.Package { 18 var rpcPkgs []*common.Package 19 for _, pkg := range pkgs { 20 rpcPkgs = append(rpcPkgs, &common.Package{ 21 Name: pkg.Name, 22 Version: pkg.Version, 23 Release: pkg.Release, 24 Epoch: int32(pkg.Epoch), 25 Arch: pkg.Arch, 26 SrcName: pkg.SrcName, 27 SrcVersion: pkg.SrcVersion, 28 SrcRelease: pkg.SrcRelease, 29 SrcEpoch: int32(pkg.SrcEpoch), 30 }) 31 } 32 return rpcPkgs 33} 34 35func ConvertFromRpcPkgs(rpcPkgs []*common.Package) []ftypes.Package { 36 var pkgs []ftypes.Package 37 for _, pkg := range rpcPkgs { 38 pkgs = append(pkgs, ftypes.Package{ 39 Name: pkg.Name, 40 Version: pkg.Version, 41 Release: pkg.Release, 42 Epoch: int(pkg.Epoch), 43 Arch: pkg.Arch, 44 SrcName: pkg.SrcName, 45 SrcVersion: pkg.SrcVersion, 46 SrcRelease: pkg.SrcRelease, 47 SrcEpoch: int(pkg.SrcEpoch), 48 }) 49 } 50 return pkgs 51} 52 53func ConvertFromRpcLibraries(rpcLibs []*common.Library) []ftypes.LibraryInfo { 54 var libs []ftypes.LibraryInfo 55 for _, l := range rpcLibs { 56 libs = append(libs, ftypes.LibraryInfo{ 57 Library: deptypes.Library{ 58 Name: l.Name, 59 Version: l.Version, 60 }, 61 }) 62 } 63 return libs 64} 65 66func ConvertToRpcLibraries(libs []deptypes.Library) []*common.Library { 67 var rpcLibs []*common.Library 68 for _, l := range libs { 69 rpcLibs = append(rpcLibs, &common.Library{ 70 Name: l.Name, 71 Version: l.Version, 72 }) 73 } 74 return rpcLibs 75} 76 77func ConvertFromRpcVulns(rpcVulns []*common.Vulnerability) []types.DetectedVulnerability { 78 var vulns []types.DetectedVulnerability 79 for _, vuln := range rpcVulns { 80 severity := dbTypes.Severity(vuln.Severity) 81 vulns = append(vulns, types.DetectedVulnerability{ 82 VulnerabilityID: vuln.VulnerabilityId, 83 PkgName: vuln.PkgName, 84 InstalledVersion: vuln.InstalledVersion, 85 FixedVersion: vuln.FixedVersion, 86 Vulnerability: dbTypes.Vulnerability{ 87 Title: vuln.Title, 88 Description: vuln.Description, 89 Severity: severity.String(), 90 References: vuln.References, 91 }, 92 }) 93 } 94 return vulns 95} 96 97func ConvertToRpcVulns(vulns []types.DetectedVulnerability) []*common.Vulnerability { 98 var rpcVulns []*common.Vulnerability 99 for _, vuln := range vulns { 100 severity, err := dbTypes.NewSeverity(vuln.Severity) 101 if err != nil { 102 log.Logger.Warn(err) 103 } 104 cvssMap := make(map[string]*common.CVSS) // This is needed because protobuf generates a map[string]*CVSS type 105 for vendor, vendorSeverity := range vuln.CVSS { 106 cvssMap[vendor] = &common.CVSS{ 107 V2Vector: vendorSeverity.V2Vector, 108 V3Vector: vendorSeverity.V3Vector, 109 V2Score: vendorSeverity.V2Score, 110 V3Score: vendorSeverity.V3Score, 111 } 112 } 113 114 rpcVulns = append(rpcVulns, &common.Vulnerability{ 115 VulnerabilityId: vuln.VulnerabilityID, 116 PkgName: vuln.PkgName, 117 InstalledVersion: vuln.InstalledVersion, 118 FixedVersion: vuln.FixedVersion, 119 Title: vuln.Title, 120 Description: vuln.Description, 121 Severity: common.Severity(severity), 122 References: vuln.References, 123 Layer: &common.Layer{ 124 Digest: vuln.Layer.Digest, 125 DiffId: vuln.Layer.DiffID, 126 }, 127 Cvss: cvssMap, 128 SeveritySource: vuln.SeveritySource, 129 CweIds: vuln.CweIDs, 130 }) 131 } 132 return rpcVulns 133} 134 135func ConvertFromRpcResults(rpcResults []*scanner.Result) []report.Result { 136 var results []report.Result 137 138 for _, result := range rpcResults { 139 var vulns []types.DetectedVulnerability 140 for _, vuln := range result.Vulnerabilities { 141 severity := dbTypes.Severity(vuln.Severity) 142 cvssMap := make(dbTypes.VendorCVSS) // This is needed because protobuf generates a map[string]*CVSS type 143 for vendor, vendorSeverity := range vuln.Cvss { 144 cvssMap[vendor] = dbTypes.CVSS{ 145 V2Vector: vendorSeverity.V2Vector, 146 V3Vector: vendorSeverity.V3Vector, 147 V2Score: vendorSeverity.V2Score, 148 V3Score: vendorSeverity.V3Score, 149 } 150 } 151 152 vulns = append(vulns, types.DetectedVulnerability{ 153 VulnerabilityID: vuln.VulnerabilityId, 154 PkgName: vuln.PkgName, 155 InstalledVersion: vuln.InstalledVersion, 156 FixedVersion: vuln.FixedVersion, 157 Vulnerability: dbTypes.Vulnerability{ 158 Title: vuln.Title, 159 Description: vuln.Description, 160 Severity: severity.String(), 161 CVSS: cvssMap, 162 References: vuln.References, 163 CweIDs: vuln.CweIds, 164 }, 165 Layer: ftypes.Layer{ 166 Digest: vuln.Layer.Digest, 167 DiffID: vuln.Layer.DiffId, 168 }, 169 SeveritySource: vuln.SeveritySource, 170 }) 171 } 172 results = append(results, report.Result{ 173 Target: result.Target, 174 Vulnerabilities: vulns, 175 Type: result.Type, 176 }) 177 } 178 return results 179} 180 181func ConvertFromRpcOS(rpcOS *common.OS) *ftypes.OS { 182 if rpcOS == nil { 183 return nil 184 } 185 return &ftypes.OS{ 186 Family: rpcOS.Family, 187 Name: rpcOS.Name, 188 } 189} 190 191func ConvertFromRpcPackageInfos(rpcPkgInfos []*common.PackageInfo) []ftypes.PackageInfo { 192 var pkgInfos []ftypes.PackageInfo 193 for _, rpcPkgInfo := range rpcPkgInfos { 194 pkgInfos = append(pkgInfos, ftypes.PackageInfo{ 195 FilePath: rpcPkgInfo.FilePath, 196 Packages: ConvertFromRpcPkgs(rpcPkgInfo.Packages), 197 }) 198 } 199 return pkgInfos 200} 201 202func ConvertFromRpcApplications(rpcApps []*common.Application) []ftypes.Application { 203 var apps []ftypes.Application 204 for _, rpcApp := range rpcApps { 205 apps = append(apps, ftypes.Application{ 206 Type: rpcApp.Type, 207 FilePath: rpcApp.FilePath, 208 Libraries: ConvertFromRpcLibraries(rpcApp.Libraries), 209 }) 210 } 211 return apps 212} 213 214func ConvertFromRpcPutArtifactRequest(req *cache.PutArtifactRequest) ftypes.ArtifactInfo { 215 created, _ := ptypes.Timestamp(req.ArtifactInfo.Created) 216 return ftypes.ArtifactInfo{ 217 SchemaVersion: int(req.ArtifactInfo.SchemaVersion), 218 Architecture: req.ArtifactInfo.Architecture, 219 Created: created, 220 DockerVersion: req.ArtifactInfo.DockerVersion, 221 OS: req.ArtifactInfo.Os, 222 HistoryPackages: ConvertFromRpcPkgs(req.ArtifactInfo.HistoryPackages), 223 } 224} 225 226func ConvertFromRpcPutBlobRequest(req *cache.PutBlobRequest) ftypes.BlobInfo { 227 return ftypes.BlobInfo{ 228 SchemaVersion: int(req.BlobInfo.SchemaVersion), 229 Digest: req.BlobInfo.Digest, 230 DiffID: req.BlobInfo.DiffId, 231 OS: ConvertFromRpcOS(req.BlobInfo.Os), 232 PackageInfos: ConvertFromRpcPackageInfos(req.BlobInfo.PackageInfos), 233 Applications: ConvertFromRpcApplications(req.BlobInfo.Applications), 234 OpaqueDirs: req.BlobInfo.OpaqueDirs, 235 WhiteoutFiles: req.BlobInfo.WhiteoutFiles, 236 } 237} 238 239func ConvertToRpcOS(fos *ftypes.OS) *common.OS { 240 if fos == nil { 241 return nil 242 } 243 return &common.OS{ 244 Family: fos.Family, 245 Name: fos.Name, 246 } 247} 248 249func ConvertToRpcArtifactInfo(imageID string, imageInfo ftypes.ArtifactInfo) *cache.PutArtifactRequest { 250 t, err := ptypes.TimestampProto(imageInfo.Created) 251 if err != nil { 252 log.Logger.Warnf("invalid timestamp: %s", err) 253 } 254 255 return &cache.PutArtifactRequest{ 256 ArtifactId: imageID, 257 ArtifactInfo: &cache.ArtifactInfo{ 258 SchemaVersion: int32(imageInfo.SchemaVersion), 259 Architecture: imageInfo.Architecture, 260 Created: t, 261 DockerVersion: imageInfo.DockerVersion, 262 Os: imageInfo.OS, 263 HistoryPackages: ConvertToRpcPkgs(imageInfo.HistoryPackages), 264 }, 265 } 266} 267 268func ConvertToRpcBlobInfo(diffID string, layerInfo ftypes.BlobInfo) *cache.PutBlobRequest { 269 var packageInfos []*common.PackageInfo 270 for _, pkgInfo := range layerInfo.PackageInfos { 271 packageInfos = append(packageInfos, &common.PackageInfo{ 272 FilePath: pkgInfo.FilePath, 273 Packages: ConvertToRpcPkgs(pkgInfo.Packages), 274 }) 275 } 276 277 var applications []*common.Application 278 for _, app := range layerInfo.Applications { 279 var libs []*common.Library 280 for _, lib := range app.Libraries { 281 libs = append(libs, &common.Library{ 282 Name: lib.Library.Name, 283 Version: lib.Library.Version, 284 }) 285 286 } 287 applications = append(applications, &common.Application{ 288 Type: app.Type, 289 FilePath: app.FilePath, 290 Libraries: libs, 291 }) 292 } 293 294 return &cache.PutBlobRequest{ 295 DiffId: diffID, 296 BlobInfo: &cache.BlobInfo{ 297 SchemaVersion: ftypes.BlobJSONSchemaVersion, 298 Digest: layerInfo.Digest, 299 DiffId: layerInfo.DiffID, 300 Os: ConvertToRpcOS(layerInfo.OS), 301 PackageInfos: packageInfos, 302 Applications: applications, 303 OpaqueDirs: layerInfo.OpaqueDirs, 304 WhiteoutFiles: layerInfo.WhiteoutFiles, 305 }, 306 } 307} 308 309func ConvertToMissingBlobsRequest(imageID string, layerIDs []string) *cache.MissingBlobsRequest { 310 return &cache.MissingBlobsRequest{ 311 ArtifactId: imageID, 312 BlobIds: layerIDs, 313 } 314} 315 316func ConvertToRpcScanResponse(results report.Results, os *ftypes.OS, eosl bool) *scanner.ScanResponse { 317 rpcOS := &common.OS{} 318 if os != nil { 319 rpcOS.Family = os.Family 320 rpcOS.Name = os.Name 321 } 322 323 var rpcResults []*scanner.Result 324 for _, result := range results { 325 rpcResults = append(rpcResults, &scanner.Result{ 326 Target: result.Target, 327 Vulnerabilities: ConvertToRpcVulns(result.Vulnerabilities), 328 Type: result.Type, 329 }) 330 } 331 332 return &scanner.ScanResponse{ 333 Os: rpcOS, 334 Eosl: eosl, 335 Results: rpcResults, 336 } 337} 338