public async Task RevokedResultDoesNotInvalidateDependentNonAuthorSignaturesSignatures(PackageSignatureType type)
            {
                // Arrange
                var revocationTime = DateTime.UtcNow;

                var verificationResult = new CertificateVerificationResult(
                    status: EndCertificateStatus.Revoked,
                    statusFlags: X509ChainStatusFlags.Revoked,
                    revocationTime: revocationTime);

                var signingState = new PackageSigningState {
                    SigningStatus = PackageSigningStatus.Valid
                };
                var signature2 = new PackageSignature {
                    Key = 12, Status = PackageSignatureStatus.Valid, Type = type
                };
                var timestamp2 = new TrustedTimestamp {
                    Value = revocationTime.AddDays(1), Status = TrustedTimestampStatus.Valid
                };

                signingState.PackageSignatures = new[] { signature2 };
                signature2.PackageSigningState = signingState;
                signature2.EndCertificate      = _certificate1;
                signature2.TrustedTimestamps   = new[] { timestamp2 };
                timestamp2.PackageSignature    = signature2;
                timestamp2.EndCertificate      = _certificate2;
                _certificate1.Use = EndCertificateUse.CodeSigning;
                _certificate2.Use = EndCertificateUse.Timestamping;
                _certificate1.PackageSignatures = new[] { signature2 };
                _certificate2.TrustedTimestamps = new[] { timestamp2 };

                _context.Mock(
                    packageSigningStates: new[] { signingState },
                    packageSignatures: new[] { signature2 },
                    trustedTimestamps: new[] { timestamp2 },
                    endCertificates: new[] { _certificate1, _certificate2 });

                var result = await _target.TrySaveResultAsync(_certificateValidation1, verificationResult);

                Assert.True(result);

                Assert.Equal(EndCertificateStatus.Revoked, _certificateValidation1.Status);

                Assert.Equal(EndCertificateStatus.Revoked, _certificate1.Status);
                Assert.Equal(0, _certificate1.ValidationFailures);
                Assert.Equal(revocationTime, _certificate1.RevocationTime);

                Assert.Equal(PackageSignatureStatus.Valid, signature2.Status);

                Assert.Equal(PackageSigningStatus.Valid, signingState.SigningStatus);

                _telemetryService.Verify(a => a.TrackUnableToValidateCertificateEvent(It.IsAny <EndCertificate>()), Times.Never);
                _telemetryService.Verify(a => a.TrackPackageSignatureShouldBeInvalidatedEvent(It.IsAny <PackageSignature>()), Times.Never);
                _telemetryService.Verify(a => a.TrackUnableToValidateCertificateEvent(It.IsAny <EndCertificate>()), Times.Never);
                _context.Verify(c => c.SaveChangesAsync(), Times.Once);
            }
Exemplo n.º 2
0
        /// <summary>
        /// Mark a package's signing state and its revoked signatures as invalid. This method does NOT
        /// persist entity changes to the database.
        /// </summary>
        /// <param name="request">The request to validate a package.</param>
        /// <param name="package">The package's overall signing state that should be invalidated.</param>
        /// <param name="signature">The package's signatures that should be invalidated.</param>
        /// <returns>A task that completes when the entities have been updated.</returns>
        private void InvalidatePackageSignature(IValidationRequest request, PackageSigningState package, PackageSignature signature)
        {
            _logger.LogWarning(
                "Invalidating package {PackageId} {PackageVersion} due to revoked signatures.",
                request.PackageId,
                request.PackageVersion);

            package.SigningStatus = PackageSigningStatus.Invalid;
            signature.Status      = PackageSignatureStatus.Invalid;
        }
