Skip to content

Commit 24fb2a3

Browse files
authored
Fix bug with namespace reservation and snupkg push with older clients (#6768)
1 parent d4df122 commit 24fb2a3

8 files changed

Lines changed: 70 additions & 27 deletions

File tree

src/NuGetGallery/Services/PackageService.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ public async Task EnsureValid(PackageArchiveReader packageArchiveReader)
5656
packageArchiveReader.GetNuspecReader(),
5757
strict: true);
5858

59+
if (packageMetadata.IsSymbolsPackage())
60+
{
61+
throw new InvalidPackageException(Strings.UploadPackage_SymbolsPackageNotAllowed);
62+
}
63+
5964
PackageHelper.ValidateNuGetPackageMetadata(packageMetadata);
6065

6166
var supportedFrameworks = GetSupportedFrameworks(packageArchiveReader).Select(fn => fn.ToShortNameOrNull()).ToArray();

src/NuGetGallery/Services/ReservedNamespaceService.cs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ namespace NuGetGallery
1515
{
1616
public class ReservedNamespaceService : IReservedNamespaceService
1717
{
18-
private static readonly Regex NamespaceRegex = new Regex(@"^\w+([_.-]\w+)*[.]?$", RegexOptions.Compiled | RegexOptions.ExplicitCapture);
18+
private static readonly Regex NamespaceRegex = new Regex(@"^\w+([_.-]\w+)*[.-]?$", RegexOptions.Compiled | RegexOptions.ExplicitCapture);
1919

2020
public IEntitiesContext EntitiesContext { get; protected set; }
2121
public IEntityRepository<ReservedNamespace> ReservedNamespaceRepository { get; protected set; }
@@ -47,7 +47,14 @@ public async Task AddReservedNamespaceAsync(ReservedNamespace newNamespace)
4747
throw new ArgumentNullException(nameof(newNamespace));
4848
}
4949

50-
ValidateNamespace(newNamespace.Value);
50+
try
51+
{
52+
ValidateNamespace(newNamespace.Value);
53+
}
54+
catch (ArgumentException ex)
55+
{
56+
throw new InvalidOperationException(ex.Message, ex);
57+
}
5158

5259
var matchingReservedNamespaces = FindAllReservedNamespacesForPrefix(prefix: newNamespace.Value, getExactMatches: !newNamespace.IsPrefix);
5360
if (matchingReservedNamespaces.Any())
@@ -348,12 +355,12 @@ public static void ValidateNamespace(string value)
348355
throw new ArgumentException(Strings.ReservedNamespace_InvalidNamespace);
349356
}
350357

351-
if (value.Length > NuGet.Services.Entities.Constants.MaxPackageIdLength)
358+
if (value.Length > Constants.MaxPackageIdLength)
352359
{
353360
throw new ArgumentException(string.Format(
354361
CultureInfo.CurrentCulture,
355362
Strings.ReservedNamespace_NamespaceExceedsLength,
356-
NuGet.Services.Entities.Constants.MaxPackageIdLength));
363+
Constants.MaxPackageIdLength));
357364
}
358365

359366
if (!NamespaceRegex.IsMatch(value))

src/NuGetGallery/Strings.Designer.cs

Lines changed: 11 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/NuGetGallery/Strings.resx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,7 @@ For more information, please contact '{2}'.</value>
491491
<value>This package will only be available to download with SemVer 2.0.0 compatible NuGet clients, such as Visual Studio 2017 (version 15.3) and above or NuGet client 4.3 and above. For more information, see https://go.microsoft.com/fwlink/?linkid=852248.</value>
492492
</data>
493493
<data name="ReservedNamespace_InvalidCharactersInNamespace" xml:space="preserve">
494-
<value>The namespace '{0}' contains invalid characters. Examples of valid namespaces include 'MyNamespace' and 'MyNamespace.'.</value>
494+
<value>The namespace '{0}' contains invalid characters. Examples of valid namespaces include 'MyNamespace', 'MyNamespace.' or 'MyNamespace-' etc.</value>
495495
</data>
496496
<data name="ReservedNamespace_InvalidNamespace" xml:space="preserve">
497497
<value>Invalid namespace specified</value>
@@ -1085,4 +1085,7 @@ The {1} Team</value>
10851085
<value>The package metadata defines '{0}' as author more than once, which is not allowed by policy.</value>
10861086
<comment>{0} is the list of duplicate package authors</comment>
10871087
</data>
1088+
<data name="UploadPackage_SymbolsPackageNotAllowed" xml:space="preserve">
1089+
<value>Snupkg upload failed. Please use latest NuGet clients (v 4.9.0 or above) and a V3 endpoint to push Symbol packages. For details, refer https://docs.microsoft.com/nuget/create-packages/symbol-packages-snupkg</value>
1090+
</data>
10881091
</root>

