diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
deleted file mode 100644
index a1c52fbc..00000000
--- a/.devcontainer/Dockerfile
+++ /dev/null
@@ -1,12 +0,0 @@
-FROM ubuntu:20.04
-
-RUN apt-get update \
- && apt-get install -y \
- wget \
- apt-transport-https \
- && wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb \
- && dpkg -i packages-microsoft-prod.deb \
- && apt-get update \
- && apt-get install -y dotnet-sdk-2.1 \
- && apt-get install -y dotnet-sdk-3.1 \
- && rm -rf /var/lib/apt/lists/*
diff --git a/.devcontainer/Ubuntu22.04/Dockerfile b/.devcontainer/Ubuntu22.04/Dockerfile
new file mode 100644
index 00000000..b153ad56
--- /dev/null
+++ b/.devcontainer/Ubuntu22.04/Dockerfile
@@ -0,0 +1,8 @@
+FROM ubuntu:22.04
+
+RUN apt-get install -y --no-install-recommends wget=2.0.1
+RUN apt-get install -y --no-install-recommends apt-transport-https=2.5.6
+RUN curl -o ./packages-microsoft-prod.deb https://packages.microsoft.com/config/ubuntu/22.04/packages-microsoft-prod.deb
+RUN dpkg -i packages-microsoft-prod.deb
+RUN apt-get install -y --no-install-recommends dotnet-sdk-7.0=7.0
+RUN rm -rf /var/lib/apt/lists/*
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index f38a279f..8c43a082 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -1,7 +1,7 @@
{
"name": "devcontainer",
"build": {
- "dockerfile": "Dockerfile",
+ "dockerfile": "Ubuntu22.04/Dockerfile",
"context": ".."
},
"extensions": [
diff --git a/.github/workflows/dotnetcore.yml b/.github/workflows/dotnetcore.yml
index 5327e90f..066bb60e 100644
--- a/.github/workflows/dotnetcore.yml
+++ b/.github/workflows/dotnetcore.yml
@@ -16,15 +16,12 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- - uses: actions/checkout@v3.1.0
- - name: Setup dotnet 3.1
+ - uses: actions/checkout@v3.5.2
+ - name: Setup dotnet
uses: actions/setup-dotnet@v3.0.3
with:
- dotnet-version: '3.1.x'
- - name: Setup dotnet 6
- uses: actions/setup-dotnet@v3.0.3
- with:
- dotnet-version: '6.x'
+ dotnet-version: |
+ 7.x
- name: Build
run: dotnet build /WarnAsError
@@ -46,15 +43,15 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
- framework: ['netcoreapp3.1','net6.0']
+ framework: ['net6.0','net7.0']
timeout-minutes: 30
-
+
steps:
- - uses: actions/checkout@v3.1.0
- - name: Setup dotnet 3.1
+ - uses: actions/checkout@v3.5.2
+ - name: Setup dotnet 7
uses: actions/setup-dotnet@v3.0.3
with:
- dotnet-version: '3.1.x'
+ dotnet-version: '7.x'
- name: Setup dotnet 6
uses: actions/setup-dotnet@v3.0.3
with:
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 27d2ce64..4358f279 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -8,7 +8,7 @@
#
# For an example commit browse to
# https://github.com/CycloneDX/cyclonedx-dotnet/commit/d110af854371374460430bb8438225a7d7a84274.
-#
+#
# The resulting release is here
# https://github.com/CycloneDX/cyclonedx-dotnet/releases/tag/v1.0.0.
#
@@ -28,19 +28,16 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- - uses: actions/checkout@v3.1.0
- - name: Setup dotnet 3.1
- uses: actions/setup-dotnet@v3.0.3
- with:
- dotnet-version: '3.1.x'
- - name: Setup dotnet 6
+ - uses: actions/checkout@v3.5.2
+ - name: Setup dotnet
uses: actions/setup-dotnet@v3.0.3
with:
- dotnet-version: '6.x'
-
+ dotnet-version: |
+ 7.x
+
# The tests should have already been run during the PR workflow, so this is really just a sanity check
- name: Tests
- run: dotnet test --framework net6.0
+ run: dotnet test --framework net7.0
# Build and package everything, including the Docker image
- name: Package release
diff --git a/.gitpod.yml b/.gitpod.yml
index 8f286a18..a5e0d30b 100644
--- a/.gitpod.yml
+++ b/.gitpod.yml
@@ -8,9 +8,8 @@ tasks:
wget --output-document="$DOTNET_ROOT/dotnet-install.sh" https://dot.net/v1/dotnet-install.sh
chmod +x "$DOTNET_ROOT/dotnet-install.sh"
"$DOTNET_ROOT/dotnet-install.sh" --channel 2.1 --install-dir "$DOTNET_ROOT"
- "$DOTNET_ROOT/dotnet-install.sh" --channel 3.1 --install-dir "$DOTNET_ROOT"
- "$DOTNET_ROOT/dotnet-install.sh" --channel 5.0 --install-dir "$DOTNET_ROOT"
"$DOTNET_ROOT/dotnet-install.sh" --channel 6.0 --install-dir "$DOTNET_ROOT"
+ "$DOTNET_ROOT/dotnet-install.sh" --channel 7.0 --install-dir "$DOTNET_ROOT"
dotnet tool install --global dotnet-reportgenerator-globaltool
dotnet restore
diff --git a/CycloneDX.Tests/CycloneDX.Tests.csproj b/CycloneDX.Tests/CycloneDX.Tests.csproj
index 9828a6bd..9e42244f 100644
--- a/CycloneDX.Tests/CycloneDX.Tests.csproj
+++ b/CycloneDX.Tests/CycloneDX.Tests.csproj
@@ -1,28 +1,29 @@
- net6.0;netcoreapp3.1
true
false
+ net7.0;net6.0
+ latest
-
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
-
-
-
-
-
-
+
+
+
+
+
+
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
diff --git a/CycloneDX.Tests/NugetV3ServiceTests.cs b/CycloneDX.Tests/NugetV3ServiceTests.cs
index 9ead85b6..4f006ef7 100644
--- a/CycloneDX.Tests/NugetV3ServiceTests.cs
+++ b/CycloneDX.Tests/NugetV3ServiceTests.cs
@@ -80,37 +80,52 @@ public async Task GetComponent_FromCachedNuspecFile_ReturnsComponent()
Assert.Equal("testpackage", component.Name);
}
- [Fact]
- public async Task GetComponent_FromCachedNugetHashFile_ReturnsComponentWithHash()
+ public static IEnumerable
diff --git a/CycloneDX/Interfaces/IAssetFileReader.cs b/CycloneDX/Interfaces/IAssetFileReader.cs
index ce27b9f6..84f46d62 100644
--- a/CycloneDX/Interfaces/IAssetFileReader.cs
+++ b/CycloneDX/Interfaces/IAssetFileReader.cs
@@ -15,6 +15,7 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) OWASP Foundation. All Rights Reserved.
+using System.IO;
using NuGet.ProjectModel;
namespace CycloneDX.Interfaces
@@ -22,5 +23,9 @@ namespace CycloneDX.Interfaces
public interface IAssetFileReader
{
LockFile Read(string filePath);
+ string ReadAllText(string filePath)
+ {
+ return File.ReadAllText(filePath);
+ }
}
}
diff --git a/CycloneDX/Interfaces/IJsonDocs .cs b/CycloneDX/Interfaces/IJsonDocs .cs
new file mode 100644
index 00000000..38e16305
--- /dev/null
+++ b/CycloneDX/Interfaces/IJsonDocs .cs
@@ -0,0 +1,27 @@
+// This file is part of CycloneDX Tool for .NET
+//
+// Licensed under the Apache License, Version 2.0 (the “License”);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an “AS IS” BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) OWASP Foundation. All Rights Reserved.
+
+using System.Text.Json;
+
+namespace CycloneDX.Interfaces
+{
+ public interface IJsonDocs
+ {
+ public JsonDocument Parse(string json);
+
+ }
+}
diff --git a/CycloneDX/Interfaces/IProjectAssetsFileService.cs b/CycloneDX/Interfaces/IProjectAssetsFileService.cs
index 9900c8e3..732fd974 100644
--- a/CycloneDX/Interfaces/IProjectAssetsFileService.cs
+++ b/CycloneDX/Interfaces/IProjectAssetsFileService.cs
@@ -22,6 +22,6 @@ namespace CycloneDX.Interfaces
{
public interface IProjectAssetsFileService
{
- HashSet GetNugetPackages(string projectFilePath, string projectAssetsFilePath, bool IsTestProject);
+ HashSet GetNugetPackages(string projectFilePath, string projectAssetsFilePath, bool IsTestProject, bool excludeDev);
}
}
diff --git a/CycloneDX/Interfaces/IProjectFileService.cs b/CycloneDX/Interfaces/IProjectFileService.cs
index 91267138..9b56e8eb 100755
--- a/CycloneDX/Interfaces/IProjectFileService.cs
+++ b/CycloneDX/Interfaces/IProjectFileService.cs
@@ -24,8 +24,8 @@ namespace CycloneDX.Interfaces
public interface IProjectFileService
{
bool DisablePackageRestore { get; set; }
- Task> GetProjectNugetPackagesAsync(string projectFilePath, string baseIntermediateOutputPath, bool excludeTestProjects, string framework, string runtime);
- Task> RecursivelyGetProjectNugetPackagesAsync(string projectFilePath, string baseIntermediateOutputPath, bool excludeTestProjects, string framework, string runtime);
+ Task> GetProjectNugetPackagesAsync(string projectFilePath, string baseIntermediateOutputPath, bool excludeTestProjects, bool excludeDev, string framework, string runtime);
+ Task> RecursivelyGetProjectNugetPackagesAsync(string projectFilePath, string baseIntermediateOutputPath, bool excludeTestProjects, bool excludeDev, string framework, string runtime);
Task> GetProjectReferencesAsync(string projectFilePath);
Task> RecursivelyGetProjectReferencesAsync(string projectFilePath);
}
diff --git a/CycloneDX/Interfaces/ISolutionFileService.cs b/CycloneDX/Interfaces/ISolutionFileService.cs
index c06b0782..3690e729 100755
--- a/CycloneDX/Interfaces/ISolutionFileService.cs
+++ b/CycloneDX/Interfaces/ISolutionFileService.cs
@@ -24,6 +24,6 @@ namespace CycloneDX.Interfaces
public interface ISolutionFileService
{
Task> GetSolutionProjectReferencesAsync(string solutionFilePath);
- Task> GetSolutionNugetPackages(string solutionFilePath, string baseIntermediateOutputPath, bool excludeTestProjects, string framework, string runtime);
+ Task> GetSolutionNugetPackages(string solutionFilePath, string baseIntermediateOutputPath, bool excludeTestProjects, bool excludeDev, string framework, string runtime);
}
}
diff --git a/CycloneDX/Models/NugetPackage.cs b/CycloneDX/Models/NugetPackage.cs
index 4fcdf47e..b3dc0d79 100644
--- a/CycloneDX/Models/NugetPackage.cs
+++ b/CycloneDX/Models/NugetPackage.cs
@@ -27,6 +27,7 @@ public class NugetPackage : IComparable
public string Name { get; set; }
public string Version { get; set; }
public bool IsDirectReference { get; set; }
+ public bool IsDevDependency { get; set; }
public Component.ComponentScope? Scope { get; set; }
public Dictionary Dependencies { get; set; } //key: name ~ value: version
diff --git a/CycloneDX/Program.cs b/CycloneDX/Program.cs
index 8f402926..aadd888e 100755
--- a/CycloneDX/Program.cs
+++ b/CycloneDX/Program.cs
@@ -240,17 +240,17 @@ async Task OnExecuteAsync(CommandLineApplication app) {
{
if (SolutionOrProjectFile.ToLowerInvariant().EndsWith(".sln", StringComparison.OrdinalIgnoreCase))
{
- packages = await solutionFileService.GetSolutionNugetPackages(fullSolutionOrProjectFilePath, baseIntermediateOutputPath, excludetestprojects, framework, runtime).ConfigureAwait(false);
+ packages = await solutionFileService.GetSolutionNugetPackages(fullSolutionOrProjectFilePath, baseIntermediateOutputPath, excludetestprojects, excludeDev, framework, runtime).ConfigureAwait(false);
topLevelComponent.Name = fileSystem.Path.GetFileNameWithoutExtension(SolutionOrProjectFile);
}
else if (Utils.IsSupportedProjectType(SolutionOrProjectFile) && scanProjectReferences)
{
- packages = await projectFileService.RecursivelyGetProjectNugetPackagesAsync(fullSolutionOrProjectFilePath, baseIntermediateOutputPath, excludetestprojects, framework, runtime).ConfigureAwait(false);
+ packages = await projectFileService.RecursivelyGetProjectNugetPackagesAsync(fullSolutionOrProjectFilePath, baseIntermediateOutputPath, excludetestprojects, excludeDev, framework, runtime).ConfigureAwait(false);
topLevelComponent.Name = fileSystem.Path.GetFileNameWithoutExtension(SolutionOrProjectFile);
}
else if (Utils.IsSupportedProjectType(SolutionOrProjectFile))
{
- packages = await projectFileService.GetProjectNugetPackagesAsync(fullSolutionOrProjectFilePath, baseIntermediateOutputPath, excludetestprojects, framework, runtime).ConfigureAwait(false);
+ packages = await projectFileService.GetProjectNugetPackagesAsync(fullSolutionOrProjectFilePath, baseIntermediateOutputPath, excludetestprojects, excludeDev, framework, runtime).ConfigureAwait(false);
topLevelComponent.Name = fileSystem.Path.GetFileNameWithoutExtension(SolutionOrProjectFile);
}
else if (Program.fileSystem.Path.GetFileName(SolutionOrProjectFile).ToLowerInvariant().Equals("packages.config", StringComparison.OrdinalIgnoreCase))
diff --git a/CycloneDX/Services/JsonDocs.cs b/CycloneDX/Services/JsonDocs.cs
new file mode 100644
index 00000000..043fe4e8
--- /dev/null
+++ b/CycloneDX/Services/JsonDocs.cs
@@ -0,0 +1,32 @@
+// This file is part of CycloneDX Tool for .NET
+//
+// Licensed under the Apache License, Version 2.0 (the “License”);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an “AS IS” BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) OWASP Foundation. All Rights Reserved.
+
+using System.Text.Json;
+using CycloneDX.Interfaces;
+
+namespace CycloneDX.Services
+{
+ public class JsonDocs : IJsonDocs
+ {
+
+ public JsonDocument Parse(string json)
+ {
+ return JsonDocument.Parse(json);
+
+ }
+ }
+}
diff --git a/CycloneDX/Services/NugetV3Service.cs b/CycloneDX/Services/NugetV3Service.cs
index 11d0fda5..4dde3c55 100644
--- a/CycloneDX/Services/NugetV3Service.cs
+++ b/CycloneDX/Services/NugetV3Service.cs
@@ -84,7 +84,7 @@ internal string GetCachedNuspecFilename(string name, string version)
foreach (var packageCachePath in _packageCachePaths)
{
- var currentDirectory = _fileSystem.Path.Combine(packageCachePath, lowerName, version);
+ var currentDirectory = _fileSystem.Path.Combine(packageCachePath, lowerName, NormalizeVersion(version));
var currentFilename = _fileSystem.Path.Combine(currentDirectory, lowerName + _nuspecExtension);
if (_fileSystem.File.Exists(currentFilename))
{
@@ -96,6 +96,24 @@ internal string GetCachedNuspecFilename(string name, string version)
return nuspecFilename;
}
+ ///
+ /// Normalize the version string according to
+ /// https://learn.microsoft.com/en-us/nuget/concepts/package-versioning#normalized-version-numbers
+ ///
+ private string NormalizeVersion(string version)
+ {
+ var separator = Math.Max(version.IndexOf('-'), version.IndexOf('+'));
+ var part1 = separator < 0 ? version : version.Substring(0, separator);
+ var part2 = separator < 0 ? string.Empty : version.Substring(separator);
+ if (Version.TryParse(part1, out var parsed) && parsed.Revision == 0)
+ {
+ part1 = parsed.ToString(3);
+ version = part1 + part2;
+ }
+
+ return version;
+ }
+
private SourceRepository SetupNugetRepository(NugetInputModel nugetInput)
{
if (nugetInput == null || string.IsNullOrEmpty(nugetInput.nugetFeedUrl) ||
@@ -153,9 +171,7 @@ public async Task GetComponentAsync(string name, string version, Comp
var component = SetupComponent(name, version, scope);
var nuspecFilename = GetCachedNuspecFilename(name, version);
-
var nuspecModel = await GetNuspec(name, version, nuspecFilename, resource).ConfigureAwait(false);
-
if (nuspecModel.hashBytes != null)
{
var hex = BitConverter.ToString(nuspecModel.hashBytes).Replace("-", string.Empty);
@@ -170,10 +186,11 @@ public async Task GetComponentAsync(string name, string version, Comp
var licenseMetadata = nuspecModel.nuspecReader.GetLicenseMetadata();
if (licenseMetadata != null && licenseMetadata.Type == LicenseType.Expression)
{
- Action licenseProcessor = delegate(NuGetLicense nugetLicense)
+ Action licenseProcessor = delegate (NuGetLicense nugetLicense)
{
var license = new License { Id = nugetLicense.Identifier, Name = nugetLicense.Identifier };
- component.Licenses = new List { new LicenseChoice { License = license } };
+ component.Licenses ??= new List();
+ component.Licenses.Add(new LicenseChoice { License = license });
};
licenseMetadata.LicenseExpression.OnEachLeafNode(licenseProcessor, null);
}
@@ -231,7 +248,8 @@ public async Task GetComponentAsync(string name, string version, Comp
{
var externalReference = new ExternalReference
{
- Type = ExternalReference.ExternalReferenceType.Website, Url = projectUrl
+ Type = ExternalReference.ExternalReferenceType.Website,
+ Url = projectUrl
};
component.ExternalReferences = new List { externalReference };
}
@@ -243,7 +261,8 @@ public async Task GetComponentAsync(string name, string version, Comp
{
var externalReference = new ExternalReference
{
- Type = ExternalReference.ExternalReferenceType.Vcs, Url = vcsUrl
+ Type = ExternalReference.ExternalReferenceType.Vcs,
+ Url = vcsUrl
};
if (null == component.ExternalReferences)
{
@@ -260,7 +279,7 @@ public async Task GetComponentAsync(string name, string version, Comp
private static Component SetupComponentProperties(Component component, NuspecModel nuspecModel)
{
- component.Publisher = nuspecModel.nuspecReader.GetAuthors();
+ component.Author = nuspecModel.nuspecReader.GetAuthors();
component.Copyright = nuspecModel.nuspecReader.GetCopyright();
// this prevents empty copyright values in the JSON BOM
if (string.IsNullOrEmpty(component.Copyright))
@@ -301,7 +320,6 @@ await resource.CopyNupkgToStreamAsync(name, packageVersion, packageStream, _sour
using PackageArchiveReader packageReader = new PackageArchiveReader(packageStream);
nuspecModel.nuspecReader = await packageReader.GetNuspecReaderAsync(_cancellationToken);
-
if (!_disableHashComputation)
{
nuspecModel.hashBytes = ComputeSha215Hash(packageStream);
@@ -322,8 +340,9 @@ await resource.CopyNupkgToStreamAsync(name, packageVersion, packageStream, _sour
// ├─..nupkg.sha512
// └─.nuspec
- string shaFilename = Path.ChangeExtension(nuspecFilename, version + _sha512Extension);
- string nupkgFilename = Path.ChangeExtension(nuspecFilename, version + _nupkgExtension);
+ var normalizedVersion = NormalizeVersion(version);
+ string shaFilename = Path.ChangeExtension(nuspecFilename, normalizedVersion + _sha512Extension);
+ string nupkgFilename = Path.ChangeExtension(nuspecFilename, normalizedVersion + _nupkgExtension);
if (_fileSystem.File.Exists(shaFilename))
{
diff --git a/CycloneDX/Services/ProjectAssetsFileService.cs b/CycloneDX/Services/ProjectAssetsFileService.cs
index 1b0f29b1..50e9ae9e 100644
--- a/CycloneDX/Services/ProjectAssetsFileService.cs
+++ b/CycloneDX/Services/ProjectAssetsFileService.cs
@@ -22,6 +22,8 @@
using System.Linq;
using CycloneDX.Interfaces;
using NuGet.Versioning;
+using NuGet.LibraryModel;
+using NuGet.ProjectModel;
namespace CycloneDX.Services
{
@@ -38,7 +40,7 @@ public ProjectAssetsFileService(IFileSystem fileSystem, IDotnetCommandService do
_assetFileReaderFactory = assetFileReaderFactory;
}
- public HashSet GetNugetPackages(string projectFilePath, string projectAssetsFilePath, bool isTestProject)
+ public HashSet GetNugetPackages(string projectFilePath, string projectAssetsFilePath, bool isTestProject, bool excludeDev)
{
var packages = new HashSet();
@@ -49,34 +51,27 @@ public HashSet GetNugetPackages(string projectFilePath, string pro
foreach (var targetRuntime in assetsFile.Targets)
{
- var directPackageDependencies = GetDirectPackageDependencies(targetRuntime.Name, projectFilePath);
var runtimePackages = new HashSet();
+ var targetFramework = assetsFile.PackageSpec.GetTargetFramework(targetRuntime.TargetFramework);
+ var dependencies = targetFramework.Dependencies;
+
foreach (var library in targetRuntime.Libraries.Where(lib => lib.Type != "project"))
{
+ var libs = dependencies.FirstOrDefault(ld => ld.Name.Equals(library.Name));
var package = new NugetPackage
{
Name = library.Name,
Version = library.Version.ToNormalizedString(),
Scope = Component.ComponentScope.Required,
Dependencies = new Dictionary(),
+ IsDevDependency = SetIsDevDependency(libs),
+ IsDirectReference = SetIsDirectReference(libs)
};
- var topLevelReferenceKey = (package.Name, package.Version);
- if (directPackageDependencies.Contains(topLevelReferenceKey))
- {
- package.IsDirectReference = true;
- }
+
// is this a test project dependency or only a development dependency
if (
isTestProject
- || (
- library.CompileTimeAssemblies.Count == 0
- && library.ContentFiles.Count == 0
- && library.EmbedAssemblies.Count == 0
- && library.FrameworkAssemblies.Count == 0
- && library.NativeLibraries.Count == 0
- && library.ResourceAssemblies.Count == 0
- && library.ToolsAssemblies.Count == 0
- )
+ || (package.IsDevDependency && excludeDev)
)
{
package.Scope = Component.ComponentScope.Excluded;
@@ -89,7 +84,7 @@ public HashSet GetNugetPackages(string projectFilePath, string pro
runtimePackages.Add(package);
}
- ResolveDependecyVersionRanges(runtimePackages);
+ ResolveDependencyVersionRanges(runtimePackages);
packages.UnionWith(runtimePackages);
}
@@ -97,58 +92,19 @@ public HashSet GetNugetPackages(string projectFilePath, string pro
return packages;
}
-
- // Future: Instead of invoking the dotnet CLI to get direct dependencies, once asset file version 3 is available through the Nuget library,
- // The direct dependencies could be retrieved from the asset file json path: .project.frameworks..dependencies
- private List<(string, string)> GetDirectPackageDependencies(string targetRuntime, string projectFilePath)
+ public bool SetIsDirectReference(LibraryDependency dependency)
{
- var directPackageDependencies = new List<(string, string)>();
- var framework = TargetFrameworkToAlias(targetRuntime);
- if (framework != null)
- {
- var output = _dotnetCommandService.Run($"list \"{projectFilePath}\" package --framework {framework}");
- var result = output.Success ? output.StdOut : null;
- if (result != null)
- {
- directPackageDependencies = result.Split('\r', '\n').Select(line => line.Trim())
- .Where(line => line.StartsWith(">", StringComparison.InvariantCulture))
- .Select(line => line.Split(' ', StringSplitOptions.RemoveEmptyEntries))
- .Where(parts => parts.Length == 4)
- .Select(parts => (parts[1], parts[3]))
- .ToList();
- }
- }
- return directPackageDependencies;
+ return dependency?.ReferenceType == LibraryDependencyReferenceType.Direct;
}
-
- ///
- /// Converts an asset file's target framework value into a csproj target framework value.
- ///
- /// Examples:
- /// .NetStandard,Version=V3.1 => netstandard3.1
- /// .NetCoreApp,Version=V3.1 => netcoreapp3.1
- /// netcoreapp3.1 => netcoreapp3.1
- /// net6.0 => net6.0
- ///
- private string TargetFrameworkToAlias(string target)
+ public bool SetIsDevDependency(LibraryDependency dependency)
{
- if (!string.IsNullOrEmpty(target))
- {
- target = target.ToLowerInvariant().TrimStart('.');
- var targetParts = target.Split(",version=v");
- if (targetParts.Length == 2)
- {
- return string.Join("", targetParts);
- }
- return targetParts[0];
- }
- return null;
+ return dependency != null && dependency.SuppressParent != LibraryIncludeFlagUtils.DefaultSuppressParent;
}
///
/// Updates all dependencies with version ranges to the version it was resolved to.
///
- private static void ResolveDependecyVersionRanges(HashSet runtimePackages)
+ private static void ResolveDependencyVersionRanges(HashSet runtimePackages)
{
var runtimePackagesLookup = runtimePackages.ToLookup(x => x.Name.ToLowerInvariant());
foreach (var runtimePackage in runtimePackages)
diff --git a/CycloneDX/Services/ProjectFileService.cs b/CycloneDX/Services/ProjectFileService.cs
index d1bf17bf..ac77d9c6 100755
--- a/CycloneDX/Services/ProjectFileService.cs
+++ b/CycloneDX/Services/ProjectFileService.cs
@@ -102,7 +102,7 @@ static internal String GetProjectProperty(string projectFilePath, string baseInt
///
///
///
- public async Task> GetProjectNugetPackagesAsync(string projectFilePath, string baseIntermediateOutputPath, bool excludeTestProjects, string framework, string runtime)
+ public async Task> GetProjectNugetPackagesAsync(string projectFilePath, string baseIntermediateOutputPath, bool excludeTestProjects, bool excludeDev, string framework, string runtime)
{
if (!_fileSystem.File.Exists(projectFilePath))
{
@@ -142,7 +142,7 @@ public async Task> GetProjectNugetPackagesAsync(string pro
{
Console.WriteLine($"File not found: \"{assetsFilename}\", \"{projectFilePath}\" ");
}
- var packages = _projectAssetsFileService.GetNugetPackages(projectFilePath, assetsFilename, isTestProject);
+ var packages = _projectAssetsFileService.GetNugetPackages(projectFilePath, assetsFilename, isTestProject, excludeDev);
// if there are no project file package references look for a packages.config
@@ -165,13 +165,13 @@ public async Task> GetProjectNugetPackagesAsync(string pro
///
///
///
- public async Task> RecursivelyGetProjectNugetPackagesAsync(string projectFilePath, string baseIntermediateOutputPath, bool excludeTestProjects, string framework, string runtime)
+ public async Task> RecursivelyGetProjectNugetPackagesAsync(string projectFilePath, string baseIntermediateOutputPath, bool excludeTestProjects, bool excludeDev, string framework, string runtime)
{
- var nugetPackages = await GetProjectNugetPackagesAsync(projectFilePath, baseIntermediateOutputPath, excludeTestProjects, framework, runtime).ConfigureAwait(false);
+ var nugetPackages = await GetProjectNugetPackagesAsync(projectFilePath, baseIntermediateOutputPath, excludeTestProjects, excludeDev, framework, runtime).ConfigureAwait(false);
var projectReferences = await RecursivelyGetProjectReferencesAsync(projectFilePath).ConfigureAwait(false);
foreach (var project in projectReferences)
{
- var projectNugetPackages = await GetProjectNugetPackagesAsync(project, baseIntermediateOutputPath, excludeTestProjects, framework, runtime).ConfigureAwait(false);
+ var projectNugetPackages = await GetProjectNugetPackagesAsync(project, baseIntermediateOutputPath, excludeTestProjects, excludeDev, framework, runtime).ConfigureAwait(false);
nugetPackages.UnionWith(projectNugetPackages);
}
return nugetPackages;
@@ -195,7 +195,7 @@ public async Task> GetProjectReferencesAsync(string projectFileP
Console.WriteLine(" Getting project references");
var projectReferences = new HashSet();
- var projectDirectory = _fileSystem.FileInfo.FromFileName(projectFilePath).Directory.FullName;
+ var projectDirectory = _fileSystem.FileInfo.New(projectFilePath).Directory.FullName;
using (StreamReader fileReader = _fileSystem.File.OpenText(projectFilePath))
{
@@ -240,7 +240,7 @@ public async Task> RecursivelyGetProjectReferencesAsync(string p
// Initialize the queue with the current project file
var files = new Queue();
- files.Enqueue(_fileSystem.FileInfo.FromFileName(projectFilePath).FullName);
+ files.Enqueue(_fileSystem.FileInfo.New(projectFilePath).FullName);
var visitedProjectFiles = new HashSet();
diff --git a/CycloneDX/Services/SolutionFileService.cs b/CycloneDX/Services/SolutionFileService.cs
index cf4f998f..3007778e 100755
--- a/CycloneDX/Services/SolutionFileService.cs
+++ b/CycloneDX/Services/SolutionFileService.cs
@@ -82,7 +82,7 @@ public async Task> GetSolutionProjectReferencesAsync(string solu
///
///
///
- public async Task> GetSolutionNugetPackages(string solutionFilePath, string baseIntermediateOutputPath, bool excludeTestProjects, string framework, string runtime)
+ public async Task> GetSolutionNugetPackages(string solutionFilePath, string baseIntermediateOutputPath, bool excludeTestProjects, bool excludeDev, string framework, string runtime)
{
if (!_fileSystem.File.Exists(solutionFilePath))
{
@@ -113,7 +113,7 @@ public async Task> GetSolutionNugetPackages(string solutio
foreach (var projectFilePath in projectQuery)
{
Console.WriteLine();
- var projectPackages = await _projectFileService.GetProjectNugetPackagesAsync(projectFilePath, baseIntermediateOutputPath, excludeTestProjects, framework, runtime).ConfigureAwait(false);
+ var projectPackages = await _projectFileService.GetProjectNugetPackagesAsync(projectFilePath, baseIntermediateOutputPath, excludeTestProjects, excludeDev, framework, runtime).ConfigureAwait(false);
directReferencePackages.UnionWith(projectPackages.Where(p => p.IsDirectReference));
packages.UnionWith(projectPackages);
}
diff --git a/Directory.Build.props b/Directory.Build.props
index cffe12cf..968b97c5 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -19,14 +19,9 @@
AllEnableByDefault
-
-
+ true
+
Steve Springett & Patrick Dwyer
diff --git a/Directory.Packages.props b/Directory.Packages.props
new file mode 100644
index 00000000..52499c36
--- /dev/null
+++ b/Directory.Packages.props
@@ -0,0 +1,27 @@
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Dockerfile b/Dockerfile
index 8afd6917..d0eaea6d 100755
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM mcr.microsoft.com/dotnet/sdk:6.0
+FROM mcr.microsoft.com/dotnet/sdk:7.0
ARG VERSION
COPY ./nupkgs /tmp/nupkgs/
@@ -6,4 +6,4 @@ RUN dotnet tool install --global CycloneDX --version ${VERSION} --add-source /tm
ln -s /root/.dotnet/tools/dotnet-CycloneDX /usr/bin/CycloneDX
ENTRYPOINT [ "CycloneDX" ]
-CMD [ "--help" ]
\ No newline at end of file
+CMD [ "--help" ]
diff --git a/README.md b/README.md
index 81297a01..b796f27c 100755
--- a/README.md
+++ b/README.md
@@ -13,14 +13,14 @@
The CycloneDX module for .NET creates a valid CycloneDX bill-of-material document containing an aggregate of all project dependencies. CycloneDX is a lightweight BOM specification that is easily created, human readable, and simple to parse.
This module runs on
-* .NET Core 3.1
-* .NET 6.0.
+* .NET 6.0
+* .NET 7.0
This module no longer runs on
-
* .NET Core 2.1
-* .NET5
-* see https://dotnet.microsoft.com/en-us/platform/support/policy/dotnet-core for more infomation
+* .NET Core 3.1
+* .NET 5.0
+* see https://dotnet.microsoft.com/en-us/platform/support/policy/dotnet-core for more information
## Usage
@@ -56,10 +56,12 @@ docker run cyclonedx/cyclonedx-dotnet [OPTIONS]
Usage: dotnet CycloneDX [options]
Arguments:
- path The path to a .sln, .csproj, .fsproj, .vbproj, or packages.config file or the path to a directory which will be recursively analyzed for packages.config files
+ path The path to a .sln, .csproj, .fsproj, .vbproj, or packages.config file or the path to a directory which will be recursively analyzed for packages.config files
Options:
-v|--version Output the tool version and exit
+ -tfm|--framework The target framework to use. If not defined, all will be aggregated.
+ -rt|--runtime The runtime to use. If not defined, all will be aggregated.
-o|--out The directory to write the BOM
-f|--filename Optionally provide a filename for the BOM (default: bom.xml or bom.json)
-j|--json Produce a JSON BOM instead of XML
@@ -86,7 +88,7 @@ Options:
-st|--set-type Override the default BOM metadata component type (defaults to application).
Allowed values are: Null, Application, Framework, Library, OperationSystem, Device, File, Container, Firmware.
Default value is: Null.
- -?|-h|--help Show help information.
+ -?|-h|--help Show help information.
```
#### Examples
diff --git a/semver.txt b/semver.txt
index 24ba9a38..dbe59006 100755
--- a/semver.txt
+++ b/semver.txt
@@ -1 +1 @@
-2.7.0
+2.8.1