Exemplo n.º 3
0
            public async Task DropsAllPackageSignaturesWhenPackageStateTransitionsToUnsigned()
            {
                // Arrange
                const int    packageKey              = 1;
                const string packageId               = "packageId";
                const string packageVersion          = "1.0.0";
                const PackageSigningStatus newStatus = PackageSigningStatus.Unsigned;

                var signature1 = new PackageSignature();
                var signature2 = new PackageSignature();

                var packageSigningState = new PackageSigningState
                {
                    PackageId                = packageId,
                    PackageKey               = packageKey,
                    SigningStatus            = PackageSigningStatus.Valid,
                    PackageNormalizedVersion = packageVersion,

                    PackageSignatures = new List <PackageSignature> {
                        signature1, signature2
                    }
                };

                var logger = _loggerFactory.CreateLogger <PackageSigningStateService>();
                var packageSigningStatesDbSetMock = DbSetMockFactory.CreateMock(packageSigningState);
                var packageSignaturesDbSetMock    = DbSetMockFactory.CreateMock(signature1, signature2);
                var validationContextMock         = new Mock <IValidationEntitiesContext>(MockBehavior.Strict);

                validationContextMock.Setup(m => m.PackageSigningStates).Returns(packageSigningStatesDbSetMock.Object);
                validationContextMock.Setup(m => m.PackageSignatures).Returns(packageSignaturesDbSetMock.Object);

                // Act
                var packageSigningStateService = new PackageSigningStateService(validationContextMock.Object, logger);

                // Assert
                await packageSigningStateService.SetPackageSigningState(
                    packageKey,
                    packageId,
                    packageVersion,
                    status : newStatus);

                // Assert
                Assert.Equal(newStatus, packageSigningState.SigningStatus);

                packageSignaturesDbSetMock.Verify(m => m.Remove(signature1), Times.Once);
                packageSignaturesDbSetMock.Verify(m => m.Remove(signature2), Times.Once);

                validationContextMock.Verify(
                    m => m.SaveChangesAsync(),
                    Times.Never,
                    "Saving the context here is incorrect as updating the validator's status also saves the context. Doing so would cause both queries not to be executed in the same transaction.");
            }
Exemplo n.º 4
0
        /// <summary>
        /// Mark a package's signing state and its revoked signatures as invalid. This method does NOT
        /// persist entity changes to the database.
        /// </summary>
        /// <param name="request">The request to validate a package.</param>
        /// <param name="package">The package's overall signing state that should be invalidated.</param>
        /// <param name="revokedSignatures">The package's signatures that should be invalidated.</param>
        /// <returns>A task that completes when the entities have been updated.</returns>
        private void InvalidatePackageSignatures(IValidationRequest request, PackageSigningState package, IEnumerable <PackageSignature> revokedSignatures)
        {
            _logger.LogWarning(
                "Invalidating package {PackageId} {PackageVersion} due to revoked signatures.",
                request.PackageId,
                request.PackageVersion);

            package.SigningStatus = PackageSigningStatus.Invalid;

            foreach (var signature in revokedSignatures)
            {
                signature.Status = PackageSignatureStatus.Invalid;
            }
        }
            public async Task RevokedResultInvalidatesDependentTimestamps()
            {
                // Arrange - "signature1" is a signature that whose timestamp depends on the certificate that will be revoked.
                var verificationResult = new CertificateVerificationResult(
                    status: EndCertificateStatus.Revoked,
                    statusFlags: X509ChainStatusFlags.Revoked,
                    revocationTime: DateTime.UtcNow);

                var signingState = new PackageSigningState {
                    SigningStatus = PackageSigningStatus.Valid
                };
                var signature1 = new PackageSignature
                {
                    Key    = 12,
                    Status = PackageSignatureStatus.Valid,
                    Type   = PackageSignatureType.Author,
                };
                var timestamp1 = new TrustedTimestamp {
                    Value = DateTime.UtcNow, Status = TrustedTimestampStatus.Valid
                };

                signingState.PackageSignatures = new[] { signature1 };
                signature1.PackageSigningState = signingState;
                signature1.EndCertificate      = _certificate1;
                signature1.TrustedTimestamps   = new[] { timestamp1 };
                timestamp1.PackageSignature    = signature1;
                timestamp1.EndCertificate      = _certificate1;
                _certificate1.Use = EndCertificateUse.Timestamping;
                _certificate1.PackageSignatures = new[] { signature1 };

                _context.Mock(
                    packageSigningStates: new[] { signingState },
                    packageSignatures: new[] { signature1 },
                    trustedTimestamps: new[] { timestamp1 },
                    endCertificates: new[] { _certificate1 });

                var result = await _target.TrySaveResultAsync(_certificateValidation1, verificationResult);

                Assert.True(result);

                Assert.Equal(EndCertificateStatus.Revoked, _certificateValidation1.Status);
                Assert.Equal(TrustedTimestampStatus.Invalid, timestamp1.Status);
                Assert.Equal(EndCertificateStatus.Revoked, _certificate1.Status);
                Assert.Equal(PackageSignatureStatus.Invalid, signature1.Status);
                Assert.Equal(PackageSigningStatus.Invalid, signingState.SigningStatus);
            }
