diff --git a/src/Validation.PackageSigning.ProcessSignature/ProcessSignatureConfiguration.cs b/src/Validation.PackageSigning.ProcessSignature/ProcessSignatureConfiguration.cs
index 4d5bb7d5c..ab0fce92b 100644
--- a/src/Validation.PackageSigning.ProcessSignature/ProcessSignatureConfiguration.cs
+++ b/src/Validation.PackageSigning.ProcessSignature/ProcessSignatureConfiguration.cs
@@ -20,5 +20,11 @@ public class ProcessSignatureConfiguration
/// repository signature is removed.
///
public string V3ServiceIndexUrl { get; set; }
+
+ ///
+ /// Whether repository signatures should be persisted to the database. Disable this if repository signing
+ /// is in test mode and repository signed packages are not published.
+ ///
+ public bool CommitRepositorySignatures { get; set; }
}
}
diff --git a/src/Validation.PackageSigning.ProcessSignature/Settings/dev.json b/src/Validation.PackageSigning.ProcessSignature/Settings/dev.json
index 11728b8a0..ecbe7450d 100644
--- a/src/Validation.PackageSigning.ProcessSignature/Settings/dev.json
+++ b/src/Validation.PackageSigning.ProcessSignature/Settings/dev.json
@@ -22,7 +22,8 @@
"AllowedRepositorySigningCertificates": [
"cf6ce6768ef858a3a667be1af8aa524d386c7f59a34542713f5dfb0d79acf3dd"
],
- "V3ServiceIndexUrl": "https://apidev.nugettest.org/v3/index.json"
+ "V3ServiceIndexUrl": "https://apidev.nugettest.org/v3/index.json",
+ "CommitRepositorySignatures": false
},
"PackageDownloadTimeout": "00:10:00",
diff --git a/src/Validation.PackageSigning.ProcessSignature/Settings/int.json b/src/Validation.PackageSigning.ProcessSignature/Settings/int.json
index 1180c0816..3dd7a70fd 100644
--- a/src/Validation.PackageSigning.ProcessSignature/Settings/int.json
+++ b/src/Validation.PackageSigning.ProcessSignature/Settings/int.json
@@ -22,7 +22,8 @@
"AllowedRepositorySigningCertificates": [
"cf6ce6768ef858a3a667be1af8aa524d386c7f59a34542713f5dfb0d79acf3dd"
],
- "V3ServiceIndexUrl": "https://apiint.nugettest.org/v3/index.json"
+ "V3ServiceIndexUrl": "https://apiint.nugettest.org/v3/index.json",
+ "CommitRepositorySignatures": false
},
"PackageDownloadTimeout": "00:10:00",
diff --git a/src/Validation.PackageSigning.ProcessSignature/Settings/prod.json b/src/Validation.PackageSigning.ProcessSignature/Settings/prod.json
index d195c2287..2836e7501 100644
--- a/src/Validation.PackageSigning.ProcessSignature/Settings/prod.json
+++ b/src/Validation.PackageSigning.ProcessSignature/Settings/prod.json
@@ -22,7 +22,8 @@
"AllowedRepositorySigningCertificates": [
"cf7ac17ad047ecd5fdc36822031b12d4ef078b6f2b4c5e6ba41f8ff2cf4bad67"
],
- "V3ServiceIndexUrl": "https://api.nuget.org/v3/index.json"
+ "V3ServiceIndexUrl": "https://api.nuget.org/v3/index.json",
+ "CommitRepositorySignatures": false
},
"PackageDownloadTimeout": "00:10:00",
diff --git a/src/Validation.PackageSigning.ProcessSignature/SignaturePartsExtractor.cs b/src/Validation.PackageSigning.ProcessSignature/SignaturePartsExtractor.cs
index 3eccf8bca..7fb6056bd 100644
--- a/src/Validation.PackageSigning.ProcessSignature/SignaturePartsExtractor.cs
+++ b/src/Validation.PackageSigning.ProcessSignature/SignaturePartsExtractor.cs
@@ -8,6 +8,7 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
using NuGet.Jobs.Validation.PackageSigning.Storage;
using NuGet.Packaging.Signing;
using NuGet.Services.Validation;
@@ -18,15 +19,18 @@ public class SignaturePartsExtractor : ISignaturePartsExtractor
{
private readonly ICertificateStore _certificateStore;
private readonly IValidationEntitiesContext _entitiesContext;
+ private readonly IOptionsSnapshot _configuration;
private readonly ILogger _logger;
public SignaturePartsExtractor(
ICertificateStore certificateStore,
IValidationEntitiesContext entitiesContext,
+ IOptionsSnapshot configuration,
ILogger logger)
{
_certificateStore = certificateStore ?? throw new ArgumentNullException(nameof(certificateStore));
_entitiesContext = entitiesContext ?? throw new ArgumentNullException(nameof(entitiesContext));
+ _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
@@ -227,6 +231,12 @@ private async Task InitializePackageSignatureAndTrustedTimestampAsync(
return;
}
+ if (type == PackageSignatureType.Repository && !_configuration.Value.CommitRepositorySignatures)
+ {
+ _logger.LogInformation("Skipping initialization of repository signature due to configuration!");
+ return;
+ }
+
// Initialize the package signature record.
var packageSignature = await InitializePackageSignatureAsync(
packageKey,
diff --git a/tests/Validation.PackageSigning.ProcessSignature.Tests/SignaturePartsExtractorFacts.cs b/tests/Validation.PackageSigning.ProcessSignature.Tests/SignaturePartsExtractorFacts.cs
index 0b4077061..885f83c4c 100644
--- a/tests/Validation.PackageSigning.ProcessSignature.Tests/SignaturePartsExtractorFacts.cs
+++ b/tests/Validation.PackageSigning.ProcessSignature.Tests/SignaturePartsExtractorFacts.cs
@@ -10,7 +10,9 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
using Moq;
+using NuGet.Jobs.Validation.PackageSigning;
using NuGet.Jobs.Validation.PackageSigning.ProcessSignature;
using NuGet.Jobs.Validation.PackageSigning.Storage;
using NuGet.Packaging.Signing;
@@ -62,7 +64,7 @@ public class SignaturePartsExtractorFacts
"CN=NUGET_DO_NOT_TRUST.root.test.test, OU=Test Organizational Unit Name, O=Test Organization Name, L=Redmond, S=WA, C=US",
TestResources.RootThumbprint),
},
- TimestampEndCertificate = new SubjectAndThumbprint(
+ TimestampEndCertificate = new SubjectAndThumbprint(
"CN=Symantec SHA256 TimeStamping Signer - G2, OU=Symantec Trust Network, O=Symantec Corporation, C=US",
TestResources.Leaf1TimestampThumbprint),
TimestampParentCertificates = new[]
@@ -116,6 +118,8 @@ public class ExtractAsync
private readonly Mock _certificateStore;
private readonly List _savedCertificates;
private readonly Mock _entitiesContext;
+ private readonly Mock> _configAccessor;
+ private readonly ProcessSignatureConfiguration _config;
private readonly Mock> _logger;
private readonly SignaturePartsExtractor _target;
@@ -152,11 +156,20 @@ public ExtractAsync()
.Setup(x => x.TrustedTimestamps)
.Returns(DbSetMockFactory.Create());
+ _configAccessor = new Mock>();
+ _config = new ProcessSignatureConfiguration
+ {
+ CommitRepositorySignatures = true
+ };
+
+ _configAccessor.Setup(a => a.Value).Returns(_config);
+
_logger = new Mock>();
_target = new SignaturePartsExtractor(
_certificateStore.Object,
_entitiesContext.Object,
+ _configAccessor.Object,
_logger.Object);
}
@@ -616,6 +629,51 @@ public async Task IgnoreExtraCertificates()
signature.SignedCms.Certificates.Count + signature.Timestamps.Sum(x => x.SignedCms.Certificates.Count));
}
+ [Fact]
+ public async Task IfRepositorySignatureExtractionIsDisabled_IgnoresRepositorySignatureOnRepositorySignedPackage()
+ {
+ // Arrange
+ var signature = await TestResources.LoadPrimarySignatureAsync(TestResources.RepoSignedPackageLeaf1);
+
+ _entitiesContext
+ .Setup(x => x.PackageSignatures)
+ .Returns(DbSetMockFactory.Create());
+
+ _config.CommitRepositorySignatures = false;
+
+ // Act
+ await _target.ExtractAsync(_packageKey, signature, _token);
+
+ // Assert
+ Assert.Equal(0, _entitiesContext.Object.PackageSignatures.Count());
+
+ // The repository signature's certificate is still stored on blob storage.
+ VerifyStoredCertificates(Leaf1Certificates);
+ }
+
+ [Fact]
+ public async Task IfRepositorySignatureExtractionIsDisabled_IgnoresRepositorySignatureOnRepositoryCounterSignedPackage()
+ {
+ // Arrange
+ var signature = await TestResources.LoadPrimarySignatureAsync(TestResources.AuthorAndRepoSignedPackageLeaf1);
+
+ _entitiesContext
+ .Setup(x => x.PackageSignatures)
+ .Returns(DbSetMockFactory.Create());
+
+ _config.CommitRepositorySignatures = false;
+
+ // Act
+ await _target.ExtractAsync(_packageKey, signature, _token);
+
+ // Assert
+ Assert.Equal(1, _entitiesContext.Object.PackageSignatures.Count());
+ Assert.Equal(PackageSignatureType.Author, _entitiesContext.Object.PackageSignatures.First().Type);
+
+ // The repository signature's certificate is still stored on blob storage.
+ VerifyStoredCertificates(AuthorAndRepoSignedCertificates);
+ }
+
private void AssignIds()
{
var endCertificates = _entitiesContext.Object.EndCertificates.AsQueryable().ToList();
diff --git a/tests/Validation.PackageSigning.ProcessSignature.Tests/SignatureValidatorIntegrationTests.cs b/tests/Validation.PackageSigning.ProcessSignature.Tests/SignatureValidatorIntegrationTests.cs
index 742f2d98c..a4d899a8a 100644
--- a/tests/Validation.PackageSigning.ProcessSignature.Tests/SignatureValidatorIntegrationTests.cs
+++ b/tests/Validation.PackageSigning.ProcessSignature.Tests/SignatureValidatorIntegrationTests.cs
@@ -119,9 +119,21 @@ public SignatureValidatorIntegrationTests(CertificateIntegrationTestFixture fixt
_certificateStore = new Mock();
+ // These dependencies are concrete.
+ _configuration = new ProcessSignatureConfiguration
+ {
+ AllowedRepositorySigningCertificates = new List { "fake-thumbprint" },
+ V3ServiceIndexUrl = TestResources.V3ServiceIndexUrl,
+ CommitRepositorySignatures = true,
+ };
+ _optionsSnapshot = new Mock>();
+ _optionsSnapshot.Setup(x => x.Value).Returns(() => _configuration);
+ _formatValidator = new SignatureFormatValidator(_optionsSnapshot.Object);
+
_signaturePartsExtractor = new SignaturePartsExtractor(
_certificateStore.Object,
_validationEntitiesContext.Object,
+ _optionsSnapshot.Object,
loggerFactory.CreateLogger());
_packageFileService = new Mock();
@@ -144,16 +156,6 @@ public SignatureValidatorIntegrationTests(CertificateIntegrationTestFixture fixt
_corePackageService = new Mock();
- // These dependencies are concrete.
- _configuration = new ProcessSignatureConfiguration
- {
- AllowedRepositorySigningCertificates = new List { "fake-thumbprint" },
- V3ServiceIndexUrl = TestResources.V3ServiceIndexUrl,
- };
- _optionsSnapshot = new Mock>();
- _optionsSnapshot.Setup(x => x.Value).Returns(() => _configuration);
- _formatValidator = new SignatureFormatValidator(_optionsSnapshot.Object);
-
_telemetryClient = new Mock();
_telemetryService = new TelemetryService(_telemetryClient.Object);