-
Notifications
You must be signed in to change notification settings - Fork 696
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
Adding support for NuGet.exe sign command with fake signing #1755
Adding support for NuGet.exe sign command with fake signing #1755
Conversation
public ISignCommandRunner SignCommandRunner { get; set; } | ||
|
||
// List of possible values - https://github.com/Microsoft/referencesource/blob/master/mscorlib/system/security/cryptography/HashAlgorithmName.cs | ||
private static string[] _acceptedHashAlgorithms = { "SHA256", "SHA384", "SHA512" }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note: this will probably need to come from the helper that verifies this later based on the package signing version, that isn't in yet though
{ | ||
throw new ArgumentException(NuGetCommand.SignCommandNoCertificateException); | ||
} | ||
else if (!string.IsNullOrEmpty(CertificatePath) && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this would more clear if we had some static helper methods for these checks.
- Verify required option exists
- Verify no invalid option combinations
- Enum parsing + verify valid result
- With a way to throw the right message for all the above
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using an else if
for all of these also implies that these things are related, but they aren't. It would be the same logic if they were all separate ifs.
{ | ||
} | ||
|
||
public ISignCommandRunner SignCommandRunner { get; set; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like it would be easier if we had a static helper that created SignArgs and passed it back instead of needing to catch the SignArgs result by passing a mock SignCommandRunner in to get that result.
<EmbeddedResource Update="NuGetResources.resx"> | ||
<!-- Strings are shared by other projects, use public strings. --> | ||
<Generator>PublicResXFileCodeGenerator</Generator> | ||
<LastGenOutput>NuGetResources.Designer.cs</LastGenOutput> | ||
</EmbeddedResource> | ||
<Compile Update="NuGetCommand.Designer.cs"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: why did this move?
<value>Signs a NuGet package.</value> | ||
</data> | ||
<data name="SignCommandTimestampHashAlgorithmDescription" xml:space="preserve"> | ||
<value>Hash algorithm to be used by the RFC 3161 time stamp server. Defaults to SHA256.</value> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should time stamp be timestamp here?
@@ -33,6 +33,9 @@ | |||
<Reference Include="System.Xml" /> | |||
<Reference Include="System.Xml.Linq" /> | |||
<Reference Include="System.IO.Compression" /> | |||
<Reference Include="System.Security"> | |||
<HintPath>C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Security.dll</HintPath> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove hint path
/// </summary> | ||
internal class CertificateSourceOptions | ||
{ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: remove extra space
{ | ||
var package = new SignedPackageArchive(zip); | ||
var signer = new Signer(package); | ||
signer.SignAsync(request, logger, CancellationToken.None).Wait(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🥇
@@ -221,7 +221,7 @@ private static string GetSourceDisplayName(string source) | |||
return "'" + source + "'"; | |||
} | |||
|
|||
private static IEnumerable<string> GetPackagesToPush(string packagePath) | |||
public static IEnumerable<string> ResolvePackageFromPath(string packagePath) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move these wildcard methods to a new static helper class. The Sign command shouldn't have a dependency on Push.
LocalFolderUtility might be a good place to add them.
|
||
// Act & Assert | ||
var ex = Assert.Throws<ArgumentException>(() => signCommand.Execute()); | ||
Assert.Equal("No package was provided. For a list of accepted ways to provide a package, please visit http://docs.nuget.org/docs/reference/command-line-reference", ex.Message); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
any reason this doesn't use the const above?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Address minor feedback then
}; | ||
} | ||
|
||
private void ValidateAndParseHashAlgorithm(string value, string name, out HashAlgorithmName hashAlgorithm) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these methods can just return the value, it doesn't look like the out is needed since there is only 1 return
@@ -949,6 +949,47 @@ public static IEnumerable<LocalPackageInfo> GetPackagesV3(string root, string id | |||
yield break; | |||
} | |||
|
|||
|
|||
public static IEnumerable<string> ResolvePackageFromPath(string packagePath) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a /// summary here to make it clear to anyone else using this that the method is applying wild cards
} | ||
} | ||
|
||
private void ValidateCertificateInputs() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it an error to specify one but not both of CryptographicServiceProvider
and KeyContainer
?
@@ -5345,4 +5345,92 @@ nuget locals global-packages -list</value> | |||
<data name="InstallCommandFrameworkDescription" xml:space="preserve"> | |||
<value>Target framework used for selecting dependencies. Defaults to 'Any' if not specified.</value> | |||
</data> | |||
<data name="SignCommandCertificatePasswordDescription" xml:space="preserve"> | |||
<value>Password for the certificate, if needed. | |||
This option can be used to specify the password for the certificate. If no password is provided, the user may be prompted for a password at run time, unless the -NonInteractive option is passed.</value> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove the extra space between NonInteractive
and option
.
@@ -5345,4 +5345,92 @@ nuget locals global-packages -list</value> | |||
<data name="InstallCommandFrameworkDescription" xml:space="preserve"> | |||
<value>Target framework used for selecting dependencies. Defaults to 'Any' if not specified.</value> | |||
</data> | |||
<data name="SignCommandCertificatePasswordDescription" xml:space="preserve"> | |||
<value>Password for the certificate, if needed. | |||
This option can be used to specify the password for the certificate. If no password is provided, the user may be prompted for a password at run time, unless the -NonInteractive option is passed.</value> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nowhere else do we say "the user". The user is reading this message. Just say, "If no password is provided, the command will prompt for a password at runtime, unless the -NonInteractive option is passed."
The certificate store can be specified by -CertificateStoreName and -CertificateStoreLocation options.</value> | ||
</data> | ||
<data name="SignCommandCertificateSubjectNameDescription" xml:space="preserve"> | ||
<value>Subject name of the certificate used to search a local certificate store for the certificate. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some of these option descriptions are quite long. Does this print nicely?
<value>Signs a NuGet package with the specified certificate.</value> | ||
</data> | ||
<data name="SignCommandExamples" xml:space="preserve"> | ||
<value>nuget sign MyPackage.nupkg -CertificatePath /path/to/certificate |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like all our other examples use Windows-style paths (\ not /).
{ | ||
// Arrange | ||
var packagePath = @"foo\bar.nupkg"; | ||
var timestamper = "http://foo.bar"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://unit.test. Applies throughout this file.
{ | ||
Console = mockConsole.Object, | ||
Timestamper = timestamper, | ||
CertificatePath =certificatePath, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While you're in this document, format it.
[InlineData("Root")] | ||
[InlineData("TrustedPeople")] | ||
[InlineData("TrustedPublisher")] | ||
[InlineData("AddreSSBook")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think you need to test the case-sensitivity of every StoreName
member. Having one case-insensitivity test is completely sufficient.
[InlineData("CurrentUser")] | ||
[InlineData("LocalMachine")] | ||
[InlineData("currentuser")] | ||
[InlineData("localmaChiNe")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One case-insensitive test is sufficient.
// Act & Assert | ||
var signArgs = signCommand.GetSignArgs(); | ||
|
||
Assert.True( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this test and subsequent tests, would it be better to have multiple assertions? If this assertion fails, you don't know the reason without debugging. Bad!
@dtivel Thanks for the feedback, I will fix these in a separate PR. |
## Bug Fixes: NA Regression: No ## Fix Details: This PR addresses the some PR feedback that came in after merging #1755 along with some additional cleanup. ## Testing/Validation Tests Added: Yes Validation done: manual validation + tests
Bug
Link: Contributes to NuGet/Home#5904
Regression: No
Fix
Details: Adds a top level command to NuGet.exe to allow authors to sign packages with fake signing. The behavior is documented in the spec.
Testing/Validation
Tests Added: Yes
Validation done: Manually tested NuGet.exe