tests/NuGetGallery.Core.Facts/TestUtils/PackageServiceUtility.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,5 +190,15 @@ public static MemoryStream CreateNuGetPackageStream(string id = "theId",
190190
licenseFilename: licenseFilename,
191191
licenseFileContents: licenseFileContents);
192192
}
193+
194+
public static PackageArchiveReader CreateArchiveReader(Stream stream)
195+
{
196+
if (stream == null)
197+
{
198+
stream = TestPackage.CreateTestPackageStream("theId", "1.0.42");
199+
}
200+
201+
return new PackageArchiveReader(stream, leaveStreamOpen: true);
202+
}
193203
}
194204
}

tests/NuGetGallery.Facts/Services/PackageServiceFacts.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2059,6 +2059,21 @@ public async Task WillThrowIfThePackageIsNull()
20592059
}
20602060
}
20612061

2062+
public class TheEnsureValidMethod
2063+
{
2064+
[Fact]
2065+
public async Task EnsureValidThrowsForSymbolsPackage()
2066+
{
2067+
// Arrange
2068+
var service = CreateService();
2069+
var packageStream = TestPackage.CreateTestSymbolPackageStream();
2070+
var packageArchiveReader = PackageServiceUtility.CreateArchiveReader(packageStream);
2071+
2072+
// Act and Assert
2073+
await Assert.ThrowsAsync<InvalidPackageException>(async () => await service.EnsureValid(packageArchiveReader));
2074+
}
2075+
}
2076+
20622077
public class TheRemovePackageOwnerMethod
20632078
{
20642079
[Fact]

tests/NuGetGallery.Facts/Services/ReservedNamespaceServiceFacts.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ public async Task EmptyOrNullNamespaceThrowsException(string value)
9999
{
100100
var service = new TestableReservedNamespaceService();
101101
var addNamespace = new ReservedNamespace(value, isSharedNamespace: false, isPrefix: true);
102-
await Assert.ThrowsAsync<ArgumentException>(async () => await service.AddReservedNamespaceAsync(addNamespace));
102+
await Assert.ThrowsAsync<InvalidOperationException>(async () => await service.AddReservedNamespaceAsync(addNamespace));
103103
}
104104

105105
[Theory]
@@ -110,7 +110,7 @@ public async Task InvalidNamespaceThrowsException(string value)
110110
{
111111
var service = new TestableReservedNamespaceService();
112112
var addNamespace = new ReservedNamespace(value, isSharedNamespace: false, isPrefix: true);
113-
await Assert.ThrowsAsync<ArgumentException>(async () => await service.AddReservedNamespaceAsync(addNamespace));
113+
await Assert.ThrowsAsync<InvalidOperationException>(async () => await service.AddReservedNamespaceAsync(addNamespace));
114114
}
115115

116116
[Fact]
@@ -969,6 +969,7 @@ public class ValidateNamespaceMethod
969969
[InlineData("Cont@ins$pecia|C#aracters")]
970970
[InlineData("Endswithperods..")]
971971
[InlineData("Multiple.Sequential..Periods.")]
972+
[InlineData("Multiple-Sequential--hyphens")]
972973
public void InvalidNamespacesThrowsException(string value)
973974
{
974975
Assert.Throws<ArgumentException>(() => ReservedNamespaceService.ValidateNamespace(value));
@@ -980,6 +981,9 @@ public void InvalidNamespacesThrowsException(string value)
980981
[InlineData("Name.Space.")]
981982
[InlineData("123_Name.space.")]
982983
[InlineData("123-Namespace.")]
984+
[InlineData("123-Namespace-endswith-hyphen-")]
985+
[InlineData("123_Namespace_endswith_Underscores_")]
986+
[InlineData("Multiple_Sequential__Underscores")]
983987
public void ValidNamespacesDontThrowException(string value)
984988
{
985989
var ex = Record.Exception(() => ReservedNamespaceService.ValidateNamespace(value));

tests/NuGetGallery.Facts/Services/SymbolPackageServiceFacts.cs

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
using System.IO.Compression;
88
using System.Threading.Tasks;
99
using Moq;
10-
using NuGet.Packaging;
1110
using NuGet.Services.Entities;
1211
using NuGetGallery.Packaging;
12+
using NuGetGallery.TestUtils;
1313
using Xunit;
1414
using ClientPackageType = NuGet.Packaging.Core.PackageType;
1515

@@ -39,16 +39,6 @@ private static ISymbolPackageService CreateService(
3939
return symbolPackageService.Object;
4040
}
4141

42-
private static PackageArchiveReader CreateArchiveReader(Stream stream)
43-
{
44-
if (stream == null)
45-
{
46-
stream = TestPackage.CreateTestPackageStream("theId", "1.0.42");
47-
}
48-
49-
return new PackageArchiveReader(stream, leaveStreamOpen: true);
50-
}
51-
5242
private static List<ClientPackageType> CreateSymbolPackageTypesObject()
5343
{
5444
return new List<ClientPackageType>()
@@ -91,7 +81,7 @@ public async Task WillThrowForMissingSymbolsPackageType()
9181
{
9282
var service = CreateService();
9383
var invalidSymbolPackageStream = TestPackage.CreateTestPackageStream("theId", "1.0.42");
94-
var packageArchiveReader = CreateArchiveReader(invalidSymbolPackageStream);
84+
var packageArchiveReader = PackageServiceUtility.CreateArchiveReader(invalidSymbolPackageStream);
9585

9686
await Assert.ThrowsAsync<InvalidPackageException>(async () => await service.EnsureValidAsync(packageArchiveReader));
9787
}
@@ -105,7 +95,7 @@ public async Task WillThrowForIncorrectSymbolsPackageTypeVersion()
10595
new ClientPackageType("SymbolsPackage", new Version("1.1"))
10696
};
10797
var invalidSymbolPackageStream = TestPackage.CreateTestPackageStream("theId", "1.0.42", packageTypes: packageTypes);
108-
var packageArchiveReader = CreateArchiveReader(invalidSymbolPackageStream);
98+
var packageArchiveReader = PackageServiceUtility.CreateArchiveReader(invalidSymbolPackageStream);
10999

110100
await Assert.ThrowsAsync<InvalidPackageException>(async () => await service.EnsureValidAsync(packageArchiveReader));
111101
}
@@ -118,7 +108,7 @@ public async Task WillThrowForMultiplePackageTypesInNuspec()
118108
packageTypes.Add(new ClientPackageType("RandomPackageType", ClientPackageType.EmptyVersion));
119109

120110
var invalidSymbolPackageStream = TestPackage.CreateTestPackageStream("theId", "1.0.42", packageTypes: packageTypes);
121-
var packageArchiveReader = CreateArchiveReader(invalidSymbolPackageStream);
111+
var packageArchiveReader = PackageServiceUtility.CreateArchiveReader(invalidSymbolPackageStream);
122112

123113
await Assert.ThrowsAsync<InvalidPackageException>(async () => await service.EnsureValidAsync(packageArchiveReader));
124114
}
@@ -130,7 +120,7 @@ public async Task WillThrowForAuthorsMetadataInNuspec()
130120
var packageTypes = CreateSymbolPackageTypesObject();
131121

132122
var invalidSymbolPackageStream = TestPackage.CreateTestPackageStream("theId", "1.0.42", authors: "Random authors", packageTypes: packageTypes);
133-
var packageArchiveReader = CreateArchiveReader(invalidSymbolPackageStream);
123+
var packageArchiveReader = PackageServiceUtility.CreateArchiveReader(invalidSymbolPackageStream);
134124

135125
await Assert.ThrowsAsync<InvalidDataException>(async () => await service.EnsureValidAsync(packageArchiveReader));
136126
}
@@ -142,7 +132,7 @@ public async Task WillThrowForOwnersMetadataInNuspec()
142132
var packageTypes = CreateSymbolPackageTypesObject();
143133

