Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Block packages with illegal package dependency version ranges #3728

Merged
merged 4 commits into from
Apr 5, 2017

Conversation

xavierdecoster
Copy link
Member

Fixes #3482

Using strictVersionCheck=true by default, to block packages from being uploaded to nuget.org if they contain package dependencies with an invalid version range.

@xavierdecoster xavierdecoster added this to the S116 - 2017.3.27 milestone Mar 30, 2017
@xavierdecoster xavierdecoster self-assigned this Mar 30, 2017
@xavierdecoster xavierdecoster changed the title No longer accept packages with illegal package dependency version ranges Block packages with illegal package dependency version ranges Mar 30, 2017
@@ -1149,7 +1150,8 @@ private ActionResult EditFailed(string id, EditPackageRequest formData, Package
package = await _packageService.CreatePackageAsync(nugetPackage, packageStreamMetadata, currentUser, commitChanges: false);
Debug.Assert(package.PackageRegistration != null);
}
catch (EntityException ex)
catch(Exception ex)
when (ex is PackagingException || ex is EntityException)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit new line looks weird here

private string[] GetErrors(Stream nuspecStream)
[Theory]
[InlineData("$version$")]
[InlineData("[15.106.0.preview]")]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is
<dependency id=""a.b.c"" version="" />
is legal?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The NuspecReader.GetDependencyGroups(useStrictVersionCheck: true) does not throw apparently when the dependency version is "". Should it? It currently still does a silent fallback to VersionRange.All - aka (,).

If it should throw, that means another fix is due on the NuGet.Packaging client lib.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Imho, when using useStrictVersionCheck: true, we should treat null and "" as invalid versions, and thus throw.

However, the PR that added the overload for strict version checks explicitly added null and "" in the test data for valid version ranges (highlight). An oversight? Or conscious?

Seems like a question @emgarten and @joelverhagen may want to comment on. The fix in the client lib is pretty trivial, but as you can tell, rather important :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our docs specifically state that you can leave the version range unspecified, and what will happen. IMO we should keep this behavior the same, or, at the bare minimum, investigate how many packages have this issue before changing it.

https://docs.microsoft.com/en-us/nuget/create-packages/dependency-versions#version-ranges

Copy link
Member Author

@xavierdecoster xavierdecoster Apr 4, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I spoke to @emgarten and @joelverhagen before implementing this change, and the conclusion was that, moving forward, we should be strict and block this from happening. The documented behavior was more a hack to support floating versions if I understood correctly. The change to reject empty dependency version ranges is also in line with the recommendation as per the docs.

For consistent behavior, it's recommended to always specify a version or version range for package dependencies.

If no version is specified for a dependency, NuGet behaves as follows:

  • NuGet v2.7.2 and earlier: The latest package version will be used
  • NuGet v2.8 and later: The lowest package version will be used

I think we should add:

  • NuGet v2.8 to v4.1.0: The lowest package version will be used
  • NuGet v4.3.0 and above: no longer supported and considered an invalid dependency version range

/// <exception cref="PackagingException">
/// This exception will be thrown if an invalid package dependency version range is detected.
/// </exception>
/// <exception cref="EntityException">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This "contract" is a bit strange... we throw EntityException for every bad metadata value, but a different exception (PackagingException) for bad dependencies.
I suggest wrapping it here in InvalidPackageException. This way we will have a clear contract with the callers.
Also, noticed there are place where we call EnsureValid, but don't expose the failure message correctly:
https://github.com/NuGet/NuGetGallery/blob/master/src/NuGetGallery/Controllers/PackagesController.cs#L234

This is one example why having a single exception type thrown will be better.

@@ -249,7 +249,7 @@ public class ManifestValidatorFacts
</metadata>
</package>";

private const string NuSpecDependencySetContainsInvalidTargetFramework = @"<?xml version=""1.0""?>
private const string NuSpecDependencySetContainsInvalidVersionRange = @"<?xml version=""1.0""?>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this change, are we no longer testing invalid target frameworks?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That string was not used anywhere, I merely put it to use in a different scenario :)

private string[] GetErrors(Stream nuspecStream)
[Theory]
[InlineData("$version$")]
[InlineData("[15.106.0.preview]")]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our docs specifically state that you can leave the version range unspecified, and what will happen. IMO we should keep this behavior the same, or, at the bare minimum, investigate how many packages have this issue before changing it.

https://docs.microsoft.com/en-us/nuget/create-packages/dependency-versions#version-ranges

public static PackageMetadata FromNuspecReader(NuspecReader nuspecReader)
{
return new PackageMetadata(
nuspecReader.GetMetadata().ToDictionary(kvp => kvp.Key, kvp => kvp.Value),
nuspecReader.GetDependencyGroups(),
nuspecReader.GetDependencyGroups(useStrictVersionCheck: true),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not in the scope of this PR, but do we potentially have similar issues with our framework reference groups, packages types, or min client version?

@xavierdecoster
Copy link
Member Author

Updated this PR to consume the fresh builds that include the null and empty check fixes. Had to modify a few tests that assumed the empty string fallback to VersionRange.All, which we now not only do not recommend, but explicitly block from being pushed/uploaded to the gallery.

Final pair of eyes please? :) @joelverhagen @scottbommarito @skofman1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants