Skip to content

Commit ddaf2b3

Browse files
author
Fatherhood.Foundation
authored
Merge branch 'main' into main
2 parents 3c6925d + bdfdcd2 commit ddaf2b3

24 files changed

+28909
-1055
lines changed

.github/workflows/snapshot-publish.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ name: Publish snapshot of test scan
22

33
env:
44
CD_DETECTOR_EXPERIMENTS: 1
5+
PipReportSkipFallbackOnFailure: "true"
6+
PIP_INDEX_URL: "https://pypi.python.org/simple"
57

68
on:
79
push:

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ This is similar to Codespaces:
8585
1. Make sure you meet [the requirements](https://code.visualstudio.com/docs/remote/containers#_getting-started) and follow the installation steps for DevContainers in VS Code
8686
1. `git clone https://github.com/microsoft/component-detection`
8787
1. Open this repo in VS Code
88-
1. A notification should popup to reopen the workspace in the container. If it doesn't, open the [`Command Palette`](https://code.visualstudio.com/docs/getstarted/tips-and-tricks#_command-palette) and type `Remote-Containers: Reopen in Container`.
88+
1. A notification should popup to reopen the workspace in the container. If it doesn't, open the [`Command Palette`](https://code.visualstudio.com/docs/getstarted/tips-and-tricks#_command-palette) and type `Dev Containers: Reopen in Container`.
8989

9090
### Community Meetings
9191

src/Microsoft.ComponentDetection.Contracts/FileComponentDetectorWithCleanup.cs

Lines changed: 69 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -56,80 +56,80 @@ protected async Task WithCleanupAsync(
5656
// determining the files that exist as there will be no subsequent cleanup process.
5757
if (this.FileUtilityService == null
5858
|| this.DirectoryUtilityService == null
59-
|| !this.TryGetCleanupFileDirectory(processRequest, out var fileParentDirectory))
59+
|| !this.TryGetCleanupFileDirectory(processRequest, out var fileParentDirectory)
60+
|| !cleanupCreatedFiles)
6061
{
6162
await process(processRequest, detectorArgs, cancellationToken).ConfigureAwait(false);
6263
return;
6364
}
6465

6566
// Get the files and directories that match the cleanup pattern and exist before the process runs.
66-
var (preExistingFiles, preExistingDirs) = this.DirectoryUtilityService.GetFilesAndDirectories(fileParentDirectory, this.CleanupPatterns, DefaultCleanDepth);
67-
try
67+
var (preSuccess, preExistingFiles, preExistingDirs) = this.TryGetFilesAndDirectories(fileParentDirectory, this.CleanupPatterns, DefaultCleanDepth);
68+
69+
await process(processRequest, detectorArgs, cancellationToken).ConfigureAwait(false);
70+
if (!preSuccess)
6871
{
69-
await process(processRequest, detectorArgs, cancellationToken).ConfigureAwait(false);
72+
// return early if we failed to get the pre-existing files and directories, since no need for cleanup
73+
return;
7074
}
71-
finally
75+
76+
// Ensure that only one cleanup process is running at a time, helping to prevent conflicts
77+
await this.cleanupSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
78+
79+
try
7280
{
73-
// Ensure that only one cleanup process is running at a time, helping to prevent conflicts
74-
await this.cleanupSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
81+
// Clean up any new files or directories created during the scan that match the clean up patterns.
82+
var (postSuccess, latestFiles, latestDirs) = this.TryGetFilesAndDirectories(fileParentDirectory, this.CleanupPatterns, DefaultCleanDepth);
83+
if (!postSuccess)
84+
{
85+
// return early if we failed to get the latest files and directories, since we will not be able
86+
// to determine what to clean up
87+
return;
88+
}
7589

76-
try
90+
var createdFiles = latestFiles.Except(preExistingFiles).ToList();
91+
var createdDirs = latestDirs.Except(preExistingDirs).ToList();
92+
93+
foreach (var createdDir in createdDirs)
7794
{
78-
// Clean up any new files or directories created during the scan that match the clean up patterns.
79-
// If the cleanupCreatedFiles flag is set to false, this will be a dry run and will just log the files that it would clean.
80-
var dryRun = !cleanupCreatedFiles;
81-
var dryRunStr = dryRun ? "[DRYRUN] " : string.Empty;
82-
var (latestFiles, latestDirs) = this.DirectoryUtilityService.GetFilesAndDirectories(fileParentDirectory, this.CleanupPatterns, DefaultCleanDepth);
83-
var createdFiles = latestFiles.Except(preExistingFiles).ToList();
84-
var createdDirs = latestDirs.Except(preExistingDirs).ToList();
85-
86-
foreach (var createdDir in createdDirs)
95+
if (createdDir is null || !this.DirectoryUtilityService.Exists(createdDir))
8796
{
88-
if (createdDir is null || !this.DirectoryUtilityService.Exists(createdDir))
89-
{
90-
continue;
91-
}
92-
93-
try
94-
{
95-
this.Logger.LogDebug("{DryRun}Cleaning up directory {Dir}", dryRunStr, createdDir);
96-
if (!dryRun)
97-
{
98-
this.DirectoryUtilityService.Delete(createdDir, true);
99-
}
100-
}
101-
catch (Exception e)
102-
{
103-
this.Logger.LogDebug(e, "{DryRun}Failed to delete directory {Dir}", dryRunStr, createdDir);
104-
}
97+
continue;
10598
}
10699

107-
foreach (var createdFile in createdFiles)
100+
try
101+
{
102+
this.Logger.LogDebug("Cleaning up directory {Dir}", createdDir);
103+
this.DirectoryUtilityService.Delete(createdDir, true);
104+
}
105+
catch (Exception e)
108106
{
109-
if (createdFile is null || !this.FileUtilityService.Exists(createdFile))
110-
{
111-
continue;
112-
}
113-
114-
try
115-
{
116-
this.Logger.LogDebug("{DryRun}Cleaning up file {File}", dryRunStr, createdFile);
117-
if (!dryRun)
118-
{
119-
this.FileUtilityService.Delete(createdFile);
120-
}
121-
}
122-
catch (Exception e)
123-
{
124-
this.Logger.LogDebug(e, "{DryRun}Failed to delete file {File}", dryRunStr, createdFile);
125-
}
107+
this.Logger.LogDebug(e, "Failed to delete directory {Dir}", createdDir);
126108
}
127109
}
128-
finally
110+
111+
foreach (var createdFile in createdFiles)
129112
{
130-
_ = this.cleanupSemaphore.Release();
113+
if (createdFile is null || !this.FileUtilityService.Exists(createdFile))
114+
{
115+
continue;
116+
}
117+
118+
try
119+
{
120+
this.Logger.LogDebug("Cleaning up file {File}", createdFile);
121+
this.FileUtilityService.Delete(createdFile);
122+
}
123+
catch (Exception e)
124+
{
125+
this.Logger.LogDebug(e, "Failed to delete file {File}", createdFile);
126+
}
131127
}
132128
}
129+
finally
130+
{
131+
_ = this.cleanupSemaphore.Release();
132+
}
133133
}
134134

