Automate NuGet Package Updates

Whether you are starting a greenfield or working on a legacy project, you can start receiving pull requests with NuGet package updates automatically, integrated in your CI pipeline with NuKeeper.

Boris Donev
6 min readJan 23, 2021
Command line output

We never updated the NuGet packages on one of the projects I’ve been working on. The project did its job, there was no need to. And then, on one innocent morning, we read about a serious vulnerability of a package we used - attackers could execute arbitrary code through that. A security patch was available in the newest version of the package. We immediately had to prioritize updating that NuGet package, which was not updated in 5 years. One of the developers in the team spent the whole sprint updating to the newest version, and the whole team spent even more time testing the application trying to find issues.
And this was not the only instance. On the very same project, we also had to update a few NuGet packages because we needed a feature in a newer version. Had the package been up to date, we would not have spent the time on updating before using the feature, which was 80% of the development time.
Needless to say, this way of keeping your NuGet packages up to date is not sustainable.
Moreover, if your system is used by renowned companies or you want to integrate with them, they will most likely request a security whitepaper, where you have to explain how you secure your system. And they are interested in how the security is automated, taken out of developers’ hands and included in the CI/CD pipeline. Having always up to date NuGet packages is one small part of it, but nevertheless will prove that you are resistant to certain types of vulnerabilities.

Typical developer reaction when they need to update a package older than a first grader (Usman Yousaf on Unsplash)

How can you keep NuGet packages in the solution always up to date

We tried to make sure this will never happen again. We could have just moved on and wait for the next incident. Or we could have talked that we need to update the packages, and do that for a couple of months before we again stopped keeping them up to date. But we took a step further and automated the NuGet packages update.

We used NuKeeper on an on-premise Azure DevOps server to receive pull requests with NuGet updates on all projects within the solution. After that, the only responsibility of the development team is to review and approve the pull request.
While NuKeeper has a marketplace task step for easy usage in Azure DevOps, it does not work with an on-premise server. The reason is that it wants basic authentication enabled on the server, while Microsoft says it is not recommended. So we had to find a workaround. The workaround was pretty simple, as it was just executing the repo command with a PowerShell step.

But before that, you’ll need to install the NuKeeper .NET tool, by using .NET Core Global Tool Installer. Since this command uses the regular dotnet tool command line in behind, we need to install the .NET Core version we use for the project as well. These are the first 2 steps in the pipeline.

Next, we run dotnet restore so the NuGet packages are retrieved, in case you use private feeds NuKeeper cannot access when it will need the packages later.

The next step is necessary because we run into a “Path too long” issue. We tell NuKeeper to use a temporary hard-coded folder, and if that folder already exists, NuKeeper will fail. So, we remove the folder if it exists.
Not the brightest solution, but it seems to work as we can usually count on the Windows machines to have the C: drive.

At last, we get to the point where we can execute NuKeeper. You’ll need to add a simple PowerShell script that will execute the repo command. As you can see, before that you need to set the global username and email, otherwise this step will fail.

NuKeeper authenticates by using PAT, so be sure you create one, and place it in a variable.
We configured NuKeeper to update only 5 packages at a time (-m 5), because we didn’t start the project with this tool, and we want to update the NuGet packages in a controlled manner. Every NuGet update needs to be tested so we are sure it does not break things. Even though there are no build errors, there might be runtime errors.
We also update only to a version that is older than 1 week, which is the default setting if left unset. We don’t want to immediately jump to the newest possible version, as it might have issues.
The -n parameter tells NuKeeper to consolidate all updates into a single pull request.
NuGet packages related to .NET are excluded (-e …), since we don’t want to suddenly raise .NET or Entity Framework versions, as they tend to have breaking changes.
We already explained above why we need the -cdir argument.
You can read much more about the configuration options here.

Once the repo command is done, just unset the name and email.

After running this build definition, you should see this little pull request.

If you open the pull request, you’ll see it just updated certain packages on all projects of the solution.

Now it’s up to the developers to test this (just in case there are runtime errors), approve and complete the pull request.
If you have end to end tests in your project, then you might skip the manual testing as well — but it is not recommended to have many of them, so it depends.

Conclusion

Updating NuGet packages is mostly a repetitive job, and we should strive to automate every repetitive job we do so we can become more productive. In the long run it benefits us as well, because we will spend more time on real problems rather than on manual updating of packages.
If you already have a continuous integration pipeline set up, then it is a piece of cake to add automatic update of NuGet packages. Having your NuGet packages always up to date ensures that your system is not susceptible to common attacks that exploit holes in old packages and dependencies that you used. It also ensures that you can use new features of said dependencies immediately, rather than having to update several generations of the package before you do so.
Using Azure DevOps is also not a requirement, because this is just a simple command line that we execute, and any DevOps solution supports that.

--

--

Boris Donev

As a technical team lead of several startup projects, I've come across different issues which I'll try to document and maybe help someone else.