/// <summary> /// Initializes a new instance of the <see cref="AzskAuditProcessor"/> class. /// </summary> /// <param name="blobStorage">Blob Storage implementation.</param> /// <param name="db">Joseki database implementation.</param> /// <param name="cache">Checks cache object.</param> /// <param name="postProcessor">ExtractOwnershipProcessor.</param> public AzskAuditProcessor(IBlobStorageProcessor blobStorage, IJosekiDatabase db, ChecksCache cache, ExtractOwnershipProcessor postProcessor) { this.blobStorage = blobStorage; this.db = db; this.cache = cache; this.extractOwnershipProcessor = postProcessor; }
public async Task ProcessAuditHappyPath() { // Arrange await using var context = JosekiTestsDb.CreateUniqueContext(); var parser = new ConfigurationParser("config.sample.yaml"); var checksCache = new ChecksCache(parser, context, new MemoryCache(new MemoryCacheOptions())); var blobsMock = new Mock <IBlobStorageProcessor>(MockBehavior.Strict); var dbMock = new Mock <IJosekiDatabase>(); var queueMock = new Mock <IQueue>(); var ownershipCache = new OwnershipCache(context, new MemoryCache(new MemoryCacheOptions())); var postProcessor = new Mock <ExtractOwnershipProcessor>(context, ownershipCache); var processor = new PolarisAuditProcessor(blobsMock.Object, dbMock.Object, checksCache, queueMock.Object, postProcessor.Object); var container = new ScannerContainer(Path.Combine("audits", "samples", "polaris")) { Metadata = new ScannerMetadata { Type = ScannerType.Polaris, Id = Guid.NewGuid().ToString(), }, }; var audit = new AuditBlob { Name = "meta.json", ParentContainer = container }; blobsMock .Setup(i => i.GetUnprocessedAudits(container)) .ReturnsAsync(new[] { audit }) .Verifiable(); blobsMock .Setup(i => i.DownloadFile($"{container.Name}/{audit.Name}")) .ReturnsAsync(File.OpenRead($"{container.Name}/{audit.Name}")) .Verifiable(); blobsMock .Setup(i => i.DownloadFile($"{container.Name}/audit.json")) .ReturnsAsync(File.OpenRead($"{container.Name}/audit.json")) .Verifiable(); blobsMock .Setup(i => i.DownloadFile($"{container.Name}/k8s-meta.json")) .ReturnsAsync(File.OpenRead($"{container.Name}/k8s-meta.json")) .Verifiable(); blobsMock .Setup(i => i.MarkAsProcessed(audit)) .Returns(Task.CompletedTask) .Verifiable(); // Act & Assert await processor.Process(container, CancellationToken.None); blobsMock.Verify(); dbMock.Verify(i => i.GetNotExpiredImageScans(It.Is <string[]>(tags => tags.Length == UniqueImageTagCount))); dbMock.Verify(i => i.SaveInProgressImageScan(It.IsAny <ImageScanResultWithCVEs>()), Times.Exactly(UniqueImageTagCount)); queueMock.Verify(i => i.EnqueueImageScanRequest(It.IsAny <ImageScanResultWithCVEs>()), Times.Exactly(UniqueImageTagCount)); dbMock.Verify(i => i.SaveAuditResult(It.Is <Audit>(a => VerifyHappyPathAudit(a, container)))); }
public async Task ProcessAuditHappyPath() { // Arrange await using var context = JosekiTestsDb.CreateUniqueContext(); var parser = new ConfigurationParser("config.sample.yaml"); var checksCache = new ChecksCache(parser, context, new MemoryCache(new MemoryCacheOptions())); var blobsMock = new Mock <IBlobStorageProcessor>(MockBehavior.Strict); var dbMock = new Mock <IJosekiDatabase>(); var ownershipCache = new OwnershipCache(context, new MemoryCache(new MemoryCacheOptions())); var postProcessor = new Mock <ExtractOwnershipProcessor>(context, ownershipCache); var processor = new AzskAuditProcessor(blobsMock.Object, dbMock.Object, checksCache, postProcessor.Object); var container = new ScannerContainer(Path.Combine("audits", "samples", "azsk")) { Metadata = new ScannerMetadata { Type = ScannerType.Azsk, Id = Guid.NewGuid().ToString(), }, }; var audit = new AuditBlob { Name = "meta.json", ParentContainer = container }; blobsMock .Setup(i => i.GetUnprocessedAudits(container)) .ReturnsAsync(new[] { audit }) .Verifiable(); blobsMock .Setup(i => i.DownloadFile($"{container.Name}/{audit.Name}")) .ReturnsAsync(File.OpenRead($"{container.Name}/{audit.Name}")) .Verifiable(); blobsMock .Setup(i => i.DownloadFile($"{container.Name}/resources.json")) .ReturnsAsync(File.OpenRead($"{container.Name}/resources.json")) .Verifiable(); blobsMock .Setup(i => i.DownloadFile($"{container.Name}/subscription.json")) .ReturnsAsync(File.OpenRead($"{container.Name}/subscription.json")) .Verifiable(); blobsMock .Setup(i => i.MarkAsProcessed(audit)) .Returns(Task.CompletedTask) .Verifiable(); // Act & Assert await processor.Process(container, CancellationToken.None); blobsMock.Verify(); dbMock.Verify(i => i.SaveAuditResult(It.Is <Audit>(a => VerifyHappyPathAudit(a, container)))); }
public async Task ExpiredThresholdCausesAzskRecordUpdate() { // Arrange await using var context = JosekiTestsDb.CreateUniqueContext(); var parser = new ConfigurationParser("config.sample.yaml"); var checksCache = new ChecksCache(parser, context, new MemoryCache(new MemoryCacheOptions())); var id = $"azsk.{Guid.NewGuid().ToString()}"; var now = DateTime.UtcNow; var expirationDate = now.AddDays(-(parser.Get().Cache.AzureCheckTtl + 1)); var oldCheck = new CheckEntity { CheckId = id, Category = Guid.NewGuid().ToString(), Description = Guid.NewGuid().ToString(), Severity = joseki.db.entities.CheckSeverity.Medium, DateUpdated = expirationDate, DateCreated = expirationDate, }; // this is the hack -_- // Use sync version, because it does not update DateUpdated & DateCreated context.Check.Add(oldCheck); context.SaveChanges(); var newCheck = new Check { Id = id, Category = Guid.NewGuid().ToString(), Description = Guid.NewGuid().ToString(), Remediation = Guid.NewGuid().ToString(), Severity = CheckSeverity.High, }; // Act & Assert context.Check.Count().Should().Be(1, "context should have the only one record before GetOrAddItem"); await checksCache.GetOrAddItem(id, () => newCheck); var actualEntity = await context.Check.FirstAsync(i => i.CheckId == id); actualEntity.Category.Should().Be(newCheck.Category); actualEntity.Description.Should().Be(newCheck.Description); actualEntity.Remediation.Should().Be(newCheck.Remediation); actualEntity.Severity.Should().Be(joseki.db.entities.CheckSeverity.High); actualEntity.DateUpdated.Should().BeOnOrAfter(now); }
public async Task GetNotExistingItemAddOneRecordToDb() { // Arrange await using var context = JosekiTestsDb.CreateUniqueContext(); var parser = new ConfigurationParser("config.sample.yaml"); var checksCache = new ChecksCache(parser, context, new MemoryCache(new MemoryCacheOptions())); var id = $"azsk.{Guid.NewGuid().ToString()}"; var check = new Check { Id = id, Category = Guid.NewGuid().ToString(), Description = Guid.NewGuid().ToString(), Severity = CheckSeverity.High }; // Act & Assert context.Check.Count().Should().Be(0, "context should be empty before GetOrAddItem"); await checksCache.GetOrAddItem(id, () => check); context.Check.Count().Should().Be(1, "context should have a single value after GetOrAddItem"); }
public async Task GetExistingItemDoesNotAddNewRecords() { // Arrange await using var context = JosekiTestsDb.CreateUniqueContext(); var parser = new ConfigurationParser("config.sample.yaml"); var checksCache = new ChecksCache(parser, context, new MemoryCache(new MemoryCacheOptions())); var id = $"azsk.{Guid.NewGuid().ToString()}"; var check = new Check { Id = id, Category = Guid.NewGuid().ToString(), Description = Guid.NewGuid().ToString(), Severity = CheckSeverity.High }; context.Check.Add(check.ToEntity()); await context.SaveChangesAsync(); // Act & Assert context.Check.Count().Should().Be(1, "context should have the only one record before GetOrAddItem"); await checksCache.GetOrAddItem(id, () => check); context.Check.Count().Should().Be(1, "context should still have the only one record after GetOrAddItem"); }
public async Task GetImageScanCheckInsertsPredefinedImageScanEntity() { // Arrange await using var context = JosekiTestsDb.CreateUniqueContext(); var parser = new ConfigurationParser("config.sample.yaml"); var checksCache = new ChecksCache(parser, context, new MemoryCache(new MemoryCacheOptions())); var checkEntity = ChecksCache.ImageScanCheck.ToEntity(); // Act & Assert context.Check.Count().Should().Be(0, "context should be empty before the first GetOrAddItem"); await checksCache.GetImageScanCheck(); context.Check.Count().Should().Be(1, "context should have a single value after three GetOrAddItem"); var actualEntity = await context.Check.FirstAsync(i => i.CheckId == ChecksCache.ImageScanCheck.Id); actualEntity.Category.Should().Be(checkEntity.Category); actualEntity.Description.Should().Be(checkEntity.Description); actualEntity.Remediation.Should().Be(checkEntity.Remediation); actualEntity.Severity.Should().Be(checkEntity.Severity); }