private async Task <ContainerImageScanResult> CalculateCounters(ImageScanResultEntity scan) { var cves = await this.db.Set <ImageScanToCveEntity>() .Include("CVE") .AsNoTracking() .Where(i => i.ScanId == scan.Id) .Select(i => new { i.CVE.Id, i.CVE.Severity }) .ToArrayAsync(); var counters = cves .GroupBy(i => i.Severity) .Select(i => new VulnerabilityCounters() { Count = i.Count(), Severity = i.Key.ToString() }) .ToArray(); return(new ContainerImageScanResult { Image = scan.ImageTag, ScanResult = ScanResult.Succeeded, Counters = counters, Date = scan.Date, }); }
/// <summary> /// Creates Image Scan entity from internal model. /// </summary> /// <param name="scan">Internal Image Scan model.</param> /// <returns>Database compatible entity.</returns> public static ImageScanResultEntity ToEntity(this ImageScanResultWithCVEs scan) { var entity = new ImageScanResultEntity { ExternalId = scan.Id, ImageTag = scan.ImageTag, Date = scan.Date, Status = scan.Status.ToEntity(), Description = scan.Description, FoundCVEs = scan.FoundCVEs?.Select(i => i.ToEntity()).ToList(), }; return(entity); }
private async Task <ContainerImageScanResult> ParseCveDetails(ImageScanResultEntity scan) { var cves = await this.db.Set <ImageScanToCveEntity>() .Include("CVE") .AsNoTracking() .Where(i => i.ScanId == scan.Id) .Select(i => new { i.Target, i.UsedPackage, i.UsedPackageVersion, i.CVE.CveId, i.CVE.Severity, i.CVE.PackageName, i.CVE.Description, i.CVE.Title, i.CVE.References, i.CVE.Remediation }) .ToArrayAsync(); var targets = new List <ImageScanTarget>(); foreach (var target in cves.GroupBy(i => i.Target)) { var vulnerabilities = new List <VulnerabilityDescription>(); foreach (var groupedByCve in target.GroupBy(i => i.CveId)) { var cve = groupedByCve.First(); vulnerabilities.Add(new VulnerabilityDescription { VulnerabilityID = cve.CveId, PkgName = cve.PackageName, Title = cve.Title, Severity = cve.Severity.ToString(), Description = cve.Description, DependenciesWithCVE = groupedByCve.Select(i => i.UsedPackage).ToArray(), InstalledVersion = cve.UsedPackageVersion, Remediation = cve.Remediation, References = string.IsNullOrEmpty(cve.References) ? new string[0] : cve.References.Split(TrivyAuditProcessor.LineSeparator).Where(i => !string.IsNullOrWhiteSpace(i)).ToArray(), }); } targets.Add(new ImageScanTarget { Target = target.Key, Vulnerabilities = vulnerabilities.ToArray(), }); } return(new ContainerImageScanResult { Image = scan.ImageTag, ScanResult = ScanResult.Succeeded, Counters = new VulnerabilityCounters[0], Targets = targets.ToArray(), Date = scan.Date, }); }
public void GetShortResultImageScanCalculatesCorrectCounters() { // Arrange // create 1 critical, 2 high, 3 medium, 4 low, 5 unknown severity issues var entity = new ImageScanResultEntity { FoundCVEs = new List <ImageScanToCveEntity> { new ImageScanToCveEntity { CVE = new CveEntity { Severity = CveSeverity.Critical } }, new ImageScanToCveEntity { CVE = new CveEntity { Severity = CveSeverity.High } }, new ImageScanToCveEntity { CVE = new CveEntity { Severity = CveSeverity.High } }, new ImageScanToCveEntity { CVE = new CveEntity { Severity = CveSeverity.Medium } }, new ImageScanToCveEntity { CVE = new CveEntity { Severity = CveSeverity.Medium } }, new ImageScanToCveEntity { CVE = new CveEntity { Severity = CveSeverity.Medium } }, new ImageScanToCveEntity { CVE = new CveEntity { Severity = CveSeverity.Low } }, new ImageScanToCveEntity { CVE = new CveEntity { Severity = CveSeverity.Low } }, new ImageScanToCveEntity { CVE = new CveEntity { Severity = CveSeverity.Low } }, new ImageScanToCveEntity { CVE = new CveEntity { Severity = CveSeverity.Low } }, new ImageScanToCveEntity { CVE = new CveEntity { Severity = CveSeverity.Unknown } }, new ImageScanToCveEntity { CVE = new CveEntity { Severity = CveSeverity.Unknown } }, new ImageScanToCveEntity { CVE = new CveEntity { Severity = CveSeverity.Unknown } }, new ImageScanToCveEntity { CVE = new CveEntity { Severity = CveSeverity.Unknown } }, new ImageScanToCveEntity { CVE = new CveEntity { Severity = CveSeverity.Unknown } }, }, }; // Act var scanResult = entity.GetShortResult(); // Assert scanResult.Counters.Should().HaveCount(5); scanResult.Counters.First(i => i.Severity == webapp.Database.Models.CveSeverity.Critical).Count.Should().Be(1); scanResult.Counters.First(i => i.Severity == webapp.Database.Models.CveSeverity.High).Count.Should().Be(2); scanResult.Counters.First(i => i.Severity == webapp.Database.Models.CveSeverity.Medium).Count.Should().Be(3); scanResult.Counters.First(i => i.Severity == webapp.Database.Models.CveSeverity.Low).Count.Should().Be(4); scanResult.Counters.First(i => i.Severity == webapp.Database.Models.CveSeverity.Unknown).Count.Should().Be(5); }
public async Task SaveImageScanResultCouldUpdateExistingEntity() { // Arrange await using var context = JosekiTestsDb.CreateUniqueContext(); var queuedScan = new ImageScanResultEntity { Date = DateTime.UtcNow.AddMinutes(-10), ExternalId = Guid.NewGuid().ToString(), Description = Guid.NewGuid().ToString(), ImageTag = Guid.NewGuid().ToString(), Status = joseki.db.entities.ImageScanStatus.Queued, }; context.Set <ImageScanResultEntity>().Add(queuedScan); await context.SaveChangesAsync(); var scan = new ImageScanResultWithCVEs { Date = DateTime.UtcNow, Id = queuedScan.ExternalId, Description = Guid.NewGuid().ToString(), ImageTag = queuedScan.ImageTag, Status = ImageScanStatus.Succeeded, FoundCVEs = new List <ImageScanToCve> { new ImageScanToCve { InternalCveId = 1, Target = Guid.NewGuid().ToString(), UsedPackage = Guid.NewGuid().ToString(), UsedPackageVersion = Guid.NewGuid().ToString() }, new ImageScanToCve { InternalCveId = 2, Target = Guid.NewGuid().ToString(), UsedPackage = Guid.NewGuid().ToString(), UsedPackageVersion = Guid.NewGuid().ToString() }, new ImageScanToCve { InternalCveId = 3, Target = Guid.NewGuid().ToString(), UsedPackage = Guid.NewGuid().ToString(), UsedPackageVersion = Guid.NewGuid().ToString() }, }, }; var parser = new ConfigurationParser("config.sample.yaml"); var db = new MssqlJosekiDatabase(context, parser); // Act & Assert context.ImageScanResult.Should().HaveCount(1); context.ImageScanResultToCve.Should().HaveCount(0); await db.SaveImageScanResult(scan); context.ImageScanResult.Should().HaveCount(1); context.ImageScanResultToCve.Should().HaveCount(scan.FoundCVEs.Count); // Only Date, Description, Status, and CVEs should be updated var actual = await context.ImageScanResult.FirstAsync(); actual.Date.Should().Be(scan.Date); actual.Description.Should().Be(scan.Description); actual.Status.Should().Be(joseki.db.entities.ImageScanStatus.Succeeded); foreach (var actualCve in await context.ImageScanResultToCve.ToArrayAsync()) { var expectedCve = scan.FoundCVEs.First(i => i.InternalCveId == actualCve.CveId); actualCve.Target.Should().Be(expectedCve.Target); actualCve.UsedPackage.Should().Be(expectedCve.UsedPackage); actualCve.UsedPackageVersion.Should().Be(expectedCve.UsedPackageVersion); } }