Skip to content

Commit 95ee455

Browse files
mtsfoniconstruct agent
andauthored
Fix/metadata import overrides (#1041)
* fix: metadata import respects --set-name/version/type overrides (#817) - ReadMetaDataFromFile now accepts IFileSystem for testability - Metadata import now only copies Metadata section, preserving BOM spec version - SetMetadataComponentIfNecessary now accepts explicit override values - RunOptions.setType now defaults to Null (not Application) to distinguish 'user explicitly set' from default - Enable 3 previously-skipped tests for setName/setVersion/setType overrides * docs: add bom-metadata reference and update README metadata section * feat: use project file <Version> in BOM metadata when --set-version not provided (#954) * docs: update bom-metadata reference with project file version source * feat: check AssemblyVersion/ProjectVersion/PackageVersion as version fallbacks (#1006) --------- Co-authored-by: construct agent <agent@construct.local>
1 parent 8b71d7a commit 95ee455

13 files changed

Lines changed: 617 additions & 42 deletions

File tree

CycloneDX.Tests/CycloneDX.Tests.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,9 @@
141141
<None Update="FunctionalTests\TestcaseFiles\Issue-758.json">
142142
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
143143
</None>
144+
<None Update="FunctionalTests\TestcaseFiles\metadata.xml">
145+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
146+
</None>
144147
<None Update="FunctionalTests\TestcaseFiles\ProjectReferenceWithPackageReferenceWithTransitivePackage.json">
145148
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
146149
</None>

CycloneDX.Tests/FunctionalTests/FunctionalTestHelper.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ public static async Task<Bom> Test(RunOptions options, INugetServiceFactory nuge
133133
return runner.LastGeneratedBom;
134134
}
135135

136-
private const string CsprojContents =
136+
public const string CsprojContents =
137137
"<Project Sdk=\"Microsoft.NET.Sdk\">\n\n " +
138138
"<PropertyGroup>\n " +
139139
"<OutputType>Exe</OutputType>\n " +
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.IO.Abstractions.TestingHelpers;
5+
using System.Linq;
6+
using System.Threading.Tasks;
7+
using CycloneDX.Models;
8+
using Xunit;
9+
10+
namespace CycloneDX.Tests.FunctionalTests
11+
{
12+
public class MetaData
13+
{
14+
private MockFileSystem getMockFS()
15+
{
16+
return new MockFileSystem(new Dictionary<string, MockFileData>
17+
{
18+
{ MockUnixSupport.Path("c:/ProjectPath/obj/project.assets.json"),
19+
new MockFileData(
20+
File.ReadAllText(Path.Combine("FunctionalTests", "TestcaseFiles", "SimpleNET6.0Library.json"))) },
21+
{ MockUnixSupport.Path("c:/ProjectPath/Project.csproj"), new MockFileData(FunctionalTestHelper.CsprojContents) },
22+
{ MockUnixSupport.Path("c:/ProjectPath/metadata.xml"),
23+
new MockFileData(
24+
File.ReadAllText(Path.Combine("FunctionalTests", "TestcaseFiles", "metadata.xml"))) }
25+
});
26+
}
27+
28+
[Fact]
29+
public async Task ImportedMetaDataAreInBomOutput()
30+
{
31+
var options = new RunOptions
32+
{
33+
importMetadataPath = MockUnixSupport.Path("c:/ProjectPath/metadata.xml")
34+
};
35+
36+
var bom = await FunctionalTestHelper.Test(options, getMockFS());
37+
38+
Assert.Equal("CycloneDX", bom.Metadata.Component.Name);
39+
Assert.Equal("1.3.0", bom.Metadata.Component.Version);
40+
Assert.Equal(Component.Classification.Application, bom.Metadata.Component.Type);
41+
Assert.False(string.IsNullOrEmpty(bom.Metadata.Component.Description));
42+
Assert.Equal("Apache License 2.0", bom.Metadata.Component.Licenses.First().License.Name);
43+
Assert.Equal("Apache-2.0", bom.Metadata.Component.Licenses.First().License.Id);
44+
Assert.Equal("pkg:nuget/CycloneDX@1.3.0", bom.Metadata.Component.Purl);
45+
}
46+
47+
[Fact]
48+
public async Task IfNoMetadataIsImportedTimestampIsSetAutomatically()
49+
{
50+
var options = new RunOptions
51+
{
52+
};
53+
54+
var bom = await FunctionalTestHelper.Test(options, getMockFS());
55+
Assert.True(bom.Metadata.Timestamp.Value > DateTime.UtcNow.AddMinutes(-10));
56+
}
57+
58+
[Fact]
59+
public async Task IfMetadataWithoutTimestampIsImportedTimestampStillGetsSet()
60+
{
61+
var options = new RunOptions
62+
{
63+
importMetadataPath = MockUnixSupport.Path("c:/ProjectPath/metadata.xml")
64+
};
65+
66+
var bom = await FunctionalTestHelper.Test(options, getMockFS());
67+
Assert.True(bom.Metadata.Timestamp.Value > DateTime.UtcNow.AddMinutes(-10));
68+
}
69+
70+
[Fact]
71+
public async Task SetVersionOverwritesVersionWhenMetadataAreProvided()
72+
{
73+
var options = new RunOptions
74+
{
75+
importMetadataPath = MockUnixSupport.Path("c:/ProjectPath/metadata.xml"),
76+
setVersion = "3.0.4"
77+
78+
};
79+
80+
var bom = await FunctionalTestHelper.Test(options, getMockFS());
81+
82+
Assert.Equal("CycloneDX", bom.Metadata.Component.Name);
83+
Assert.Equal("3.0.4", bom.Metadata.Component.Version);
84+
Assert.Equal(Component.Classification.Application, bom.Metadata.Component.Type);
85+
Assert.False(string.IsNullOrEmpty(bom.Metadata.Component.Description));
86+
Assert.Equal("Apache License 2.0", bom.Metadata.Component.Licenses.First().License.Name);
87+
Assert.Equal("Apache-2.0", bom.Metadata.Component.Licenses.First().License.Id);
88+
Assert.Equal("pkg:nuget/CycloneDX@1.3.0", bom.Metadata.Component.Purl);
89+
}
90+
91+
[Fact]
92+
public async Task SetNameOverwritesNameWhenMetadataAreProvided()
93+
{
94+
var options = new RunOptions
95+
{
96+
importMetadataPath = MockUnixSupport.Path("c:/ProjectPath/metadata.xml"),
97+
setName = "Foo"
98+
99+
};
100+
101+
var bom = await FunctionalTestHelper.Test(options, getMockFS());
102+
103+
Assert.Equal("Foo", bom.Metadata.Component.Name);
104+
Assert.Equal("1.3.0", bom.Metadata.Component.Version);
105+
Assert.Equal(Component.Classification.Application, bom.Metadata.Component.Type);
106+
Assert.False(string.IsNullOrEmpty(bom.Metadata.Component.Description));
107+
Assert.Equal("Apache License 2.0", bom.Metadata.Component.Licenses.First().License.Name);
108+
Assert.Equal("Apache-2.0", bom.Metadata.Component.Licenses.First().License.Id);
109+
Assert.Equal("pkg:nuget/CycloneDX@1.3.0", bom.Metadata.Component.Purl);
110+
}
111+
112+
[Fact]
113+
public async Task SetTypeOverwritesTypeWhenMetadataAreProvided()
114+
{
115+
var options = new RunOptions
116+
{
117+
importMetadataPath = MockUnixSupport.Path("c:/ProjectPath/metadata.xml"),
118+
setType = Component.Classification.Container
119+
120+
};
121+
122+
var bom = await FunctionalTestHelper.Test(options, getMockFS());
123+
124+
Assert.Equal("CycloneDX", bom.Metadata.Component.Name);
125+
Assert.Equal("1.3.0", bom.Metadata.Component.Version);
126+
Assert.Equal(Component.Classification.Container, bom.Metadata.Component.Type);
127+
Assert.False(string.IsNullOrEmpty(bom.Metadata.Component.Description));
128+
Assert.Equal("Apache License 2.0", bom.Metadata.Component.Licenses.First().License.Name);
129+
Assert.Equal("Apache-2.0", bom.Metadata.Component.Licenses.First().License.Id);
130+
Assert.Equal("pkg:nuget/CycloneDX@1.3.0", bom.Metadata.Component.Purl);
131+
}
132+
}
133+
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// This file is part of CycloneDX Tool for .NET
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
//
15+
// SPDX-License-Identifier: Apache-2.0
16+
// Copyright (c) OWASP Foundation. All Rights Reserved.
17+
18+
using System.Collections.Generic;
19+
using System.IO.Abstractions.TestingHelpers;
20+
using System.Threading.Tasks;
21+
using CycloneDX.Models;
22+
using Xunit;
23+
using XFS = System.IO.Abstractions.TestingHelpers.MockUnixSupport;
24+
25+
namespace CycloneDX.Tests.FunctionalTests
26+
{
27+
public class ProjectVersionMetadataTest
28+
{
29+
[Fact]
30+
public async Task BomMetadataVersion_ShouldMatchProjectVersion()
31+
{
32+
var csproj = "<Project Sdk=\"Microsoft.NET.Sdk\">\n" +
33+
" <PropertyGroup>\n" +
34+
" <OutputType>Exe</OutputType>\n" +
35+
" <Version>2.1.3</Version>\n" +
36+
" </PropertyGroup>\n" +
37+
"</Project>\n";
38+
39+
var mockFileSystem = new MockFileSystem(new Dictionary<string, MockFileData>
40+
{
41+
{ XFS.Path("c:/ProjectPath/Project.csproj"), new MockFileData(csproj) },
42+
{ XFS.Path("c:/ProjectPath/obj/project.assets.json"), new MockFileData("{}") }
43+
});
44+
45+
var options = new RunOptions
46+
{
47+
SolutionOrProjectFile = XFS.Path("c:/ProjectPath/Project.csproj"),
48+
outputDirectory = XFS.Path("c:/ProjectPath/"),
49+
disablePackageRestore = true
50+
};
51+
52+
var bom = await FunctionalTestHelper.Test(options, mockFileSystem);
53+
Assert.Equal("2.1.3", bom.Metadata.Component.Version);
54+
}
55+
56+
[Fact]
57+
public async Task BomMetadataVersion_SetVersionFlagOverridesProjectVersion()
58+
{
59+
var csproj = "<Project Sdk=\"Microsoft.NET.Sdk\">\n" +
60+
" <PropertyGroup>\n" +
61+
" <OutputType>Exe</OutputType>\n" +
62+
" <Version>2.1.3</Version>\n" +
63+
" </PropertyGroup>\n" +
64+
"</Project>\n";
65+
66+
var mockFileSystem = new MockFileSystem(new Dictionary<string, MockFileData>
67+
{
68+
{ XFS.Path("c:/ProjectPath/Project.csproj"), new MockFileData(csproj) },
69+
{ XFS.Path("c:/ProjectPath/obj/project.assets.json"), new MockFileData("{}") }
70+
});
71+
72+
var options = new RunOptions
73+
{
74+
SolutionOrProjectFile = XFS.Path("c:/ProjectPath/Project.csproj"),
75+
outputDirectory = XFS.Path("c:/ProjectPath/"),
76+
disablePackageRestore = true,
77+
setVersion = "9.9.9"
78+
};
79+
80+
var bom = await FunctionalTestHelper.Test(options, mockFileSystem);
81+
Assert.Equal("9.9.9", bom.Metadata.Component.Version);
82+
}
83+
84+
[Fact]
85+
public async Task BomMetadataVersion_DefaultsTo000WhenNoVersionInProjectFile()
86+
{
87+
var csproj = "<Project Sdk=\"Microsoft.NET.Sdk\">\n" +
88+
" <PropertyGroup>\n" +
89+
" <OutputType>Exe</OutputType>\n" +
90+
" </PropertyGroup>\n" +
91+
"</Project>\n";
92+
93+
var mockFileSystem = new MockFileSystem(new Dictionary<string, MockFileData>
94+
{
95+
{ XFS.Path("c:/ProjectPath/Project.csproj"), new MockFileData(csproj) },
96+
{ XFS.Path("c:/ProjectPath/obj/project.assets.json"), new MockFileData("{}") }
97+
});
98+
99+
var options = new RunOptions
100+
{
101+
SolutionOrProjectFile = XFS.Path("c:/ProjectPath/Project.csproj"),
102+
outputDirectory = XFS.Path("c:/ProjectPath/"),
103+
disablePackageRestore = true
104+
};
105+
106+
var bom = await FunctionalTestHelper.Test(options, mockFileSystem);
107+
Assert.Equal("0.0.0", bom.Metadata.Component.Version);
108+
}
109+
}
110+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<bom xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" serialNumber="urn:uuid:087d0712-f591-4995-ba76-03f1c5c48884" version="1" xmlns="http://cyclonedx.org/schema/bom/1.5">
3+
<metadata>
4+
<component type="application" bom-ref="pkg:nuget/CycloneDX@1.3.0">
5+
<name>CycloneDX</name>
6+
<version>1.3.0</version>
7+
<description>
8+
<![CDATA[The [CycloneDX module](https://github.com/CycloneDX/cyclonedx-dotnet) 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.]]>
9+
</description>
10+
<licenses>
11+
<license>
12+
<name>Apache License 2.0</name>
13+
<id>Apache-2.0</id>
14+
</license>
15+
</licenses>
16+
<purl>pkg:nuget/CycloneDX@1.3.0</purl>
17+
</component>
18+
</metadata>
19+
</bom>

CycloneDX.Tests/ProgramTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
using System;
1919
using System.Collections.Generic;
2020
using System.IO;
21+
using System.IO.Abstractions;
2122
using System.IO.Abstractions.TestingHelpers;
2223
using System.Threading.Tasks;
2324
using CycloneDX.Interfaces;
@@ -237,7 +238,7 @@ public void CheckMetaDataTemplate()
237238
{
238239
var bom = new Bom();
239240
string resourcePath = Path.Join(AppContext.BaseDirectory, "Resources", "metadata");
240-
bom = Runner.ReadMetaDataFromFile(bom, Path.Join(resourcePath, "cycloneDX-metadata-template.xml"));
241+
bom = Runner.ReadMetaDataFromFile(bom, Path.Join(resourcePath, "cycloneDX-metadata-template.xml"), new FileSystem());
241242
Assert.NotNull(bom.Metadata);
242243
Assert.Matches("CycloneDX", bom.Metadata.Component.Name);
243244
Assert.NotEmpty(bom.Metadata.Tools.Tools);

0 commit comments

Comments
 (0)