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

Commit b2334fd

Browse files
authored
[Repository Signing] Don't repository sign package if owner(s) have malformed username (#498)
Fixes https://github.com/NuGet/Engineering/issues/1572
1 parent f18edac commit b2334fd

2 files changed

Lines changed: 67 additions & 7 deletions

File tree

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

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@
55
using System.Collections.Generic;
66
using System.Data.Entity;
77
using System.Linq;
8+
using System.Text.RegularExpressions;
89
using System.Threading.Tasks;
910
using Microsoft.Extensions.Logging;
1011
using Microsoft.Extensions.Options;
1112
using NuGet.Jobs.Validation;
12-
using NuGet.Jobs.Validation.Storage;
1313
using NuGet.Jobs.Validation.ScanAndSign;
14+
using NuGet.Jobs.Validation.Storage;
1415
using NuGet.Services.Validation.Vcs;
1516
using NuGetGallery;
1617

@@ -19,6 +20,8 @@ namespace NuGet.Services.Validation.Orchestrator.PackageSigning.ScanAndSign
1920
[ValidatorName(ValidatorName.ScanAndSign)]
2021
public class ScanAndSignProcessor : IProcessor
2122
{
23+
private const string UsernameRegex = @"^[A-Za-z0-9][A-Za-z0-9_\.-]+[A-Za-z0-9]$";
24+
2225
private readonly IValidationEntitiesContext _validationContext;
2326
private readonly IValidatorStateService _validatorStateService;
2427
private readonly ICorePackageService _packageService;
@@ -131,10 +134,10 @@ public async Task<IValidationResult> StartAsync(IValidationRequest request)
131134
return processorStatus.ToValidationResult();
132135
}
133136

134-
if (await ShouldRepositorySignAsync(request))
135-
{
136-
var owners = FindPackageOwners(request);
137+
var owners = FindPackageOwners(request);
137138

139+
if (await ShouldRepositorySignAsync(request, owners))
140+
{
138141
_logger.LogInformation(
139142
"Repository signing {PackageId} {PackageVersion} with {ServiceIndex} and {Owners}",
140143
request.PackageId,
@@ -197,7 +200,7 @@ private bool ShouldSkipScan(IValidationRequest request)
197200
return false;
198201
}
199202

200-
private async Task<bool> ShouldRepositorySignAsync(IValidationRequest request)
203+
private async Task<bool> ShouldRepositorySignAsync(IValidationRequest request, List<string> owners)
201204
{
202205
var hasRepositorySignature = await _validationContext
203206
.PackageSignatures
@@ -215,7 +218,18 @@ private async Task<bool> ShouldRepositorySignAsync(IValidationRequest request)
215218
return false;
216219
}
217220

218-
return true;
221+
if (owners.Any(IsInvalidUsername))
222+
{
223+
_logger.LogWarning(
224+
"Package {PackageId} {PackageVersion} has an owner with an invalid username. Scanning instead of signing. {Owners}",
225+
request.PackageId,
226+
request.PackageVersion,
227+
owners);
228+
229+
return false;
230+
}
231+
232+
return true;
219233
}
220234

221235
private List<string> FindPackageOwners(IValidationRequest request)
@@ -234,5 +248,10 @@ private List<string> FindPackageOwners(IValidationRequest request)
234248
.Select(o => o.Username)
235249
.ToList();
236250
}
251+
252+
private bool IsInvalidUsername(string username)
253+
{
254+
return !Regex.IsMatch(username, UsernameRegex, RegexOptions.None, TimeSpan.FromSeconds(5));
255+
}
237256
}
238257
}

tests/Validation.PackageSigning.ScanAndSign.Tests/ScanAndSignProcessorFacts.cs

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,30 @@ public async Task EnqueuesScanAndSignIfPackageHasNoRepositorySignature()
262262
.Verify(v => v.TryAddValidatorStatusAsync(It.IsAny<IValidationRequest>(), It.IsAny<ValidatorStatus>(), It.IsAny<ValidationStatus>()), Times.Once);
263263
}
264264

265+
[Fact]
266+
public async Task WhenUsernameInvalid_SkipsScanAndSign()
267+
{
268+
_config.RepositorySigningEnabled = true;
269+
270+
_validationContext.Mock();
271+
_packageServiceMock
272+
.Setup(p => p.FindPackageRegistrationById(_request.PackageId))
273+
.Returns(_packageRegistrationWithInvalidUser);
274+
275+
var result = await _target.StartAsync(_request);
276+
277+
_packageServiceMock
278+
.Verify(p => p.FindPackageRegistrationById(_request.PackageId), Times.Once);
279+
280+
_enqueuerMock
281+
.Verify(e => e.EnqueueScanAsync(_request.ValidationId, _request.NupkgUrl), Times.Once);
282+
283+
_validatorStateServiceMock
284+
.Verify(v => v.TryAddValidatorStatusAsync(_request, _status, ValidationStatus.Incomplete), Times.Once);
285+
_validatorStateServiceMock
286+
.Verify(v => v.TryAddValidatorStatusAsync(It.IsAny<IValidationRequest>(), It.IsAny<ValidatorStatus>(), It.IsAny<ValidationStatus>()), Times.Once);
287+
}
288+
265289
[Fact]
266290
public async Task EnqueuesScanAndSignEvenIfRepositorySigningIsDisabled()
267291
{
@@ -336,10 +360,14 @@ public async Task EnqueuesScanIfPackageHasARepositorySignature()
336360
}
337361
});
338362

363+
_packageServiceMock
364+
.Setup(p => p.FindPackageRegistrationById(_request.PackageId))
365+
.Returns(_packageRegistration);
366+
339367
var result = await _target.StartAsync(_request);
340368

341369
_packageServiceMock
342-
.Verify(p => p.FindPackageRegistrationById(It.IsAny<string>()), Times.Never);
370+
.Verify(p => p.FindPackageRegistrationById(It.IsAny<string>()), Times.Once);
343371

344372
_enqueuerMock
345373
.Verify(e => e.EnqueueScanAsync(_request.ValidationId, _request.NupkgUrl), Times.Once);
@@ -361,6 +389,10 @@ public async Task WhenPackageIsRepositorySigned_SkipsCheckWhenPackageFitsCriteri
361389
}
362390
});
363391

392+
_packageServiceMock
393+
.Setup(p => p.FindPackageRegistrationById(_request.PackageId))
394+
.Returns(_packageRegistration);
395+
364396
_criteriaEvaluatorMock
365397
.Setup(ce => ce.IsMatch(It.IsAny<ICriteria>(), It.IsAny<Package>()))
366398
.Returns(false);
@@ -414,6 +446,15 @@ public async Task WhenPackageFitsCriteriaAndIsNotRepositorySigned_DoesNotSkipSca
414446
}
415447
};
416448

449+
private PackageRegistration _packageRegistrationWithInvalidUser = new PackageRegistration
450+
{
451+
Owners = new List<User>
452+
{
453+
new User("Billy"),
454+
new User("Satan Claus"),
455+
}
456+
};
457+
417458
public TheStartAsyncMethod()
418459
{
419460
_request = new ValidationRequest(Guid.NewGuid(), 42, "somepackage", "somversion", "https://example.com/package.nupkg");

0 commit comments

Comments
 (0)