Exemplo n.º 6
0
        public async Task ValidateSigningCertificate(
            Func <CertificateIntegrationTestFixture, Task <X509Certificate2> > createCertificateFunc,
            DateTime signatureTime,
            EndCertificateStatus expectedCertificateStatus,
            PackageSignatureStatus expectedStatusForSignatureAtIngestion,
            PackageSignatureStatus expectedStatusForSignatureInGracePeriod,
            PackageSignatureStatus expectedStatusForSignatureAfterGracePeriod)
        {
            // Arrange
            var certificate = await createCertificateFunc(_fixture);

            var endCertificateKey = 123;
            var validationId      = Guid.NewGuid();

            var packageSigningState1 = new PackageSigningState {
                SigningStatus = PackageSigningStatus.Valid
            };
            var packageSigningState2 = new PackageSigningState {
                SigningStatus = PackageSigningStatus.Valid
            };
            var packageSigningState3 = new PackageSigningState {
                SigningStatus = PackageSigningStatus.Valid
            };

            var signatureAtIngestion = new PackageSignature
            {
                Status = PackageSignatureStatus.Unknown,
                Type   = PackageSignatureType.Author,
            };
            var signatureInGracePeriod = new PackageSignature
            {
                Status = PackageSignatureStatus.InGracePeriod,
                Type   = PackageSignatureType.Author,
            };
            var signatureAfterGracePeriod = new PackageSignature
            {
                Status = PackageSignatureStatus.Valid,
                Type   = PackageSignatureType.Author,
            };

            var trustedTimestamp1 = new TrustedTimestamp {
                Status = TrustedTimestampStatus.Valid, Value = signatureTime
            };
            var trustedTimestamp2 = new TrustedTimestamp {
                Status = TrustedTimestampStatus.Valid, Value = signatureTime
            };
            var trustedTimestamp3 = new TrustedTimestamp {
                Status = TrustedTimestampStatus.Valid, Value = signatureTime
            };

            var endCertificate = new EndCertificate
            {
                Key    = endCertificateKey,
                Status = EndCertificateStatus.Unknown,
                Use    = EndCertificateUse.CodeSigning,
                CertificateChainLinks = new CertificateChainLink[0],
            };

            var validation = new EndCertificateValidation
            {
                EndCertificateKey = endCertificateKey,
                ValidationId      = validationId,
                Status            = null,
                EndCertificate    = endCertificate
            };

            signatureAtIngestion.PackageSigningState      = packageSigningState1;
            signatureAtIngestion.EndCertificate           = endCertificate;
            signatureAtIngestion.TrustedTimestamps        = new[] { trustedTimestamp1 };
            signatureInGracePeriod.PackageSigningState    = packageSigningState2;
            signatureInGracePeriod.EndCertificate         = endCertificate;
            signatureInGracePeriod.TrustedTimestamps      = new[] { trustedTimestamp2 };
            signatureAfterGracePeriod.PackageSigningState = packageSigningState3;
            signatureAfterGracePeriod.EndCertificate      = endCertificate;
            signatureAfterGracePeriod.TrustedTimestamps   = new[] { trustedTimestamp3 };

            _context.Mock(
                packageSignatures: new[] { signatureAtIngestion, signatureInGracePeriod, signatureAfterGracePeriod },
                endCertificates: new[] { endCertificate },
                certificateValidations: new EndCertificateValidation[] { validation });

            _certificateStore.Setup(s => s.LoadAsync(It.IsAny <string>(), It.IsAny <CancellationToken>()))
            .Returns(Task.FromResult(certificate));

            // Act
            await _target.HandleAsync(new CertificateValidationMessage(certificateKey : endCertificateKey, validationId : validationId));

            // Assert
            Assert.Equal(expectedCertificateStatus, validation.Status);
            Assert.Equal(expectedCertificateStatus, endCertificate.Status);
            Assert.Equal(expectedStatusForSignatureAtIngestion, signatureAtIngestion.Status);
            Assert.Equal(expectedStatusForSignatureInGracePeriod, signatureInGracePeriod.Status);
            Assert.Equal(expectedStatusForSignatureAfterGracePeriod, signatureAfterGracePeriod.Status);

            _context.Verify(c => c.SaveChangesAsync(), Times.Once);
        }
