Skip to content
This repository was archived by the owner on Jul 30, 2024. It is now read-only.

Commit 5e13e86

Browse files
authored
Repository sign packages at ingestion (#452)
Addresses https://github.com/NuGet/Engineering/issues/1328
1 parent afe77ed commit 5e13e86

17 files changed

Lines changed: 789 additions & 281 deletions

File tree

src/NuGet.Services.Validation.Orchestrator/PackageSigning/ProcessSignature/PackageSignatureValidator.cs

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55
using System.Linq;
66
using System.Threading.Tasks;
77
using Microsoft.Extensions.Logging;
8+
using Microsoft.Extensions.Options;
89
using NuGet.Jobs.Validation;
910
using NuGet.Jobs.Validation.PackageSigning.Storage;
1011
using NuGet.Jobs.Validation.Storage;
12+
using NuGet.Services.Validation.Orchestrator.PackageSigning.ScanAndSign;
1113
using NuGet.Services.Validation.Orchestrator.Telemetry;
1214

1315
namespace NuGet.Services.Validation.PackageSigning.ProcessSignature
@@ -22,13 +24,15 @@ public class PackageSignatureValidator : BaseSignatureProcessor, IValidator
2224
private readonly IValidatorStateService _validatorStateService;
2325
private readonly IProcessSignatureEnqueuer _signatureVerificationEnqueuer;
2426
private readonly ISimpleCloudBlobProvider _blobProvider;
27+
private readonly ScanAndSignConfiguration _config;
2528
private readonly ITelemetryService _telemetryService;
2629
private readonly ILogger<PackageSignatureValidator> _logger;
2730

2831
public PackageSignatureValidator(
2932
IValidatorStateService validatorStateService,
3033
IProcessSignatureEnqueuer signatureVerificationEnqueuer,
3134
ISimpleCloudBlobProvider blobProvider,
35+
IOptionsSnapshot<ScanAndSignConfiguration> configAccessor,
3236
ITelemetryService telemetryService,
3337
ILogger<PackageSignatureValidator> logger)
3438
: base(validatorStateService, signatureVerificationEnqueuer, blobProvider, telemetryService, logger)
@@ -38,6 +42,13 @@ public PackageSignatureValidator(
3842
_blobProvider = blobProvider ?? throw new ArgumentNullException(nameof(blobProvider));
3943
_telemetryService = telemetryService ?? throw new ArgumentNullException(nameof(telemetryService));
4044
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
45+
46+
if (configAccessor?.Value == null)
47+
{
48+
throw new ArgumentException($"{nameof(ScanAndSignConfiguration)} is required", nameof(configAccessor));
49+
}
50+
51+
_config = configAccessor.Value;
4152
}
4253

4354
/// <summary>
@@ -66,14 +77,29 @@ private IValidationResult Validate(IValidationResult result)
6677
/// All signature validation issues should be caught and handled by the processor.
6778
if (result.Status == ValidationStatus.Failed || result.NupkgUrl != null)
6879
{
69-
_logger.LogCritical(
70-
"Unexpected validation result in package signature validator. This may be caused by an invalid repository " +
71-
"signature. Status = {ValidationStatus}, Nupkg URL = {NupkgUrl}, validation issues = {Issues}",
72-
result.Status,
73-
result.NupkgUrl,
74-
result.Issues.Select(i => i.IssueCode));
80+
if (_config.RepositorySigningEnabled)
81+
{
82+
_logger.LogCritical(
83+
"Unexpected validation result in package signature validator. This may be caused by an invalid repository " +
84+
"signature. Throwing an exception to force this validation to dead-letter. " +
85+
"Status = {ValidationStatus}, Nupkg URL = {NupkgUrl}, validation issues = {Issues}",
86+
result.Status,
87+
result.NupkgUrl,
88+
result.Issues.Select(i => i.IssueCode));
89+
90+
throw new InvalidOperationException("Package signature validator has an unexpected validation result");
91+
}
92+
else
93+
{
94+
_logger.LogInformation(
95+
"Ignoring invalid validation result in package signature validator as repository signing is disabled. " +
96+
"Status = {ValidationStatus}, Nupkg URL = {NupkgUrl}, validation issues = {Issues}",
97+
result.Status,
98+
result.NupkgUrl,
99+
result.Issues.Select(i => i.IssueCode));
75100

76-
throw new InvalidOperationException("Package signature validator has an unexpected validation result");
101+
return ValidationResult.Succeeded;
102+
}
77103
}
78104

79105
/// Suppress all validation issues. The <see cref="PackageSignatureProcessor"/> should

src/NuGet.Services.Validation.Orchestrator/PackageSigning/ScanAndSign/IScanAndSignEnqueuer.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4+
using System.Collections.Generic;
45
using System.Threading.Tasks;
5-
using NuGet.Jobs.Validation.ScanAndSign;
66

77
namespace NuGet.Services.Validation.Orchestrator.PackageSigning.ScanAndSign
88
{
@@ -13,5 +13,13 @@ public interface IScanAndSignEnqueuer
1313
/// </summary>
1414
/// <param name="request">Request data</param>
1515
Task EnqueueScanAsync(IValidationRequest request);
16+
17+
/// <summary>
18+
/// Enqueues Scan And Sign operation.
19+
/// </summary>
20+
/// <param name="request">The requested package validation.</param>
21+
/// <param name="v3ServiceIndexUrl">The service index URL that should be put on the package's repository signature.</param>
22+
/// <param name="owners">The list of owners that should be put on the package's repository signature.</param>
23+
Task EnqueueScanAndSignAsync(IValidationRequest request, string v3ServiceIndexUrl, List<string> owners);
1624
}
1725
}

