private async Task SetValidationStatusAsync(
            PackageValidation packageValidation,
            INuGetValidationResponse validationResponse,
            DateTime now)
        {
            if (validationResponse.Status != ValidationStatus.Incomplete)
            {
                AddValidationIssues(packageValidation, validationResponse.Issues);
            }

            if (validationResponse.Status == ValidationStatus.Succeeded &&
                validationResponse.NupkgUrl != null)
            {
                if (!_validatorProvider.IsNuGetProcessor(packageValidation.Type))
                {
                    throw new InvalidOperationException(
                              $"The validator '{packageValidation.Type}' is not a processor but returned a .nupkg URL as " +
                              $"part of the validation step response.");
                }

                await _packageFileService.CopyPackageUrlForValidationSetAsync(
                    packageValidation.PackageValidationSet,
                    validationResponse.NupkgUrl);
            }

            packageValidation.ValidationStatus          = validationResponse.Status;
            packageValidation.ValidationStatusTimestamp = now;
            await _validationContext.SaveChangesAsync();

            TrackValidationStatus(packageValidation);
        }
        private INuGetValidationResponse Validate(INuGetValidationRequest request, INuGetValidationResponse response)
        {
            /// The package signature validator runs after the <see cref="PackageSignatureProcessor" />.
            /// All signature validation issues should be caught and handled by the processor.
            if (response.Status == ValidationStatus.Failed || response.NupkgUrl != null)
            {
                if (!_config.RepositorySigningEnabled)
                {
                    _logger.LogInformation(
                        "Ignoring invalid validation response in package signature validator as repository signing is disabled. " +
                        "Status = {ValidationStatus}, Nupkg URL = {NupkgUrl}, validation issues = {Issues}",
                        response.Status,
                        response.NupkgUrl,
                        response.Issues.Select(i => i.IssueCode));

                    return(NuGetValidationResponse.Succeeded);
                }

                _logger.LogCritical(
                    "Unexpected validation response in package signature validator. This may be caused by an invalid repository " +
                    "signature. Throwing an exception to force this validation to dead-letter. " +
                    "Status = {ValidationStatus}, Nupkg URL = {NupkgUrl}, validation issues = {Issues}",
                    response.Status,
                    response.NupkgUrl,
                    response.Issues.Select(i => i.IssueCode));

                throw new InvalidOperationException("Package signature validator has an unexpected validation response");
            }

            /// Suppress all validation issues. The <see cref="PackageSignatureProcessor"/> should
            /// have already reported any issues related to the author signature. Customers should
            /// not be notified of validation issues due to the repository signature.
            if (response.Issues.Count != 0)
            {
                _logger.LogWarning(
                    "Ignoring {ValidationIssueCount} validation issues from response. Issues: {Issues}",
                    response.Issues.Count,
                    response.Issues.Select(i => i.IssueCode));

                return(new NuGetValidationResponse(response.Status));
            }

            return(response);
        }
        public async Task MarkValidationStartedAsync(PackageValidation packageValidation, INuGetValidationResponse validationResponse)
        {
            packageValidation = packageValidation ?? throw new ArgumentNullException(nameof(packageValidation));

            _logger.LogInformation("Marking validation {ValidationName} {ValidationId} {PackageId} {PackageVersion} as started with status {ValidationStatus}",
                                   packageValidation.Type,
                                   packageValidation.PackageValidationSet.ValidationTrackingId,
                                   packageValidation.PackageValidationSet.PackageId,
                                   packageValidation.PackageValidationSet.PackageNormalizedVersion,
                                   validationResponse.Status);

            if (validationResponse.Status == ValidationStatus.NotStarted)
            {
                throw new ArgumentOutOfRangeException(
                          nameof(validationResponse),
                          $"Cannot mark validation {packageValidation.Type} for " +
                          $"{packageValidation.PackageValidationSet.PackageId} " +
                          $"{packageValidation.PackageValidationSet.PackageNormalizedVersion} as started " +
                          $"with status {ValidationStatus.NotStarted}");
            }

            var now = DateTime.UtcNow;

            packageValidation.Started = now;

            await SetValidationStatusAsync(packageValidation, validationResponse, now);
        }
        public async Task UpdateValidationStatusAsync(PackageValidation packageValidation, INuGetValidationResponse validationResponse)
        {
            packageValidation = packageValidation ?? throw new ArgumentNullException(nameof(packageValidation));

            if (packageValidation.ValidationStatus == validationResponse.Status)
            {
                _logger.LogInformation("Validation {ValidationName} {ValidationId} {PackageId} {PackageVersion} already has status {ValidationStatus}",
                                       packageValidation.Type,
                                       packageValidation.PackageValidationSet.ValidationTrackingId,
                                       packageValidation.PackageValidationSet.PackageId,
                                       packageValidation.PackageValidationSet.PackageNormalizedVersion,
                                       validationResponse.Status);

                return;
            }

            _logger.LogInformation("Updating the status of the validation {ValidationName} {ValidationId} {PackageId} {PackageVersion} to {ValidationStatus}",
                                   packageValidation.Type,
                                   packageValidation.PackageValidationSet.ValidationTrackingId,
                                   packageValidation.PackageValidationSet.PackageId,
                                   packageValidation.PackageValidationSet.PackageNormalizedVersion,
                                   validationResponse.Status);

            await SetValidationStatusAsync(packageValidation, validationResponse, DateTime.UtcNow);
        }