135135
protected override async Task OnFileFoundAsync(ProcessRequest processRequest, IDictionary<string, string> detectorArgs, bool cleanupCreatedFiles, CancellationToken cancellationToken = default) =>
@@ -151,4 +151,19 @@ private bool TryGetCleanupFileDirectory(ProcessRequest processRequest, out strin
151151

152152
return false;
153153
}
154+
155+
private (bool Success, HashSet<string> Files, HashSet<string> Directories) TryGetFilesAndDirectories(string root, IList<string> patterns, int depth)
156+
{
157+
try
158+
{
159+
var (files, directories) = this.DirectoryUtilityService.GetFilesAndDirectories(root, patterns, depth);
160+
return (true, files, directories);
161+
}
162+
catch (UnauthorizedAccessException e)
163+
{
164+
// log and return false if we are unauthorized to get files and directories
165+
this.Logger.LogDebug(e, "Unauthorized to get files and directories for {Root}", root);
166+
return (false, new HashSet<string>(), new HashSet<string>());
167+
}
168+
}
154169
}

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

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ namespace Microsoft.ComponentDetection.Detectors.NuGet;
77
using System.IO;
88
using System.Linq;
99
using global::NuGet.Frameworks;
10+
using global::NuGet.Packaging.Core;
11+
using global::NuGet.ProjectModel;
1012
using global::NuGet.Versioning;
1113

1214
/// <summary>
@@ -73,7 +75,7 @@ internal static void Register(params FrameworkPackages[] toRegister)
7375
}
7476
}
7577

