I'm checking on ways to make GitHub Actions CI build to fail when a vulnerable nuget package is found in the projects within solution. Here is the repo.
Initially, I had the following simple command in the deployment.yml
:
# Check Vulnerable Nuget Packages
- name: Checking Vulnerable Nuget Packages
run: dotnet list package --vulnerable --include-transitive
But this doesn't make the build to fail. So after some googling I found that it is possible to make the build fail when vulnerable packages are found as per the following article. So I modified the above yml as follows:
# Check Vulnerable Nuget Packages
- name: Checking Vulnerable Nuget Packages
run: |
dotnet list package --vulnerable --include-transitive 2>&1 | tee build.log
echo "Analyze dotnet vulnerable nuget package command log output..."
grep -q -i "critical\|high\|moderate\|low" build.log; [ $? -eq 0 ] && echo "Security Vulnerabilities found in Nuget Packages on the log output" && exit 1
And here are the logs for the above command:
Run dotnet list package --vulnerable --include-transitive 2>&1 | tee build.log
dotnet list package --vulnerable --include-transitive 2>&1 | tee build.log
echo "Analyze dotnet vulnerable nuget package command log output..."
grep -q -i "critical\|high\|moderate\|low" build.log; [ $? -eq 0 ] && echo "Security Vulnerabilities found in Nuget Packages on the log output" && exit 1
shell: /usr/bin/bash -e {0}
env:
DOTNET_ROOT: /usr/share/dotnet
The following sources were used:
https://api.nuget.org/v3/index.json
The given project `Web` has no vulnerable packages given the current sources.
The given project `BaseComponents` has no vulnerable packages given the current sources.
The given project `BlazorDemoComponents` has no vulnerable packages given the current sources.
The given project `SharedModels` has no vulnerable packages given the current sources.
The given project `OOPSDemoComponents` has no vulnerable packages given the current sources.
The given project `UITests` has no vulnerable packages given the current sources.
The given project `DependencyInjectionDemoComponents` has no vulnerable packages given the current sources.
The given project `SharedComponents` has no vulnerable packages given the current sources.
The given project `LINQDemoComponents` has no vulnerable packages given the current sources.
The given project `DesignPatternDemoComponents` has no vulnerable packages given the current sources.
The given project `ReportDemoComponents` has no vulnerable packages given the current sources.
The given project `HTTPClientDemoComponents` has no vulnerable packages given the current sources.
The given project `MiddlewareDemoComponents` has no vulnerable packages given the current sources.
The given project `PythonDemoComponents` has no vulnerable packages given the current sources.
The given project `SOLIDDemoComponents` has no vulnerable packages given the current sources.
The given project `TDDDemoComponents` has no vulnerable packages given the current sources.
The given project `WebAPIDemoComponents` has no vulnerable packages given the current sources.
The given project `CommonComponents` has no vulnerable packages given the current sources.
Analyze dotnet vulnerable nuget package command log output...
Security Vulnerabilities found in Nuget Packages on the log output
Error: Process completed with exit code 1.
The above logs say there are no vulnerable packages in any of the project, but the build still failed. So I decided to print the contents of the build.log
to see what's wrong in it. And here is the updated command:
- name: Checking Vulnerable Nuget Packages
run: |
dotnet list package --vulnerable --include-transitive 2>&1 | tee build.log
echo "printing build.log..."
cat build.log
echo "Analyze dotnet vulnerable nuget package command log output..."
grep -q -i "critical\|high\|moderate\|low" build.log; [ $? -eq 0 ] && echo "Security Vulnerabilities found in Nuget Packages on the log output" && exit 1
and here is the output of the above command:
Run dotnet list package --vulnerable --include-transitive 2>&1 | tee build.log
dotnet list package --vulnerable --include-transitive 2>&1 | tee build.log
echo "printing build.log..."
cat build.log
echo "Analyze dotnet vulnerable nuget package command log output..."
grep -q -i "critical\|high\|moderate\|low" build.log; [ $? -eq 0 ] && echo "Security Vulnerabilities found in Nuget Packages on the log output" && exit 1
shell: /usr/bin/bash -e {0}
env:
DOTNET_ROOT: /usr/share/dotnet
The following sources were used:
https://api.nuget.org/v3/index.json
The given project `Web` has no vulnerable packages given the current sources.
The given project `BaseComponents` has no vulnerable packages given the current sources.
The given project `BlazorDemoComponents` has no vulnerable packages given the current sources.
The given project `SharedModels` has no vulnerable packages given the current sources.
The given project `OOPSDemoComponents` has no vulnerable packages given the current sources.
The given project `UITests` has no vulnerable packages given the current sources.
The given project `DependencyInjectionDemoComponents` has no vulnerable packages given the current sources.
The given project `SharedComponents` has no vulnerable packages given the current sources.
The given project `LINQDemoComponents` has no vulnerable packages given the current sources.
The given project `DesignPatternDemoComponents` has no vulnerable packages given the current sources.
The given project `ReportDemoComponents` has no vulnerable packages given the current sources.
The given project `HTTPClientDemoComponents` has no vulnerable packages given the current sources.
The given project `MiddlewareDemoComponents` has no vulnerable packages given the current sources.
The given project `PythonDemoComponents` has no vulnerable packages given the current sources.
The given project `SOLIDDemoComponents` has no vulnerable packages given the current sources.
The given project `TDDDemoComponents` has no vulnerable packages given the current sources.
The given project `WebAPIDemoComponents` has no vulnerable packages given the current sources.
The given project `CommonComponents` has no vulnerable packages given the current sources.
printing build.log...
The following sources were used:
https://api.nuget.org/v3/index.json
The given project `Web` has no vulnerable packages given the current sources.
The given project `BaseComponents` has no vulnerable packages given the current sources.
The given project `BlazorDemoComponents` has no vulnerable packages given the current sources.
The given project `SharedModels` has no vulnerable packages given the current sources.
The given project `OOPSDemoComponents` has no vulnerable packages given the current sources.
The given project `UITests` has no vulnerable packages given the current sources.
The given project `DependencyInjectionDemoComponents` has no vulnerable packages given the current sources.
The given project `SharedComponents` has no vulnerable packages given the current sources.
The given project `LINQDemoComponents` has no vulnerable packages given the current sources.
The given project `DesignPatternDemoComponents` has no vulnerable packages given the current sources.
The given project `ReportDemoComponents` has no vulnerable packages given the current sources.
The given project `HTTPClientDemoComponents` has no vulnerable packages given the current sources.
The given project `MiddlewareDemoComponents` has no vulnerable packages given the current sources.
The given project `PythonDemoComponents` has no vulnerable packages given the current sources.
The given project `SOLIDDemoComponents` has no vulnerable packages given the current sources.
The given project `TDDDemoComponents` has no vulnerable packages given the current sources.
The given project `WebAPIDemoComponents` has no vulnerable packages given the current sources.
The given project `CommonComponents` has no vulnerable packages given the current sources.
Analyze dotnet vulnerable nuget package command log output...
Security Vulnerabilities found in Nuget Packages on the log output
Error: Process completed with exit code 1.
Still the build fails. Please can you help me understand what I'm doing wrong? Anything wrong with the grep
command?
Update 1:
The answer accepted works fine in case when vulnerability is present but fails when no vulnerability is present. And thats because of the change in json structure. I have requested for update in answer.
Here is the No Vulnerabilties Found
case json result.
{
"version": 1,
"parameters": "--vulnerable --include-transitive",
"sources": [
"https://api.nuget.org/v3/index.json"
],
"projects": [
{
"path": "/home/runner/work/ilovedotnet/ilovedotnet/Web/Web.csproj"
},
{
"path": "/home/runner/work/ilovedotnet/ilovedotnet/BaseComponents/BaseComponents.csproj"
}
]
}
Here is the Vulnerabilities Found
case json result
{
"version": 1,
"parameters": "--vulnerable --include-transitive",
"sources": [
"https://api.nuget.org/v3/index.json"
],
"projects": [
{
"path": "/home/runner/work/NugetVulnerabilityCheck/NugetVulnerabilityCheck/NugetVulnerabilityCheck/NugetVulnerabilityCheck.csproj",
"frameworks": [
{
"framework": "net6.0",
"topLevelPackages": [
{
"id": "System.Net.Http",
"requestedVersion": "4.3.3",
"resolvedVersion": "4.3.3",
"vulnerabilities": [
{
"severity": "High",
"advisoryurl": "https://github.com/advisories/GHSA-7jgj-8wvc-jh57"
}
]
}
]
}
]
}
]
}
Here is the new sample repo used to evaluate the answers.
The solution with grep
command i.e.:
grep -q -i "critical\|high\|moderate\|low" build.log
scans the complete build.log
including:
The following sources were used:
https://api.nuget.org/v3/index.json
and, here it matches the word "low" with "following" and that's why it's failing.
You may tweak the regex to handle that; but in future, the component name or the log message itself may contain the strings being checked by the grep
regex resulting in failure.
A more robust solution would be to use the JSON format.
Starting .NET SDK 7.0.200, dotnet list package
subcommand offers a --format
flag that may be used to generate JSON output:
dotnet list package
commandThe JSON key severity
can be checked with the jq
command to identify the vulnerabilities.
Here's an example (https://jqplay.org/s/Ym9kqW4LbCe):
dotnet list package --vulnerable --include-transitive --format=json > list.json
if jq -cre '.projects | .. | .severity? // empty' list.json; then
echo 'Vulnerabilities found! Exiting...'
jq . list.json
exit 1
else
echo 'No vulnerabilities found!'
fi
It:
list.json
fileseverity
key under projects
severity
KV pairs
You can adjust this solution to fail your workflow for some specific severity level e.g. "Critical" by updating jq
filter i.e. select(test("Critical"))
:
dotnet list package --vulnerable --include-transitive --format=json > list.json
if jq -cre '.projects | .. | .severity? // empty | select(test("Critical"))' list.json; then
echo 'Vulnerabilities found! Exiting...'
jq . list.json
exit 1
else
echo 'No vulnerabilities found!'
fi
You can further expand this solution according to your complete use case as you deem fit e.g. you might want to add validation checks for the intermediate nodes, etc.