Exemplo n.º 7
0
        public async Task ValidateTimestampingCertificate()
        {
            // Arrange
            var certificate = await _fixture.GetRevokedTimestampingCertificateAsync(RevocationTime);

            var endCertificateKey = 123;
            var validationId      = Guid.NewGuid();

            var packageSigningState = new PackageSigningState {
                SigningStatus = PackageSigningStatus.Valid
            };

            var signatureAtIngestion = new PackageSignature
            {
                Status = PackageSignatureStatus.Unknown,
                Type   = PackageSignatureType.Author,
            };
            var signatureInGracePeriod = new PackageSignature
            {
                Status = PackageSignatureStatus.InGracePeriod,
                Type   = PackageSignatureType.Author,
            };
            var signatureAfterGracePeriod = new PackageSignature
            {
                Status = PackageSignatureStatus.Valid,
                Type   = PackageSignatureType.Author,
            };

            var endCertificate = new EndCertificate
            {
                Key    = endCertificateKey,
                Status = EndCertificateStatus.Unknown,
                Use    = EndCertificateUse.Timestamping,
                CertificateChainLinks = new CertificateChainLink[0],
            };

            var trustedTimestamp = new TrustedTimestamp
            {
                EndCertificate = endCertificate,
                Status         = TrustedTimestampStatus.Valid
            };

            var validation = new EndCertificateValidation
            {
                EndCertificateKey = endCertificateKey,
                ValidationId      = validationId,
                Status            = null,
                EndCertificate    = endCertificate
            };

            signatureAtIngestion.PackageSigningState      = packageSigningState;
            signatureAtIngestion.TrustedTimestamps        = new[] { trustedTimestamp };
            signatureInGracePeriod.PackageSigningState    = packageSigningState;
            signatureInGracePeriod.TrustedTimestamps      = new[] { trustedTimestamp };
            signatureAfterGracePeriod.PackageSigningState = packageSigningState;
            signatureAfterGracePeriod.TrustedTimestamps   = new[] { trustedTimestamp };

            _context.Mock(
                packageSignatures: new[] { signatureAtIngestion, signatureInGracePeriod, signatureAfterGracePeriod },
                endCertificates: new[] { endCertificate },
                certificateValidations: new EndCertificateValidation[] { validation });

            _certificateStore.Setup(s => s.LoadAsync(It.IsAny <string>(), It.IsAny <CancellationToken>()))
            .Returns(Task.FromResult(certificate));

            // Act
            await _target.HandleAsync(new CertificateValidationMessage(certificateKey : endCertificateKey, validationId : validationId));

            // Assert
            Assert.Equal(EndCertificateStatus.Revoked, validation.Status);
            Assert.Equal(EndCertificateStatus.Revoked, endCertificate.Status);
            Assert.Equal(PackageSignatureStatus.Invalid, signatureAtIngestion.Status);
            Assert.Equal(PackageSignatureStatus.Invalid, signatureInGracePeriod.Status);
            Assert.Equal(PackageSignatureStatus.Invalid, signatureAfterGracePeriod.Status);

            _context.Verify(c => c.SaveChangesAsync(), Times.Once);
        }
            public async Task InvalidResultInvalidatesDependentSignatures()
            {
                // Arrange - Invalidate a certificate that is depended on by "signature1"'s certificate.
                // This should result in "signature1" being invalidated.
                var verificationResult = new CertificateVerificationResult(
                    status: EndCertificateStatus.Invalid,
                    statusFlags: X509ChainStatusFlags.ExplicitDistrust);

                var signingState = new PackageSigningState {
                    SigningStatus = PackageSigningStatus.Valid
                };
                var signature1 = new PackageSignature
                {
                    Key    = 123,
                    Status = PackageSignatureStatus.Valid,
                    Type   = PackageSignatureType.Author,
                };
                var signature2 = new PackageSignature
                {
                    Key    = 456,
                    Status = PackageSignatureStatus.Valid,
                    Type   = PackageSignatureType.Author,
                };
                var timestamp = new TrustedTimestamp {
                    Value = DateTime.UtcNow
                };

                signingState.PackageSignatures  = new[] { signature1, signature2 };
                signature1.PackageSigningState  = signingState;
                signature2.PackageSigningState  = signingState;
                signature1.EndCertificate       = _certificate1;
                signature2.EndCertificate       = _certificate2;
                signature1.TrustedTimestamps    = new TrustedTimestamp[0];
                signature2.TrustedTimestamps    = new[] { timestamp };
                timestamp.PackageSignature      = signature2;
                timestamp.EndCertificate        = _certificate1;
                _certificate1.PackageSignatures = new[] { signature1 };
                _certificate1.TrustedTimestamps = new[] { timestamp };
                _certificate1.Use = EndCertificateUse.CodeSigning;

                _context.Mock(
                    packageSignatures: new[] { signature1, signature2 },
                    trustedTimestamps: new[] { timestamp });

                // Act
                var result = await _target.TrySaveResultAsync(_certificateValidation1, verificationResult);

                Assert.True(result);

                Assert.Equal(EndCertificateStatus.Invalid, _certificateValidation1.Status);

                Assert.Equal(EndCertificateStatus.Invalid, _certificate1.Status);
                Assert.Equal(0, _certificate1.ValidationFailures);
                Assert.Null(_certificate1.RevocationTime);

                Assert.Equal(PackageSignatureStatus.Invalid, signature1.Status);
                Assert.Equal(PackageSignatureStatus.Valid, signature2.Status);

                Assert.Equal(PackageSigningStatus.Invalid, signingState.SigningStatus);

                // The package's signing state is "Valid", a MayBeInvalidated (warn) event should be raised.
                _telemetryService.Verify(a => a.TrackUnableToValidateCertificateEvent(It.IsAny <EndCertificate>()), Times.Never);
                _telemetryService.Verify(a => a.TrackPackageSignatureMayBeInvalidatedEvent(It.IsAny <PackageSignature>()), Times.Exactly(1));
                _telemetryService.Verify(a => a.TrackPackageSignatureShouldBeInvalidatedEvent(It.IsAny <PackageSignature>()), Times.Exactly(0));
                _context.Verify(c => c.SaveChangesAsync(), Times.Once);
            }
            public async Task ProcessesSignaturesInBatchesOf500()
            {
                // Arrange - Invalidate a certificate that is depended on by 501 signatures.
                // This should invalidate all signatures in batches of 500 signatures.
                var verificationResult = new CertificateVerificationResult(
                    status: EndCertificateStatus.Invalid,
                    statusFlags: X509ChainStatusFlags.ExplicitDistrust);

                var signatures = new List <PackageSignature>();

                for (var i = 0; i < 501; i++)
                {
                    var state = new PackageSigningState {
                        SigningStatus = PackageSigningStatus.Valid
                    };

                    var signature = new PackageSignature
                    {
                        Key    = i,
                        Status = PackageSignatureStatus.Valid,
                        Type   = PackageSignatureType.Author
                    };

                    state.PackageSignatures       = new[] { signature };
                    signature.PackageSigningState = state;
                    signature.EndCertificate      = _certificate1;
                    signature.TrustedTimestamps   = new TrustedTimestamp[0];

                    signatures.Add(signature);
                }

                _certificate1.PackageSignatures = signatures;
                _certificate1.TrustedTimestamps = new TrustedTimestamp[0];
                _certificate1.Use = EndCertificateUse.CodeSigning;

                _context.Mock(packageSignatures: signatures);

                var hasSaved = false;
                var invalidationsBeforeSave = 0;
                var invalidationsAfterSave  = 0;

                _context.Setup(c => c.SaveChangesAsync())
                .Returns(Task.FromResult(0))
                .Callback(() => hasSaved = true);

                _telemetryService
                .Setup(t => t.TrackPackageSignatureMayBeInvalidatedEvent(It.IsAny <PackageSignature>()))
                .Callback((PackageSignature s) =>
                {
                    if (!hasSaved)
                    {
                        invalidationsBeforeSave++;
                    }
                    else
                    {
                        invalidationsAfterSave++;
                    }
                });

                // Act
                var result = await _target.TrySaveResultAsync(_certificateValidation1, verificationResult);

                // Assert - two batches should be saved. The first batch should invalidate 500 signatures,
                // the second batch should invalidate 1 signature.
                _context.Verify(c => c.SaveChangesAsync(), Times.Exactly(2));

                Assert.Equal(500, invalidationsBeforeSave);
                Assert.Equal(1, invalidationsAfterSave);
            }
            public async Task RevokedResultInvalidatesDependentSignatures()
            {
                // Arrange - "signature1" is a signature that uses the certificate before the revocation date,
                // "signature2" is a signature that uses the certificate after the revocation date, "signature3"
                // is a signature that doesn't depend on the certificate.
                var revocationTime = DateTime.UtcNow;

                var verificationResult = new CertificateVerificationResult(
                    status: EndCertificateStatus.Revoked,
                    statusFlags: X509ChainStatusFlags.Revoked,
                    revocationTime: revocationTime);

                var signingState = new PackageSigningState {
                    SigningStatus = PackageSigningStatus.Valid
                };
                var signature1 = new PackageSignature
                {
                    Key    = 12,
                    Status = PackageSignatureStatus.Valid,
                    Type   = PackageSignatureType.Author,
                };
                var signature2 = new PackageSignature
                {
                    Key    = 23,
                    Status = PackageSignatureStatus.Valid,
                    Type   = PackageSignatureType.Author,
                };
                var signature3 = new PackageSignature
                {
                    Key    = 34,
                    Status = PackageSignatureStatus.Valid,
                    Type   = PackageSignatureType.Author,
                };
                var timestamp1 = new TrustedTimestamp {
                    Value = revocationTime.AddDays(-1), Status = TrustedTimestampStatus.Valid
                };
                var timestamp2 = new TrustedTimestamp {
                    Value = revocationTime.AddDays(1), Status = TrustedTimestampStatus.Valid
                };
                var timestamp3 = new TrustedTimestamp {
                    Value = revocationTime.AddDays(-1), Status = TrustedTimestampStatus.Valid
                };

                signingState.PackageSignatures = new[] { signature1, signature2, signature3 };
                signature1.PackageSigningState = signingState;
                signature2.PackageSigningState = signingState;
                signature3.PackageSigningState = signingState;
                signature1.EndCertificate      = _certificate1;
                signature2.EndCertificate      = _certificate1;
                signature3.EndCertificate      = _certificate2;
                signature1.TrustedTimestamps   = new[] { timestamp1 };
                signature2.TrustedTimestamps   = new[] { timestamp2 };
                signature3.TrustedTimestamps   = new[] { timestamp3 };
                timestamp1.PackageSignature    = signature1;
                timestamp2.PackageSignature    = signature2;
                timestamp3.PackageSignature    = signature3;
                timestamp1.EndCertificate      = _certificate2;
                timestamp2.EndCertificate      = _certificate2;
                timestamp3.EndCertificate      = _certificate2;
                _certificate1.Use = EndCertificateUse.CodeSigning;
                _certificate2.Use = EndCertificateUse.Timestamping;
                _certificate1.PackageSignatures = new[] { signature1, signature2 };
                _certificate2.TrustedTimestamps = new[] { timestamp1, timestamp2, timestamp3 };

                _context.Mock(
                    packageSigningStates: new[] { signingState },
                    packageSignatures: new[] { signature1, signature2, signature3 },
                    trustedTimestamps: new[] { timestamp1, timestamp2, timestamp3 },
                    endCertificates: new[] { _certificate1, _certificate2 });

                var result = await _target.TrySaveResultAsync(_certificateValidation1, verificationResult);

                Assert.True(result);

                Assert.Equal(EndCertificateStatus.Revoked, _certificateValidation1.Status);

                Assert.Equal(EndCertificateStatus.Revoked, _certificate1.Status);
                Assert.Equal(0, _certificate1.ValidationFailures);
                Assert.Equal(revocationTime, _certificate1.RevocationTime);

                Assert.Equal(PackageSignatureStatus.Valid, signature1.Status);
                Assert.Equal(PackageSignatureStatus.Invalid, signature2.Status);
                Assert.Equal(PackageSignatureStatus.Valid, signature3.Status);

                Assert.Equal(PackageSigningStatus.Invalid, signingState.SigningStatus);

                _telemetryService.Verify(a => a.TrackUnableToValidateCertificateEvent(It.IsAny <EndCertificate>()), Times.Never);
                _telemetryService.Verify(a => a.TrackPackageSignatureShouldBeInvalidatedEvent(It.IsAny <PackageSignature>()), Times.Exactly(1));
                _context.Verify(c => c.SaveChangesAsync(), Times.Once);
            }