What are some Nuget package best practices? And how can I sign my Nuget package?
- Page Owner: Not Set
- Last Reviewed: 2022-08-18
I'm trying to publish a Nuget package, what best practices should I follow?
Also, I've got a code signing certificate, but how do I use it to actually sign the cert?
Answer
First off, keep in mind the code signing cert is considered HIGHLY SENSITIVE information and should not be shared, and should never be stored unencrypted.
Package Name
For any package in the public Nuget feed, it must be prefixed with BlendInteractive. to be signed and verified as belonging to Blend. No one other than Blend can publish BlendInteractive. packages.
Include a readme, license, and icon files
You should have a README.md, license.txt, and some kind of icon file in your repository. You should link these files in your .csproj file for inclusion in the package at the root level of the nuget package.
For example:
<ItemGroup>
<None Include="..\..\license.txt">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
<None Include="..\..\README.md">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
<None Include="..\..\icon.png">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
</ItemGroup>
Include basic information
As an example, include the following at minimum. Note that all versions (Version, PackageVersion, AssemblyVersion, FileVersion) should match (minus the missing .0 on Version).
<PackageId>BlendInteractive.Sentry</PackageId>
<Description>Default Sentry configuration for Blend Interactive projects</Description>
<Version>1.0.3</Version>
<PackageVersion>1.0.3</PackageVersion>
<AssemblyVersion>1.0.3.0</AssemblyVersion>
<FileVersion>1.0.3.0</FileVersion>
<Authors>Blend Interactive</Authors>
<Company>Blend Interactive</Company>
<PackageProjectUrl>https://github.com/blendinteractive/blend-sentry</PackageProjectUrl>
<RepositoryUrl>https://github.com/blendinteractive/blend-sentry.git</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageTags></PackageTags>
<IsPackable>true</IsPackable>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<PackageIcon>icon.png</PackageIcon>
<PackageLicenseFile>license.txt</PackageLicenseFile>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageIconUrl />
Include a SourceLink package as a dev dependency
If the project is open source and on Github, add a dependency to your .csproj:
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All"/>
</ItemGroup>
This should enable SourceLink so users can see the source code for the package if they need to for debugging. PrivateAssets="All" makes the dependency a dev-only dependency, so it does not get bundled with the project. I believe it executes at build time to link the appropriate files to their Github equivalents.
There are SourceLink packages for other providers, but as of this writing, all our open source stuff is on Github.
Generate a symbols package as well
Again in your .csproj file:
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
Use Deteriminstic build
Do not build packages on your local machine for public or internal consumption except in rare special circumstances, only use Continuous Integration builds for packages that will be used by others.
You can signal to the build process that this is a CI build by passing /p:ContinuousIntegrationBuild=true to the build or pack step. For example, splitting the build and pack steps into two separate steps:
dotnet build .\src\BlendInteractive.Sentry\BlendInteractive.Sentry.csproj -c Release /p:ContinuousIntegrationBuild=true
dotnet pack .\src\BlendInteractive.Sentry\BlendInteractive.Sentry.csproj -c Release --no-build -o ./artifacts/
Sign your package
You may need to first combine your public certificate and private key into a single P12 file. You can do this from with OpenSSL tools, something like:
openssl pkcs12 -export -out code-signing.p12 -inkey privkey.pem -in cert.pem -passout pass:REPLACE_PASSWORD
Obiviously, replace REPLACE_PASSWORD with a strong password saved in a secure place. code-signing.p12 is the file that Nuget will use for signing. Keep this file safe, always encrypted, never shared.
Then sign your built package:
dotnet nuget sign .\artifacts\BlendInteractive.Sentry.1.0.3.nupkg --certificate-path J:\super_secure\code-signing.p12 --timestamper http://timestamp.sectigo.com --certificate-password REPLACE_PASSWORD
(note: still need to get the signing working on CI builds, but this is how you can do it from your local machine -- consider this answer work-in-progress)