src/NuGet.Services.Validation.Orchestrator/PackageSigning/ScanAndSign/ScanAndSignConfiguration.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,18 @@ public class ScanAndSignConfiguration
2020
public TimeSpan? MessageDelay { get; set; }
2121

2222
/// <summary>
23-
/// The criteria used to determine if a package should be submitted scanning.
23+
/// The criteria used to determine whether a package should be scanned.
2424
/// </summary>
2525
public PackageCriteria PackageCriteria { get; set; } = new PackageCriteria();
26+
27+
/// <summary>
28+
/// If true, packages with no repository signatures will be repository signed.
29+
/// </summary>
30+
public bool RepositorySigningEnabled { get; set; }
31+
32+
/// <summary>
33+
/// The service index URL that should be stamped on repository signatures.
34+
/// </summary>
35+
public string V3ServiceIndexUrl { get; set; }
2636
}
2737
}

src/NuGet.Services.Validation.Orchestrator/PackageSigning/ScanAndSign/ScanAndSignEnqueuer.cs

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
5+
using System.Collections.Generic;
56
using System.Threading.Tasks;
7+
using Microsoft.Extensions.Logging;
68
using Microsoft.Extensions.Options;
79
using NuGet.Jobs.Validation.ScanAndSign;
810
using NuGet.Services.ServiceBus;
@@ -14,14 +16,18 @@ public class ScanAndSignEnqueuer : IScanAndSignEnqueuer
1416
private readonly ITopicClient _topicClient;
1517
private readonly IBrokeredMessageSerializer<ScanAndSignMessage> _serializer;
1618
private readonly ScanAndSignConfiguration _configuration;
19+
private readonly ILogger<IScanAndSignEnqueuer> _logger;
1720

1821
public ScanAndSignEnqueuer(
1922
ITopicClient topicClient,
2023
IBrokeredMessageSerializer<ScanAndSignMessage> serializer,
21-
IOptionsSnapshot<ScanAndSignConfiguration> configurationAccessor)
24+
IOptionsSnapshot<ScanAndSignConfiguration> configurationAccessor,
25+
ILogger<IScanAndSignEnqueuer> logger)
2226
{
2327
_topicClient = topicClient ?? throw new ArgumentNullException(nameof(topicClient));
2428
_serializer = serializer ?? throw new ArgumentNullException(nameof(serializer));
29+
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
30+
2531
if (configurationAccessor == null)
2632
{
2733
throw new ArgumentNullException(nameof(configurationAccessor));
@@ -40,10 +46,41 @@ public Task EnqueueScanAsync(IValidationRequest request)
4046
throw new ArgumentNullException(nameof(request));
4147
}
4248

43-
var message = new ScanAndSignMessage(
44-
OperationRequestType.Scan,
45-
request.ValidationId,
46-
new Uri(request.NupkgUrl));
49+
return SendScanAndSignMessageAsync(
50+
new ScanAndSignMessage(
51+
OperationRequestType.Scan,
52+
request.ValidationId,
53+
new Uri(request.NupkgUrl)));
54+
}
55+
56+
public Task EnqueueScanAndSignAsync(IValidationRequest request, string v3ServiceIndexUrl, List<string> owners)
57+
{
58+
if (request == null) throw new ArgumentNullException(nameof(request));
59+
if (owners == null) throw new ArgumentNullException(nameof(owners));
60+
61+
if (string.IsNullOrEmpty(v3ServiceIndexUrl))
62+
{
63+
throw new ArgumentException("The service index URL parameter is required", nameof(v3ServiceIndexUrl));
64+
}
65+
66+
_logger.LogInformation(
67+
"Requested scan and sign for package {PackageId} {PackageVersion} using service index {ServiceIndex} and owners {Owners}",
68+
request.PackageId,
69+
request.PackageVersion,
70+
v3ServiceIndexUrl,
71+
owners);
72+
73+
return SendScanAndSignMessageAsync(
74+
new ScanAndSignMessage(
75+
OperationRequestType.Sign,
76+
request.ValidationId,
77+
new Uri(request.NupkgUrl),
78+
v3ServiceIndexUrl,
79+
owners));
80+
}
81+
82+
private Task SendScanAndSignMessageAsync(ScanAndSignMessage message)
83+
{
4784
var brokeredMessage = _serializer.Serialize(message);
4885

4986
var visibleAt = DateTimeOffset.UtcNow + (_configuration.MessageDelay ?? TimeSpan.Zero);

0 commit comments

Comments
 (0)