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

Commit 6694d3b

Browse files
committed
Add telemetry to track stripped repository signatures (#392)
Progress on NuGet/Engineering#1207
1 parent fa031ef commit 6694d3b

9 files changed

Lines changed: 314 additions & 2 deletions

File tree

src/Validation.PackageSigning.ProcessSignature/Job.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using NuGet.Jobs.Validation.PackageSigning.Configuration;
1212
using NuGet.Jobs.Validation.PackageSigning.Messages;
1313
using NuGet.Jobs.Validation.PackageSigning.Storage;
14+
using NuGet.Jobs.Validation.PackageSigning.Telemetry;
1415
using NuGet.Jobs.Validation.Storage;
1516
using NuGet.Services.ServiceBus;
1617
using NuGet.Services.Storage;
@@ -31,6 +32,8 @@ protected override void ConfigureJobServices(IServiceCollection services, IConfi
3132

3233
services.AddTransient<IEntityRepository<Certificate>, EntityRepository<Certificate>>();
3334

35+
services.AddTransient<ITelemetryService, TelemetryService>();
36+
3437
services.AddTransient<ICertificateStore>(p =>
3538
{
3639
var config = p.GetRequiredService<IOptionsSnapshot<CertificateStoreConfiguration>>().Value;
@@ -59,6 +62,7 @@ protected override void ConfigureJobServices(IServiceCollection services, IConfi
5962
p.GetRequiredService<ISignaturePartsExtractor>(),
6063
p.GetRequiredService<IProcessorPackageFileService>(),
6164
p.GetRequiredService<IEntityRepository<Certificate>>(),
65+
p.GetRequiredService<ITelemetryService>(),
6266
p.GetRequiredService<ILogger<SignatureValidator>>()));
6367
}
6468

src/Validation.PackageSigning.ProcessSignature/SignatureValidator.cs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
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.Diagnostics;
56
using System.IO;
67
using System.Linq;
78
using System.Security.Cryptography.Pkcs;
@@ -12,6 +13,7 @@
1213
using NuGet.Common;
1314
using NuGet.Jobs.Validation.PackageSigning.Messages;
1415
using NuGet.Jobs.Validation.PackageSigning.Storage;
16+
using NuGet.Jobs.Validation.PackageSigning.Telemetry;
1517
using NuGet.Jobs.Validation.Storage;
1618
using NuGet.Packaging.Signing;
1719
using NuGet.Services.Validation;
@@ -31,6 +33,7 @@ public class SignatureValidator : ISignatureValidator
3133
private readonly ISignaturePartsExtractor _signaturePartsExtractor;
3234
private readonly IProcessorPackageFileService _packageFileService;
3335
private readonly IEntityRepository<Certificate> _certificates;
36+
private readonly ITelemetryService _telemetryService;
3437
private readonly ILogger<SignatureValidator> _logger;
3538

3639
public SignatureValidator(
@@ -40,6 +43,7 @@ public SignatureValidator(
4043
ISignaturePartsExtractor signaturePartsExtractor,
4144
IProcessorPackageFileService packageFileService,
4245
IEntityRepository<Certificate> certificates,
46+
ITelemetryService telemetryService,
4347
ILogger<SignatureValidator> logger)
4448
{
4549
_packageSigningStateService = packageSigningStateService ?? throw new ArgumentNullException(nameof(packageSigningStateService));
@@ -48,6 +52,7 @@ public SignatureValidator(
4852
_signaturePartsExtractor = signaturePartsExtractor ?? throw new ArgumentNullException(nameof(signaturePartsExtractor));
4953
_packageFileService = packageFileService ?? throw new ArgumentNullException(nameof(packageFileService));
5054
_certificates = certificates ?? throw new ArgumentNullException(nameof(certificates));
55+
_telemetryService = telemetryService ?? throw new ArgumentNullException(nameof(telemetryService));
5156
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
5257
}
5358

@@ -208,12 +213,21 @@ private async Task<SignatureValidatorResult> StripRepositorySignaturesAsync(Cont
208213
{
209214
packageStreamToDispose = FileStreamUtility.GetTemporaryFile();
210215

211-
var removed = await SignedPackageArchiveUtility.RemoveRepositorySignaturesAsync(
216+
var stopwatch = Stopwatch.StartNew();
217+
218+
var changed = await SignedPackageArchiveUtility.RemoveRepositorySignaturesAsync(
212219
context.PackageStream,
213220
packageStreamToDispose,
214221
context.CancellationToken);
215222

216-
if (removed)
223+
_telemetryService.TrackDurationToStripRepositorySignatures(
224+
stopwatch.Elapsed,
225+
context.Message.PackageId,
226+
context.Message.PackageVersion,
227+
context.Message.ValidationId,
228+
changed);
229+
230+
if (changed)
217231
{
218232
_logger.LogInformation(
219233
"Repository signatures were removed from package {PackageId} {PackageVersion} for validation {ValidationId}.",
@@ -232,6 +246,8 @@ private async Task<SignatureValidatorResult> StripRepositorySignaturesAsync(Cont
232246
packageStreamToDispose = null;
233247
context.PackageReader = new SignedPackageArchive(context.PackageStream, packageWriteStream: Stream.Null);
234248

249+
var initialSignature = context.Signature;
250+
235251
if (await context.PackageReader.IsSignedAsync(context.CancellationToken))
236252
{
237253
_logger.LogInformation(
@@ -241,6 +257,13 @@ private async Task<SignatureValidatorResult> StripRepositorySignaturesAsync(Cont
241257
context.Message.ValidationId);
242258

243259
context.Signature = await context.PackageReader.GetPrimarySignatureAsync(context.CancellationToken);
260+
261+
_telemetryService.TrackStrippedRepositorySignatures(
262+
context.Message.PackageId,
263+
context.Message.PackageVersion,
264+
context.Message.ValidationId,
265+
initialSignature,
266+
context.Signature);
244267
}
245268
else
246269
{
@@ -253,6 +276,14 @@ private async Task<SignatureValidatorResult> StripRepositorySignaturesAsync(Cont
253276
// The package is now unsigned. This would happen if the primary signature was a repository
254277
// signature that was removed.
255278
context.Signature = null;
279+
280+
_telemetryService.TrackStrippedRepositorySignatures(
281+
context.Message.PackageId,
282+
context.Message.PackageVersion,
283+
context.Message.ValidationId,
284+
initialSignature,
285+
outputSignature: null);
286+
256287
return await HandleUnsignedPackageAsync(context);
257288
}
258289
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using NuGet.Packaging.Signing;
6+
7+
namespace NuGet.Jobs.Validation.PackageSigning.Telemetry
8+
{
9+
public interface ITelemetryService
10+
{
11+
void TrackDurationToStripRepositorySignatures(
12+
TimeSpan duration,
13+
string packageId,
14+
string normalizedVersion,
15+
Guid validationId,
16+
bool changed);
17+
18+
void TrackStrippedRepositorySignatures(
19+
string packageId,
20+
string normalizedVersion,
21+
Guid validationId,
22+
PrimarySignature inputSignature,
23+
PrimarySignature outputSignature);
24+
}
25+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using NuGet.Packaging.Signing;
7+
using NuGet.Services.Logging;
8+
9+
namespace NuGet.Jobs.Validation.PackageSigning.Telemetry
10+
{
11+
public class TelemetryService : ITelemetryService
12+
{
13+
private const string Prefix = "ProcessSignature.";
14+
private const string StrippedRepositorySignatures = Prefix + "StrippedRepositorySignatures";
15+
private const string DurationToStripRepositorySignaturesSeconds = Prefix + "DurationToStripRepositorySignaturesSeconds";
16+
17+
private const string PackageId = "PackageId";
18+
private const string NormalizedVersion = "NormalizedVersion";
19+
private const string ValidationId = "ValidationId";
20+
private const string InputSignatureType = "InputSignatureType";
21+
private const string InputCounterSignatureCount = "InputCounterSignatureCount";
22+
private const string OutputSignatureType = "OutputSignatureType";
23+
private const string OutputCounterSignatureCount = "OutputCounterSignatureCount";
24+
private const string Changed = "Changed";
25+
26+
private readonly ITelemetryClient _telemetryClient;
27+
28+
public TelemetryService(ITelemetryClient telemetryClient)
29+
{
30+
_telemetryClient = telemetryClient ?? throw new ArgumentNullException(nameof(telemetryClient));
31+
}
32+
33+
public void TrackStrippedRepositorySignatures(
34+
string packageId,
35+
string normalizedVersion,
36+
Guid validationId,
37+
PrimarySignature inputSignature,
38+
PrimarySignature outputSignature)
39+
{
40+
var properties = new Dictionary<string, string>
41+
{
42+
{ PackageId, packageId },
43+
{ NormalizedVersion, normalizedVersion },
44+
{ ValidationId, validationId.ToString() },
45+
{ InputSignatureType, inputSignature.Type.ToString() },
46+
{ InputCounterSignatureCount, inputSignature.SignerInfo.CounterSignerInfos.Count.ToString() },
47+
};
48+
49+
if (outputSignature != null)
50+
{
51+
properties.Add(OutputSignatureType, outputSignature.Type.ToString());
52+
properties.Add(OutputCounterSignatureCount, outputSignature.SignerInfo.CounterSignerInfos.Count.ToString());
53+
}
54+
55+
_telemetryClient.TrackMetric(
56+
StrippedRepositorySignatures,
57+
1,
58+
properties);
59+
}
60+
61+
public void TrackDurationToStripRepositorySignatures(
62+
TimeSpan duration,
63+
string packageId,
64+
string normalizedVersion,
65+
Guid validationId,
66+
bool changed)
67+
{
68+
var properties = new Dictionary<string, string>
69+
{
70+
{ PackageId, packageId },
71+
{ NormalizedVersion, normalizedVersion },
72+
{ ValidationId, validationId.ToString() },
73+
{ Changed, changed.ToString() },
74+
};
75+
76+
_telemetryClient.TrackMetric(
77+
DurationToStripRepositorySignaturesSeconds,
78+
duration.TotalSeconds,
79+
properties);
80+
}
81+
}
82+
}

src/Validation.PackageSigning.ProcessSignature/Validation.PackageSigning.ProcessSignature.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@
5757
<Compile Include="Properties\AssemblyInfo.cs" />
5858
<Compile Include="SignatureValidationMessageHandler.cs" />
5959
<Compile Include="SignatureValidatorResult.cs" />
60+
<Compile Include="Telemetry\ITelemetryService.cs" />
61+
<Compile Include="Telemetry\TelemetryService.cs" />
6062
</ItemGroup>
6163
<ItemGroup>
6264
<None Include="App.config" />

tests/Validation.PackageSigning.ProcessSignature.Tests/SignatureValidatorFacts.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using NuGet.Jobs.Validation.PackageSigning.Messages;
1313
using NuGet.Jobs.Validation.PackageSigning.ProcessSignature;
1414
using NuGet.Jobs.Validation.PackageSigning.Storage;
15+
using NuGet.Jobs.Validation.PackageSigning.Telemetry;
1516
using NuGet.Jobs.Validation.Storage;
1617
using NuGet.Packaging.Signing;
1718
using NuGet.Services.Validation;
@@ -41,6 +42,7 @@ public class ValidateAsync
4142
private readonly Mock<IProcessorPackageFileService> _packageFileService;
4243
private readonly Uri _nupkgUri;
4344
private readonly SignatureValidator _target;
45+
private readonly Mock<ITelemetryService> _telemetryService;
4446

4547
public ValidateAsync(ITestOutputHelper output)
4648
{
@@ -82,13 +84,16 @@ public ValidateAsync(ITestOutputHelper output)
8284
.Setup(x => x.GetReadAndDeleteUriAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<Guid>()))
8385
.ReturnsAsync(() => _nupkgUri);
8486

87+
_telemetryService = new Mock<ITelemetryService>();
88+
8589
_target = new SignatureValidator(
8690
_packageSigningStateService.Object,
8791
_mimimalPackageSignatureVerifier.Object,
8892
_fullPackageSignatureVerifier.Object,
8993
_signaturePartsExtractor.Object,
9094
_packageFileService.Object,
9195
_certificates.Object,
96+
_telemetryService.Object,
9297
_logger);
9398
}
9499

tests/Validation.PackageSigning.ProcessSignature.Tests/SignatureValidatorIntegrationTests.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@
1818
using NuGet.Jobs.Validation.PackageSigning.Messages;
1919
using NuGet.Jobs.Validation.PackageSigning.ProcessSignature;
2020
using NuGet.Jobs.Validation.PackageSigning.Storage;
21+
using NuGet.Jobs.Validation.PackageSigning.Telemetry;
2122
using NuGet.Jobs.Validation.Storage;
2223
using NuGet.Packaging.Signing;
24+
using NuGet.Services.Logging;
2325
using NuGet.Services.Validation;
2426
using NuGet.Services.Validation.Issues;
2527
using NuGetGallery;
@@ -44,6 +46,8 @@ public class SignatureValidatorIntegrationTests : IDisposable
4446
private readonly List<string> _trustedThumbprints;
4547
private readonly IPackageSignatureVerifier _minimalPackageSignatureVerifier;
4648
private readonly IPackageSignatureVerifier _fullPackageSignatureVerifier;
49+
private readonly Mock<ITelemetryClient> _telemetryClient;
50+
private readonly TelemetryService _telemetryService;
4751
private readonly RecordingLogger<SignatureValidator> _logger;
4852
private readonly int _packageKey;
4953
private Stream _packageStream;
@@ -91,6 +95,9 @@ public SignatureValidatorIntegrationTests(CertificateIntegrationTestFixture fixt
9195
_minimalPackageSignatureVerifier = PackageSignatureVerifierFactory.CreateMinimal();
9296
_fullPackageSignatureVerifier = PackageSignatureVerifierFactory.CreateFull();
9397

98+
_telemetryClient = new Mock<ITelemetryClient>();
99+
_telemetryService = new TelemetryService(_telemetryClient.Object);
100+
94101
var loggerFactory = new LoggerFactory();
95102
loggerFactory.AddXunit(output);
96103
_logger = new RecordingLogger<SignatureValidator>(loggerFactory.CreateLogger<SignatureValidator>());
@@ -112,6 +119,7 @@ public SignatureValidatorIntegrationTests(CertificateIntegrationTestFixture fixt
112119
_signaturePartsExtractor.Object,
113120
_packageFileService.Object,
114121
_certificates.Object,
122+
_telemetryService,
115123
_logger);
116124
}
117125

0 commit comments

Comments
 (0)