示例#5
0
        private bool IsChecksumMatch(string peFilePath, string packageId, string packageNormalizedVersion, out INuGetValidationResponse validationResponse)
        {
            validationResponse = NuGetValidationResponse.Succeeded;
            using (var peStream = File.OpenRead(peFilePath))
                using (var peReader = new PEReader(peStream))
                {
                    // This checks if portable PDB is associated with the PE file and opens it for reading.
                    // It also validates that it matches the PE file.
                    // It does not validate that the checksum matches, so we need to do that in the following block.
                    if (peReader.TryOpenAssociatedPortablePdb(peFilePath, File.OpenRead, out var pdbReaderProvider, out var pdbPath) &&
                        // No need to validate embedded PDB (pdbPath == null for embedded)
                        pdbPath != null)
                    {
                        // Get all checksum entries. There can be more than one. At least one must match the PDB.
                        var checksumRecords = peReader.ReadDebugDirectory().Where(entry => entry.Type == DebugDirectoryEntryType.PdbChecksum)
                                              .Select(e => peReader.ReadPdbChecksumDebugDirectoryData(e))
                                              .ToArray();

                        if (checksumRecords.Length == 0)
                        {
                            _telemetryService.TrackSymbolsAssemblyValidationResultEvent(packageId, packageNormalizedVersion, ValidationStatus.Failed, nameof(ValidationIssue.SymbolErrorCode_ChecksumDoesNotMatch), assemblyName: Path.GetFileName(peFilePath));
                            validationResponse = NuGetValidationResponse.FailedWithIssues(ValidationIssue.SymbolErrorCode_ChecksumDoesNotMatch);
                            return(false);
                        }

                        var pdbBytes = File.ReadAllBytes(pdbPath);
                        var hashes   = new Dictionary <string, byte[]>();

                        using (pdbReaderProvider)
                        {
                            var pdbReader = pdbReaderProvider.GetMetadataReader();
                            int idOffset  = pdbReader.DebugMetadataHeader.IdStartOffset;

                            foreach (var checksumRecord in checksumRecords)
                            {
                                if (!hashes.TryGetValue(checksumRecord.AlgorithmName, out var hash))
                                {
                                    HashAlgorithmName han = new HashAlgorithmName(checksumRecord.AlgorithmName);
                                    using (var hashAlg = IncrementalHash.CreateHash(han))
                                    {
                                        hashAlg.AppendData(pdbBytes, 0, idOffset);
                                        hashAlg.AppendData(new byte[20]);
                                        int offset = idOffset + 20;
                                        int count  = pdbBytes.Length - offset;
                                        hashAlg.AppendData(pdbBytes, offset, count);
                                        hash = hashAlg.GetHashAndReset();
                                    }
                                    hashes.Add(checksumRecord.AlgorithmName, hash);
                                }
                                if (checksumRecord.Checksum.ToArray().SequenceEqual(hash))
                                {
                                    // found the right checksum
                                    _telemetryService.TrackSymbolsAssemblyValidationResultEvent(packageId, packageNormalizedVersion, ValidationStatus.Succeeded, issue: "", assemblyName: Path.GetFileName(peFilePath));
                                    return(true);
                                }
                            }

                            // Not found any checksum record that matches the PDB.
                            _telemetryService.TrackSymbolsAssemblyValidationResultEvent(packageId, packageNormalizedVersion, ValidationStatus.Failed, nameof(ValidationIssue.SymbolErrorCode_ChecksumDoesNotMatch), assemblyName: Path.GetFileName(peFilePath));
                            validationResponse = NuGetValidationResponse.FailedWithIssues(ValidationIssue.SymbolErrorCode_ChecksumDoesNotMatch);
                            return(false);
                        }
                    }
                }
            _telemetryService.TrackSymbolsAssemblyValidationResultEvent(packageId, packageNormalizedVersion, ValidationStatus.Failed, nameof(ValidationIssue.SymbolErrorCode_MatchingAssemblyNotFound), assemblyName: Path.GetFileName(peFilePath));
            validationResponse = NuGetValidationResponse.FailedWithIssues(ValidationIssue.SymbolErrorCode_MatchingAssemblyNotFound);
            return(false);
        }
示例#6
0
 protected override async Task ExecuteAsync(INuGetValidationResponse validationResponse)
 {
     await _target.MarkValidationStartedAsync(_packageValidation, validationResponse);
 }
示例#7
0
 protected override async Task ExecuteAsync(INuGetValidationResponse response)
 {
     await _target.UpdateValidationStatusAsync(_packageValidation, response);
 }
示例#8
0
 protected abstract Task ExecuteAsync(INuGetValidationResponse validationResponse);