up
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "jq",
|
||||
"versions": {
|
||||
"stable": "1.7"
|
||||
},
|
||||
"revision": 0,
|
||||
"tap": "homebrew/core",
|
||||
"poured_from_bottle": true,
|
||||
"time": 1700000000,
|
||||
"installed_as_dependency": false,
|
||||
"installed_on_request": true,
|
||||
"runtime_dependencies": [],
|
||||
"build_dependencies": [],
|
||||
"source": {
|
||||
"url": "https://github.com/jqlang/jq/releases/download/jq-1.7/jq-1.7.tar.gz",
|
||||
"checksum": "sha256:jq17hash"
|
||||
},
|
||||
"desc": "Lightweight and flexible command-line JSON processor",
|
||||
"homepage": "https://jqlang.github.io/jq/",
|
||||
"license": "MIT",
|
||||
"arch": "arm64"
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "openssl@3",
|
||||
"versions": {
|
||||
"stable": "3.1.0"
|
||||
},
|
||||
"revision": 0,
|
||||
"tap": "homebrew/core",
|
||||
"poured_from_bottle": true,
|
||||
"time": 1699000000,
|
||||
"installed_as_dependency": false,
|
||||
"installed_on_request": true,
|
||||
"runtime_dependencies": [
|
||||
{
|
||||
"full_name": "ca-certificates",
|
||||
"version": "2023-01-10"
|
||||
}
|
||||
],
|
||||
"build_dependencies": [],
|
||||
"source": {
|
||||
"url": "https://www.openssl.org/source/openssl-3.1.0.tar.gz",
|
||||
"checksum": "sha256:aafde89dd0e91c3d0e87c4b4e3f4d4c9f8f5a6e2b3d4c5a6f7e8d9c0a1b2c3d4e5"
|
||||
},
|
||||
"desc": "Cryptography and SSL/TLS Toolkit",
|
||||
"homepage": "https://openssl.org/",
|
||||
"license": "Apache-2.0",
|
||||
"arch": "x86_64"
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "wget",
|
||||
"versions": {
|
||||
"stable": "1.21.4"
|
||||
},
|
||||
"revision": 1,
|
||||
"tap": "homebrew/core",
|
||||
"poured_from_bottle": true,
|
||||
"time": 1698500000,
|
||||
"installed_as_dependency": true,
|
||||
"installed_on_request": false,
|
||||
"runtime_dependencies": [
|
||||
{
|
||||
"full_name": "openssl@3",
|
||||
"version": "3.1.0"
|
||||
},
|
||||
{
|
||||
"full_name": "gettext",
|
||||
"version": "0.21.1"
|
||||
}
|
||||
],
|
||||
"build_dependencies": [],
|
||||
"source": {
|
||||
"url": "https://ftp.gnu.org/gnu/wget/wget-1.21.4.tar.gz",
|
||||
"checksum": "sha256:abc123def456"
|
||||
},
|
||||
"desc": "Internet file retriever",
|
||||
"homepage": "https://www.gnu.org/software/wget/",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"arch": "x86_64"
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using StellaOps.Scanner.Analyzers.OS.Homebrew;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Scanner.Analyzers.OS.Homebrew.Tests;
|
||||
|
||||
public sealed class HomebrewPackageAnalyzerTests
|
||||
{
|
||||
private static readonly string FixturesRoot = Path.Combine(
|
||||
AppContext.BaseDirectory,
|
||||
"Fixtures");
|
||||
|
||||
private readonly HomebrewPackageAnalyzer _analyzer;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public HomebrewPackageAnalyzerTests()
|
||||
{
|
||||
_logger = NullLoggerFactory.Instance.CreateLogger<HomebrewPackageAnalyzer>();
|
||||
_analyzer = new HomebrewPackageAnalyzer((ILogger<HomebrewPackageAnalyzer>)_logger);
|
||||
}
|
||||
|
||||
private OSPackageAnalyzerContext CreateContext(string rootPath)
|
||||
{
|
||||
return new OSPackageAnalyzerContext(
|
||||
rootPath,
|
||||
workspacePath: null,
|
||||
TimeProvider.System,
|
||||
_logger);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AnalyzerId_ReturnsHomebrew()
|
||||
{
|
||||
Assert.Equal("homebrew", _analyzer.AnalyzerId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AnalyzeAsync_WithValidCellar_ReturnsPackages()
|
||||
{
|
||||
// Arrange
|
||||
var context = CreateContext(FixturesRoot);
|
||||
|
||||
// Act
|
||||
var result = await _analyzer.AnalyzeAsync(context, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal("homebrew", result.AnalyzerId);
|
||||
Assert.True(result.Packages.Count > 0, "Expected at least one package");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AnalyzeAsync_FindsIntelCellarPackages()
|
||||
{
|
||||
// Arrange
|
||||
var context = CreateContext(FixturesRoot);
|
||||
|
||||
// Act
|
||||
var result = await _analyzer.AnalyzeAsync(context, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
var openssl = result.Packages.FirstOrDefault(p => p.Name == "openssl@3");
|
||||
Assert.NotNull(openssl);
|
||||
Assert.Equal("3.1.0", openssl.Version);
|
||||
Assert.Equal("x86_64", openssl.Architecture);
|
||||
Assert.Contains("pkg:brew/homebrew%2Fcore/openssl%403@3.1.0", openssl.PackageUrl);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AnalyzeAsync_FindsAppleSiliconCellarPackages()
|
||||
{
|
||||
// Arrange
|
||||
var context = CreateContext(FixturesRoot);
|
||||
|
||||
// Act
|
||||
var result = await _analyzer.AnalyzeAsync(context, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
var jq = result.Packages.FirstOrDefault(p => p.Name == "jq");
|
||||
Assert.NotNull(jq);
|
||||
Assert.Equal("1.7", jq.Version);
|
||||
Assert.Equal("arm64", jq.Architecture);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AnalyzeAsync_PackageWithRevision_IncludesRevisionInPurl()
|
||||
{
|
||||
// Arrange
|
||||
var context = CreateContext(FixturesRoot);
|
||||
|
||||
// Act
|
||||
var result = await _analyzer.AnalyzeAsync(context, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
var wget = result.Packages.FirstOrDefault(p => p.Name == "wget");
|
||||
Assert.NotNull(wget);
|
||||
Assert.Contains("?revision=1", wget.PackageUrl);
|
||||
Assert.Equal("1", wget.Release);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AnalyzeAsync_ExtractsDependencies()
|
||||
{
|
||||
// Arrange
|
||||
var context = CreateContext(FixturesRoot);
|
||||
|
||||
// Act
|
||||
var result = await _analyzer.AnalyzeAsync(context, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
var wget = result.Packages.FirstOrDefault(p => p.Name == "wget");
|
||||
Assert.NotNull(wget);
|
||||
Assert.Contains("openssl@3", wget.Depends);
|
||||
Assert.Contains("gettext", wget.Depends);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AnalyzeAsync_ExtractsVendorMetadata()
|
||||
{
|
||||
// Arrange
|
||||
var context = CreateContext(FixturesRoot);
|
||||
|
||||
// Act
|
||||
var result = await _analyzer.AnalyzeAsync(context, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
var openssl = result.Packages.FirstOrDefault(p => p.Name == "openssl@3");
|
||||
Assert.NotNull(openssl);
|
||||
Assert.Equal("homebrew/core", openssl.VendorMetadata["brew:tap"]);
|
||||
Assert.Equal("true", openssl.VendorMetadata["brew:poured_from_bottle"]);
|
||||
Assert.Equal("Cryptography and SSL/TLS Toolkit", openssl.VendorMetadata["description"]);
|
||||
Assert.Equal("https://openssl.org/", openssl.VendorMetadata["homepage"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AnalyzeAsync_SetsEvidenceSourceToHomebrewCellar()
|
||||
{
|
||||
// Arrange
|
||||
var context = CreateContext(FixturesRoot);
|
||||
|
||||
// Act
|
||||
var result = await _analyzer.AnalyzeAsync(context, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
foreach (var package in result.Packages)
|
||||
{
|
||||
Assert.Equal(PackageEvidenceSource.HomebrewCellar, package.EvidenceSource);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AnalyzeAsync_DiscoversBinFiles()
|
||||
{
|
||||
// Arrange
|
||||
var context = CreateContext(FixturesRoot);
|
||||
|
||||
// Act
|
||||
var result = await _analyzer.AnalyzeAsync(context, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
var wget = result.Packages.FirstOrDefault(p => p.Name == "wget");
|
||||
Assert.NotNull(wget);
|
||||
Assert.Contains(wget.Files, f => f.Path.Contains("wget"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AnalyzeAsync_ResultsAreDeterministicallySorted()
|
||||
{
|
||||
// Arrange
|
||||
var context = CreateContext(FixturesRoot);
|
||||
|
||||
// Act
|
||||
var result1 = await _analyzer.AnalyzeAsync(context, CancellationToken.None);
|
||||
var result2 = await _analyzer.AnalyzeAsync(context, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(result1.Packages.Count, result2.Packages.Count);
|
||||
for (int i = 0; i < result1.Packages.Count; i++)
|
||||
{
|
||||
Assert.Equal(result1.Packages[i].PackageUrl, result2.Packages[i].PackageUrl);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AnalyzeAsync_NoCellar_ReturnsEmptyPackages()
|
||||
{
|
||||
// Arrange - use temp directory without Cellar structure
|
||||
var tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
try
|
||||
{
|
||||
var context = CreateContext(tempPath);
|
||||
|
||||
// Act
|
||||
var result = await _analyzer.AnalyzeAsync(context, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Empty(result.Packages);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(tempPath, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AnalyzeAsync_PopulatesTelemetry()
|
||||
{
|
||||
// Arrange
|
||||
var context = CreateContext(FixturesRoot);
|
||||
|
||||
// Act
|
||||
var result = await _analyzer.AnalyzeAsync(context, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result.Telemetry);
|
||||
Assert.True(result.Telemetry.PackageCount > 0);
|
||||
Assert.True(result.Telemetry.Duration > TimeSpan.Zero);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,269 @@
|
||||
using System.Text;
|
||||
using StellaOps.Scanner.Analyzers.OS.Homebrew;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Scanner.Analyzers.OS.Homebrew.Tests;
|
||||
|
||||
public sealed class HomebrewReceiptParserTests
|
||||
{
|
||||
private readonly HomebrewReceiptParser _parser = new();
|
||||
|
||||
[Fact]
|
||||
public void Parse_ValidReceipt_ReturnsExpectedValues()
|
||||
{
|
||||
// Arrange
|
||||
var json = """
|
||||
{
|
||||
"name": "openssl@3",
|
||||
"versions": { "stable": "3.1.0" },
|
||||
"revision": 0,
|
||||
"tap": "homebrew/core",
|
||||
"poured_from_bottle": true,
|
||||
"time": 1699000000,
|
||||
"installed_as_dependency": false,
|
||||
"installed_on_request": true,
|
||||
"runtime_dependencies": [{ "full_name": "ca-certificates", "version": "2023-01-10" }],
|
||||
"desc": "Cryptography and SSL/TLS Toolkit",
|
||||
"homepage": "https://openssl.org/",
|
||||
"license": "Apache-2.0",
|
||||
"arch": "x86_64"
|
||||
}
|
||||
""";
|
||||
using var stream = new MemoryStream(Encoding.UTF8.GetBytes(json));
|
||||
|
||||
// Act
|
||||
var receipt = _parser.Parse(stream);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(receipt);
|
||||
Assert.Equal("openssl@3", receipt.Name);
|
||||
Assert.Equal("3.1.0", receipt.Version);
|
||||
Assert.Equal(0, receipt.Revision);
|
||||
Assert.Equal("homebrew/core", receipt.Tap);
|
||||
Assert.True(receipt.PouredFromBottle);
|
||||
Assert.False(receipt.InstalledAsDependency);
|
||||
Assert.True(receipt.InstalledOnRequest);
|
||||
Assert.Single(receipt.RuntimeDependencies);
|
||||
Assert.Equal("ca-certificates", receipt.RuntimeDependencies[0]);
|
||||
Assert.Equal("Cryptography and SSL/TLS Toolkit", receipt.Description);
|
||||
Assert.Equal("https://openssl.org/", receipt.Homepage);
|
||||
Assert.Equal("Apache-2.0", receipt.License);
|
||||
Assert.Equal("x86_64", receipt.Architecture);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Parse_WithRevision_ReturnsCorrectRevision()
|
||||
{
|
||||
// Arrange
|
||||
var json = """
|
||||
{
|
||||
"name": "wget",
|
||||
"versions": { "stable": "1.21.4" },
|
||||
"revision": 1,
|
||||
"tap": "homebrew/core",
|
||||
"poured_from_bottle": true,
|
||||
"arch": "x86_64"
|
||||
}
|
||||
""";
|
||||
using var stream = new MemoryStream(Encoding.UTF8.GetBytes(json));
|
||||
|
||||
// Act
|
||||
var receipt = _parser.Parse(stream);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(receipt);
|
||||
Assert.Equal("wget", receipt.Name);
|
||||
Assert.Equal("1.21.4", receipt.Version);
|
||||
Assert.Equal(1, receipt.Revision);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Parse_AppleSilicon_ReturnsArm64Architecture()
|
||||
{
|
||||
// Arrange
|
||||
var json = """
|
||||
{
|
||||
"name": "jq",
|
||||
"versions": { "stable": "1.7" },
|
||||
"revision": 0,
|
||||
"tap": "homebrew/core",
|
||||
"arch": "arm64"
|
||||
}
|
||||
""";
|
||||
using var stream = new MemoryStream(Encoding.UTF8.GetBytes(json));
|
||||
|
||||
// Act
|
||||
var receipt = _parser.Parse(stream);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(receipt);
|
||||
Assert.Equal("arm64", receipt.Architecture);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Parse_WithSourceInfo_ExtractsSourceUrlAndChecksum()
|
||||
{
|
||||
// Arrange
|
||||
var json = """
|
||||
{
|
||||
"name": "test",
|
||||
"versions": { "stable": "1.0.0" },
|
||||
"tap": "homebrew/core",
|
||||
"source": {
|
||||
"url": "https://example.com/test-1.0.0.tar.gz",
|
||||
"checksum": "sha256:abcdef123456"
|
||||
}
|
||||
}
|
||||
""";
|
||||
using var stream = new MemoryStream(Encoding.UTF8.GetBytes(json));
|
||||
|
||||
// Act
|
||||
var receipt = _parser.Parse(stream);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(receipt);
|
||||
Assert.Equal("https://example.com/test-1.0.0.tar.gz", receipt.SourceUrl);
|
||||
Assert.Equal("sha256:abcdef123456", receipt.SourceChecksum);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Parse_MultipleDependencies_SortsAlphabetically()
|
||||
{
|
||||
// Arrange
|
||||
var json = """
|
||||
{
|
||||
"name": "test",
|
||||
"versions": { "stable": "1.0.0" },
|
||||
"tap": "homebrew/core",
|
||||
"runtime_dependencies": [
|
||||
{ "full_name": "zlib" },
|
||||
{ "full_name": "openssl" },
|
||||
{ "full_name": "libpng" }
|
||||
]
|
||||
}
|
||||
""";
|
||||
using var stream = new MemoryStream(Encoding.UTF8.GetBytes(json));
|
||||
|
||||
// Act
|
||||
var receipt = _parser.Parse(stream);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(receipt);
|
||||
Assert.Equal(3, receipt.RuntimeDependencies.Count);
|
||||
Assert.Equal("libpng", receipt.RuntimeDependencies[0]);
|
||||
Assert.Equal("openssl", receipt.RuntimeDependencies[1]);
|
||||
Assert.Equal("zlib", receipt.RuntimeDependencies[2]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Parse_InvalidJson_ReturnsNull()
|
||||
{
|
||||
// Arrange
|
||||
var invalidJson = "{ invalid json }";
|
||||
using var stream = new MemoryStream(Encoding.UTF8.GetBytes(invalidJson));
|
||||
|
||||
// Act
|
||||
var receipt = _parser.Parse(stream);
|
||||
|
||||
// Assert
|
||||
Assert.Null(receipt);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Parse_EmptyJson_ReturnsNull()
|
||||
{
|
||||
// Arrange
|
||||
var emptyJson = "{}";
|
||||
using var stream = new MemoryStream(Encoding.UTF8.GetBytes(emptyJson));
|
||||
|
||||
// Act
|
||||
var receipt = _parser.Parse(stream);
|
||||
|
||||
// Assert
|
||||
Assert.Null(receipt);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Parse_MissingName_ReturnsNull()
|
||||
{
|
||||
// Arrange
|
||||
var json = """
|
||||
{
|
||||
"versions": { "stable": "1.0.0" },
|
||||
"tap": "homebrew/core"
|
||||
}
|
||||
""";
|
||||
using var stream = new MemoryStream(Encoding.UTF8.GetBytes(json));
|
||||
|
||||
// Act
|
||||
var receipt = _parser.Parse(stream);
|
||||
|
||||
// Assert
|
||||
Assert.Null(receipt);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Parse_TappedFrom_UsesTappedFromOverTap()
|
||||
{
|
||||
// Arrange
|
||||
var json = """
|
||||
{
|
||||
"name": "test",
|
||||
"versions": { "stable": "1.0.0" },
|
||||
"tap": "homebrew/core",
|
||||
"tapped_from": "custom/tap"
|
||||
}
|
||||
""";
|
||||
using var stream = new MemoryStream(Encoding.UTF8.GetBytes(json));
|
||||
|
||||
// Act
|
||||
var receipt = _parser.Parse(stream);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(receipt);
|
||||
Assert.Equal("custom/tap", receipt.Tap);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Parse_FallbackVersion_UsesVersionFieldWhenVersionsStableMissing()
|
||||
{
|
||||
// Arrange - older receipt format uses version field directly
|
||||
var json = """
|
||||
{
|
||||
"name": "test",
|
||||
"version": "2.0.0",
|
||||
"tap": "homebrew/core"
|
||||
}
|
||||
""";
|
||||
using var stream = new MemoryStream(Encoding.UTF8.GetBytes(json));
|
||||
|
||||
// Act
|
||||
var receipt = _parser.Parse(stream);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(receipt);
|
||||
Assert.Equal("2.0.0", receipt.Version);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Parse_NormalizesArchitecture_AArch64ToArm64()
|
||||
{
|
||||
// Arrange
|
||||
var json = """
|
||||
{
|
||||
"name": "test",
|
||||
"versions": { "stable": "1.0.0" },
|
||||
"tap": "homebrew/core",
|
||||
"arch": "aarch64"
|
||||
}
|
||||
""";
|
||||
using var stream = new MemoryStream(Encoding.UTF8.GetBytes(json));
|
||||
|
||||
// Act
|
||||
var receipt = _parser.Parse(stream);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(receipt);
|
||||
Assert.Equal("arm64", receipt.Architecture);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<UseConcelierTestInfra>false</UseConcelierTestInfra>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.0-rc.2.25502.107" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.0" />
|
||||
<PackageReference Include="xunit" Version="2.9.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.4" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../../__Libraries/StellaOps.Scanner.Analyzers.OS/StellaOps.Scanner.Analyzers.OS.csproj" />
|
||||
<ProjectReference Include="../../__Libraries/StellaOps.Scanner.Analyzers.OS.Homebrew/StellaOps.Scanner.Analyzers.OS.Homebrew.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Fixtures\**\*" CopyToOutputDirectory="PreserveNewest" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user