76-
public static FrameworkPackages[] GetFrameworkPackages(NuGetFramework framework, string[] frameworkReferences)
78+
public static FrameworkPackages[] GetFrameworkPackages(NuGetFramework framework, string[] frameworkReferences, LockFileTarget lockFileTarget)
7779
{
7880
var frameworkPackages = new List<FrameworkPackages>();
7981

@@ -102,9 +104,64 @@ public static FrameworkPackages[] GetFrameworkPackages(NuGetFramework framework,
102104
}
103105
}
104106

107+
frameworkPackages.AddRange(GetLegacyFrameworkPackagesFromPlatformPackages(framework, lockFileTarget));
108+
105109
return frameworkPackages.ToArray();
106110
}
107111

112+
private static IEnumerable<FrameworkPackages> GetLegacyFrameworkPackagesFromPlatformPackages(NuGetFramework framework, LockFileTarget lockFileTarget)
113+
{
114+
if (framework.Framework == FrameworkConstants.FrameworkIdentifiers.NetCoreApp && framework.Version.Major < 3)
115+
{
116+
// For .NETCore 1.x (all frameworks) and 2.x (ASP.NET Core) the $(MicrosoftNETPlatformLibrary) property specified the framework package of the project.
117+
// This package and all its dependencies were excluded from copy to the output directory for framework deepndent apps.
118+
// See https://github.com/dotnet/sdk/blob/b3d6acae421815e90c74ddb631e426290348651c/src/Tasks/Microsoft.NET.Build.Tasks/ResolvePackageAssets.cs#L1882-L1898
119+
// We can't know from the assets file what the value of MicrosoftNETPlatformLibrary was, nor if an app was self-contained or not.
120+
// To avoid false positives, and since these frameworks are no longer supported, we'll just assume that all platform packages are framework,
121+
// and that the app is framework-dependent.
122+
// This is consistent with the old behavior of the old NuGet Detector.
123+
var lookup = lockFileTarget.Libraries.ToDictionary(l => l.Name, l => l, StringComparer.OrdinalIgnoreCase);
124+
string[] platformPackageNames = [
125+
FrameworkNames.NetCoreApp, // Default platform package for .NET Core 1.x and 2.x https://github.com/dotnet/sdk/blob/516dcf4a3bcf52ac3dce2452ea15ddd5cf057300/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.targets#L519
126+
FrameworkNames.AspNetCoreApp, // ASP.NET platform package for .NET Core 2.x https://github.com/dotnet/aspnetcore/blob/ac66280fe9024bdd686354e342fcdfb3409597f7/src/Microsoft.AspNetCore.App/build/netcoreapp2.1/Microsoft.AspNetCore.App.targets#L10
127+
"Microsoft.AspNetCore.All", // Alternate ASP.NET platform package for .NET Core 2.x https://github.com/dotnet/aspnetcore/blob/ac66280fe9024bdd686354e342fcdfb3409597f7/src/Microsoft.AspNetCore.All/build/netcoreapp2.1/Microsoft.AspNetCore.All.targets#L10
128+
129+
// ASP.NET did not have platform package / shared framework for .NET Core 1.x - it was app-local only
130+
];
131+
132+
foreach (var platformPackageName in platformPackageNames)
133+
{
134+
if (lookup.TryGetValue(platformPackageName, out var platformLibrary))
135+
{
136+
var frameworkPackagesFromPlatformPackage = new FrameworkPackages(framework, platformPackageName);
137+
138+
frameworkPackagesFromPlatformPackage.Packages.Add(platformLibrary.Name, platformLibrary.Version);
139+
140+
CollectDependencies(platformLibrary.Dependencies);
141+
142+
yield return frameworkPackagesFromPlatformPackage;
143+
144+
// recursively include dependencies, so long as they were not upgraded by some other reference
145+
void CollectDependencies(IEnumerable<PackageDependency> dependencies)
146+
{
147+
foreach (var dependency in dependencies)
148+
{
149+
if (lookup.TryGetValue(dependency.Id, out var library) &&
150+
library.Version.Equals(dependency.VersionRange.MinVersion))
151+
{
152+
// if this is the first time we add the package, add its dependencies as well
153+
if (frameworkPackagesFromPlatformPackage.Packages.TryAdd(library.Name, library.Version))
154+
{
155+
CollectDependencies(library.Dependencies);
156+
}
157+
}
158+
}
159+
}
160+
}
161+
}
162+
}
163+
}
164+
108165
private static FrameworkPackages LoadFrameworkPackagesFromPack(NuGetFramework framework, string frameworkName)
109166
{
110167
if (framework is null || framework.Framework != FrameworkConstants.FrameworkIdentifiers.NetCoreApp)

0 commit comments

Comments
 (0)