/// <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))));
        }
Esempio n. 3
0
        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))));
        }
Esempio n. 4
0
        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);
        }
Esempio n. 5
0
        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");
        }
Esempio n. 6
0
        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");
        }
Esempio n. 7
0
        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);
        }