144134
var invalidSymbolPackageStream = TestPackage.CreateTestPackageStream("theId", "1.0.42", owners: "Random owners", packageTypes: packageTypes);
145-
var packageArchiveReader = CreateArchiveReader(invalidSymbolPackageStream);
135+
var packageArchiveReader = PackageServiceUtility.CreateArchiveReader(invalidSymbolPackageStream);
146136

147137
await Assert.ThrowsAsync<InvalidDataException>(async () => await service.EnsureValidAsync(packageArchiveReader));
148138
}
@@ -158,7 +148,7 @@ public async Task WillThrowForInvalidFilesInSnupkg(string extension)
158148
var action = CreatePopulatePackageAction(extension);
159149

160150
var invalidSymbolPackageStream = TestPackage.CreateTestSymbolPackageStream("theId", "1.0.42", populatePackage: action);
161-
var packageArchiveReader = CreateArchiveReader(invalidSymbolPackageStream);
151+
var packageArchiveReader = PackageServiceUtility.CreateArchiveReader(invalidSymbolPackageStream);
162152

163153
await Assert.ThrowsAsync<InvalidDataException>(async () => await service.EnsureValidAsync(packageArchiveReader));
164154
}
@@ -175,7 +165,7 @@ public async Task WillNotThrowForValidSnupkgFile(string extension)
175165
var action = CreatePopulatePackageAction(extension);
176166

177167
var validSymbolPackageStream = TestPackage.CreateTestSymbolPackageStream("theId", "1.0.42", populatePackage: action);
178-
var packageArchiveReader = CreateArchiveReader(validSymbolPackageStream);
168+
var packageArchiveReader = PackageServiceUtility.CreateArchiveReader(validSymbolPackageStream);
179169

180170
await service.EnsureValidAsync(packageArchiveReader);
181171
}

0 commit comments

Comments
 (0)