Skip to content

Commit 65ec29b

Browse files
committed
Add support for Nuget lockfiles
1 parent 9a5fff2 commit 65ec29b

File tree

2 files changed

+57
-1
lines changed

2 files changed

+57
-1
lines changed

src/Microsoft.ComponentDetection.Detectors/nuget/NuGetComponentDetector.cs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ namespace Microsoft.ComponentDetection.Detectors.NuGet;
55
using System.IO;
66
using System.Linq;
77
using System.Reactive.Linq;
8+
using System.Text.Json;
89
using System.Text.RegularExpressions;
910
using System.Threading.Tasks;
1011
using System.Xml;
@@ -20,6 +21,7 @@ public class NuGetComponentDetector : FileComponentDetector
2021
private static readonly IEnumerable<string> LowConfidencePackages = new[] { "Newtonsoft.Json" };
2122

2223
public const string NugetConfigFileName = "nuget.config";
24+
public const string NugetLockfileName = "packages.lock.json";
2325

2426
private readonly IList<string> repositoryPathKeyNames = new List<string> { "repositorypath", "globalpackagesfolder" };
2527

@@ -37,7 +39,15 @@ public NuGetComponentDetector(
3739

3840
public override IEnumerable<string> Categories => new[] { Enum.GetName(typeof(DetectorClass), DetectorClass.NuGet) };
3941

40-
public override IList<string> SearchPatterns { get; } = new List<string> { "*.nupkg", "*.nuspec", NugetConfigFileName, "paket.lock" };
42+
public override IList<string> SearchPatterns { get; }
43+
= new List<string>
44+
{
45+
"*.nupkg",
46+
"*.nuspec",
47+
NugetConfigFileName,
48+
NugetLockfileName,
49+
"paket.lock",
50+
};
4151

4252
public override IEnumerable<ComponentType> SupportedComponentTypes { get; } = new[] { ComponentType.NuGet };
4353

@@ -105,6 +115,12 @@ private async Task ProcessFileAsync(ProcessRequest processRequest)
105115
else if ("paket.lock".Equals(stream.Pattern, StringComparison.OrdinalIgnoreCase))
106116
{
107117
this.ParsePaketLock(processRequest);
118+
return;
119+
}
120+
else if (NugetLockfileName.Equals(stream.Pattern, StringComparison.OrdinalIgnoreCase))
121+
{
122+
await this.ParseNugetLockfileAsync(processRequest);
123+
return;
108124
}
109125
else
110126
{
@@ -174,6 +190,29 @@ private void ParsePaketLock(ProcessRequest processRequest)
174190
}
175191
}
176192

193+
private async Task ParseNugetLockfileAsync(ProcessRequest processRequest)
194+
{
195+
var singleFileComponentRecorder = processRequest.SingleFileComponentRecorder;
196+
var stream = processRequest.ComponentStream;
197+
198+
var lockfile = await JsonSerializer.DeserializeAsync<NugetLockfileShape>(stream.Stream);
199+
if (lockfile.Version != 1)
200+
{
201+
// only version 1 is supported
202+
singleFileComponentRecorder.RegisterPackageParseFailure(stream.Location);
203+
return;
204+
}
205+
206+
foreach (var framework in lockfile.Dependencies.Values)
207+
{
208+
foreach (var (name, value) in framework)
209+
{
210+
var component = new NuGetComponent(name, value.Resolved);
211+
singleFileComponentRecorder.RegisterUsage(new DetectedComponent(component));
212+
}
213+
}
214+
}
215+
177216
private IList<DirectoryInfo> GetRepositoryPathsFromNugetConfig(IComponentStream componentStream)
178217
{
179218
var potentialPaths = new List<string>();
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
namespace Microsoft.ComponentDetection.Detectors.NuGet;
2+
3+
using System.Collections.Generic;
4+
5+
internal class NugetLockfileShape
6+
{
7+
public int Version { get; set; }
8+
9+
public Dictionary<string, Dictionary<string, PackageShape>> Dependencies { get; set; }
10+
11+
public class PackageShape
12+
{
13+
public string Type { get; set; }
14+
15+
public string Resolved { get; set; }
16+
}
17+
}

0 commit comments

Comments
 (0)