public async Task WaitsForPackageAvailabilityInGalleryDBWithCheckValidator() { var messageData = PackageValidationMessageData.NewCheckValidator(Guid.NewGuid()); var validationConfiguration = new ValidationConfiguration(); var validationSet = new PackageValidationSet { PackageKey = 42, ValidatingType = ValidatingType.SymbolPackage }; ValidationSetProviderMock .Setup(ps => ps.TryGetParentValidationSetAsync(messageData.CheckValidator.ValidationId)) .ReturnsAsync(validationSet) .Verifiable(); CoreSymbolPackageServiceMock .Setup(ps => ps.FindPackageByKey(validationSet.PackageKey)) .Returns <SymbolPackage>(null) .Verifiable(); var handler = CreateHandler(); var result = await handler.HandleAsync(messageData); ValidationSetProviderMock.Verify( ps => ps.TryGetParentValidationSetAsync(messageData.CheckValidator.ValidationId), Times.Once); CoreSymbolPackageServiceMock.Verify( ps => ps.FindPackageByKey(validationSet.PackageKey), Times.Once); Assert.False(result, "The handler should not have succeeded."); }
public async Task DropsMessageIfPackageIsSoftDeletedForCheckValidator() { var messageData = PackageValidationMessageData.NewCheckValidator(Guid.NewGuid()); var validationConfiguration = new ValidationConfiguration(); var package = new Package { Key = 42, PackageStatusKey = PackageStatus.Deleted }; var packageValidatingEntity = new PackageValidatingEntity(package); var validationSet = new PackageValidationSet { PackageKey = package.Key, ValidatingType = ValidatingType.Package }; ValidationSetProviderMock .Setup(ps => ps.TryGetParentValidationSetAsync(messageData.CheckValidator.ValidationId)) .ReturnsAsync(validationSet) .Verifiable(); CorePackageServiceMock .Setup(ps => ps.FindPackageByKey(package.Key)) .Returns(packageValidatingEntity); var handler = CreateHandler(); var result = await handler.HandleAsync(messageData); Assert.True(result); ValidationSetProviderMock.Verify( vsp => vsp.TryGetParentValidationSetAsync(messageData.CheckValidator.ValidationId), Times.Once); CorePackageServiceMock.Verify( ps => ps.FindPackageByKey(package.Key), Times.Once); }
public HandleCheckValidatorAsync(ITestOutputHelper output) : base(output) { ValidationId = new Guid("1f25a05c-4bbb-4366-a0bf-d9acef69cca1"); Message = PackageValidationMessageData.NewCheckValidator(ValidationId); ValidationSetProvider .Setup(x => x.TryGetParentValidationSetAsync(It.IsAny <Guid>())) .ReturnsAsync(() => ValidationSet); }
public void ProducesExpectedMessageForCheckValidator() { // Arrange var input = PackageValidationMessageData.NewCheckValidator(ValidationId); // Act var output = _target.SerializePackageValidationMessageData(input); // Assert Assert.Contains(SchemaVersionKey, output.Properties.Keys); Assert.Equal(SchemaVersion1, output.Properties[SchemaVersionKey]); Assert.Contains(SchemaName, output.Properties.Keys); Assert.Equal(CheckValidatorType, output.Properties[SchemaName]); var body = output.GetBody(); Assert.Equal(TestData.SerializedCheckValidatorData, body); }
public async Task WaitsForValidationSetAvailabilityInValidationDBWithCheckValidator() { var messageData = PackageValidationMessageData.NewCheckValidator(Guid.NewGuid()); var validationConfiguration = new ValidationConfiguration(); ValidationSetProviderMock .Setup(ps => ps.TryGetParentValidationSetAsync(messageData.CheckValidator.ValidationId)) .ReturnsAsync((PackageValidationSet)null) .Verifiable(); var handler = CreateHandler(); var result = await handler.HandleAsync(messageData); ValidationSetProviderMock.Verify( ps => ps.TryGetParentValidationSetAsync(messageData.CheckValidator.ValidationId), Times.Once); Assert.False(result, "The handler should not have succeeded."); }
public async Task RejectsNonSymbolPackageValidationSetWithCheckValidator() { var messageData = PackageValidationMessageData.NewCheckValidator(Guid.NewGuid()); var validationConfiguration = new ValidationConfiguration(); var validationSet = new PackageValidationSet { PackageKey = 42, ValidatingType = ValidatingType.Package }; ValidationSetProviderMock .Setup(ps => ps.TryGetParentValidationSetAsync(messageData.CheckValidator.ValidationId)) .ReturnsAsync(validationSet) .Verifiable(); var handler = CreateHandler(); var result = await handler.HandleAsync(messageData); ValidationSetProviderMock.Verify( ps => ps.TryGetParentValidationSetAsync(messageData.CheckValidator.ValidationId), Times.Once); Assert.False(result, "The handler should not have succeeded."); }
private async Task <bool> HandleAsync(SignatureValidationMessage message, CancellationToken cancellationToken) { using (_logger.BeginScope("Handling signature validation message for package {PackageId} {PackageVersion}, validation {ValidationId}", message.PackageId, message.PackageVersion, message.ValidationId)) { // Find the signature validation entity that matches this message. var validation = await _validatorStateService.GetStatusAsync(message.ValidationId); // A signature validation should be queued with ValidatorState == Incomplete. if (validation == null) { _logger.LogInformation( "Could not find validation entity, requeueing (package: {PackageId} {PackageVersion}, validationId: {ValidationId})", message.PackageId, message.PackageVersion, message.ValidationId); // Message may be retried. return(false); } else if (validation.State == ValidationStatus.NotStarted) { _logger.LogWarning( "Unexpected signature verification status '{ValidatorState}' when 'Incomplete' was expected, requeueing (package id: {PackageId} package version: {PackageVersion} validation id: {ValidationId})", validation.State, message.PackageId, message.PackageVersion, message.ValidationId); // Message may be retried. return(false); } else if (validation.State != ValidationStatus.Incomplete) { _logger.LogWarning( "Terminal signature verification status '{ValidatorState}' when 'Incomplete' was expected, dropping message (package id: {PackageId} package version: {PackageVersion} validation id: {ValidationId})", validation.State, message.PackageId, message.PackageVersion, message.ValidationId); // Consume the message. return(true); } // Validate package using (var packageStream = await _packageDownloader.DownloadAsync(message.NupkgUri, cancellationToken)) { var result = await _signatureValidator.ValidateAsync( validation.PackageKey, packageStream, message, cancellationToken); validation.State = result.State; // Save any issues if the resulting state is terminal. if (validation.State == ValidationStatus.Failed || validation.State == ValidationStatus.Succeeded) { validation.ValidatorIssues = validation.ValidatorIssues ?? new List <ValidatorIssue>(); foreach (var issue in result.Issues) { validation.ValidatorIssues.Add(new ValidatorIssue { IssueCode = issue.IssueCode, Data = issue.Serialize(), }); } } // Save the .nupkg URL if the resulting state is successful. if (validation.State == ValidationStatus.Succeeded && result.NupkgUri != null) { validation.NupkgUrl = result.NupkgUri.AbsoluteUri; } } // The signature validator should do all of the work to bring this validation to its completion. if (validation.State != ValidationStatus.Succeeded && validation.State != ValidationStatus.Failed) { _logger.LogError("The signature validator should have set the status 'Succeeded' or 'Failed', not " + "'{ValidatorState}' (package id: {PackageId} package version: {PackageVersion} validation id: {ValidationId})", validation.State, message.PackageId, message.PackageVersion, message.ValidationId); return(false); } // Save the resulting validation status. var completed = await SaveStatusAsync(validation, message); if (completed && _featureFlagService.IsQueueBackEnabled()) { _logger.LogInformation("Sending queue-back message for validation {ValidationId}.", message.ValidationId); var messageData = PackageValidationMessageData.NewCheckValidator(message.ValidationId); await _validationEnqueuer.SendMessageAsync(messageData); } return(completed); } }
/// <summary> /// Perform the certificate validation request, including online revocation checks. /// </summary> /// <param name="message">The message requesting the certificate validation.</param> /// <returns>Whether the validation completed. If false, the validation should be retried later.</returns> public async Task <bool> HandleAsync(CertificateValidationMessage message) { using (_logger.BeginScope("Handling validate certificate message {CertificateKey} {ValidationId}", message.CertificateKey, message.ValidationId)) { var validation = await _certificateValidationService.FindCertificateValidationAsync(message); if (validation == null) { _logger.LogInformation( "Could not find a certificate validation entity, failing (certificate: {CertificateKey} validation: {ValidationId})", message.CertificateKey, message.ValidationId); return(false); } if (validation.Status != null) { // A certificate validation should be queued with a Status of null, and once the certificate validation // completes, the Status should be updated to a non-null value. Hence, the Status here SHOULD be null. // A non-null Status may indicate message duplication. _logger.LogWarning( "Invalid certificate validation entity's status, dropping message (certificate: {CertificateThumbprint} validation: {ValidationId})", validation.EndCertificate.Thumbprint, validation.ValidationId); return(true); } if (validation.EndCertificate.Status == EndCertificateStatus.Revoked) { if (message.RevalidateRevokedCertificate) { _logger.LogWarning( "Revalidating certificate that is known to be revoked " + "(certificate: {CertificateThumbprint} validation: {ValidationId})", validation.EndCertificate.Thumbprint, validation.ValidationId); } else { // Do NOT revalidate a certificate that is known to be revoked unless explicitly told to! // Certificate Authorities are not required to keep a certificate's revocation information // forever, therefore, revoked certificates should only be revalidated in special cases. _logger.LogError( "Certificate known to be revoked MUST be validated with the " + $"{nameof(CertificateValidationMessage.RevalidateRevokedCertificate)} flag enabled " + "(certificate: {CertificateThumbprint} validation: {ValidationId})", validation.EndCertificate.Thumbprint, validation.ValidationId); return(true); } } CertificateVerificationResult result; using (var certificates = await LoadCertificatesAsync(validation)) { switch (validation.EndCertificate.Use) { case EndCertificateUse.CodeSigning: result = _certificateVerifier.VerifyCodeSigningCertificate( certificates.EndCertificate, certificates.AncestorCertificates); break; case EndCertificateUse.Timestamping: result = _certificateVerifier.VerifyTimestampingCertificate( certificates.EndCertificate, certificates.AncestorCertificates); break; default: throw new InvalidOperationException($"Unknown {nameof(EndCertificateUse)}: {validation.EndCertificate.Use}"); } } // Save the result. This may alert if packages are invalidated. if (!await _certificateValidationService.TrySaveResultAsync(validation, result)) { _logger.LogWarning( "Failed to save certificate validation result " + "(certificate: {CertificateThumbprint} validation: {ValidationId}), " + "retrying validation...", validation.EndCertificate.Thumbprint, validation.ValidationId); return(false); } var completed = HasValidationCompleted(validation, result); if (completed && message.SendCheckValidator && _featureFlagService.IsQueueBackEnabled()) { _logger.LogInformation("Sending queue-back message for validation {ValidationId}.", message.ValidationId); var messageData = PackageValidationMessageData.NewCheckValidator(message.ValidationId); await _validationEnqueuer.SendMessageAsync(messageData); } return(completed); } }
public async Task <bool> HandleAsync(SymbolsValidatorMessage message) { using (_logger.BeginScope("{ValidatorName}: Handling message for {PackageId} {PackageVersion} validation set {ValidationId}", ValidatorName.SymbolsValidator, message.PackageId, message.PackageNormalizedVersion, message.ValidationId)) { if (message == null) { throw new ArgumentNullException(nameof(message)); } var validation = await _validatorStateService.GetStatusAsync(message.ValidationId); // A validation should be queued with ValidatorState == Incomplete. if (validation == null) { _logger.LogInformation( "{ValidatorName} : Could not find validation entity, requeueing (package: {PackageId} {PackageVersion}, validationId: {ValidationId})", ValidatorName.SymbolsValidator, message.PackageId, message.PackageNormalizedVersion, message.ValidationId); // Message may be retried. return(false); } else if (validation.State == ValidationStatus.NotStarted) { _logger.LogWarning( "{ValidatorName}:Unexpected status '{ValidatorState}' when 'Incomplete' was expected, requeueing package id: {PackageId} package version: {PackageVersion} validation id: {ValidationId})", ValidatorName.SymbolsValidator, validation.State, message.PackageId, message.PackageNormalizedVersion, message.ValidationId); // Message may be retried. return(false); } // Final states else if (validation.State == ValidationStatus.Failed || validation.State == ValidationStatus.Succeeded) { _logger.LogWarning( "{ValidatorName}:Terminal symbol verification status '{ValidatorState}' when 'Incomplete' was expected, dropping message (package id: {PackageId} package version: {PackageVersion} validation id: {ValidationId})", ValidatorName.SymbolsValidator, validation.State, message.PackageId, message.PackageNormalizedVersion, message.ValidationId); // Consume the message. return(true); } var validationResult = await _symbolValidatorService.ValidateSymbolsAsync(message, CancellationToken.None); if (validationResult.Status == ValidationStatus.Failed || validationResult.Status == ValidationStatus.Succeeded) { validation.State = validationResult.Status; validation.ValidatorIssues = validation.ValidatorIssues ?? new List <ValidatorIssue>(); foreach (var issue in validationResult.Issues) { validation.ValidatorIssues.Add(new ValidatorIssue { IssueCode = issue.IssueCode, Data = issue.Serialize(), }); } if (validationResult.NupkgUrl != null) { validation.NupkgUrl = validationResult.NupkgUrl; } var completed = await SaveStatusAsync(validation, message, MaxDBSaveRetry); if (completed && _featureFlagService.IsQueueBackEnabled()) { _logger.LogInformation("Sending queue-back message for validation {ValidationId}.", message.ValidationId); var messageData = PackageValidationMessageData.NewCheckValidator(message.ValidationId); await _validationEnqueuer.SendMessageAsync(messageData); } return(completed); } _logger.LogWarning( "{ValidatorName}:The validation did not return a complete status for package {PackageId} {PackageVersion} for validation id: {ValidationId} .", ValidatorName.SymbolsValidator, message.PackageId, message.PackageNormalizedVersion, message.ValidationId); return(false); } }