Restructure solution layout by module
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
using StellaOps.Scanner.Analyzers.Lang.Tests.TestUtilities;
|
||||
|
||||
namespace StellaOps.Scanner.Analyzers.Lang.Tests.Core;
|
||||
|
||||
public sealed class LanguageAnalyzerResultTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task MergesDuplicateComponentsDeterministicallyAsync()
|
||||
{
|
||||
var analyzer = new DuplicateComponentAnalyzer();
|
||||
var engine = new LanguageAnalyzerEngine(new[] { analyzer });
|
||||
var root = TestPaths.CreateTemporaryDirectory();
|
||||
try
|
||||
{
|
||||
var context = new LanguageAnalyzerContext(root, TimeProvider.System);
|
||||
var result = await engine.AnalyzeAsync(context, CancellationToken.None);
|
||||
|
||||
var component = Assert.Single(result.Components);
|
||||
Assert.Equal("purl::pkg:example/acme@2.0.0", component.ComponentKey);
|
||||
Assert.Equal("pkg:example/acme@2.0.0", component.Purl);
|
||||
Assert.True(component.UsedByEntrypoint);
|
||||
Assert.Equal(2, component.Evidence.Count);
|
||||
Assert.Equal(3, component.Metadata.Count);
|
||||
|
||||
// Metadata retains stable ordering (sorted by key)
|
||||
var keys = component.Metadata.Keys.ToArray();
|
||||
Assert.Equal(new[] { "artifactId", "groupId", "path" }, keys);
|
||||
|
||||
// Evidence de-duplicates via comparison key
|
||||
Assert.Equal(2, component.Evidence.Count);
|
||||
}
|
||||
finally
|
||||
{
|
||||
TestPaths.SafeDelete(root);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class DuplicateComponentAnalyzer : ILanguageAnalyzer
|
||||
{
|
||||
public string Id => "duplicate";
|
||||
|
||||
public string DisplayName => "Duplicate Analyzer";
|
||||
|
||||
public async ValueTask AnalyzeAsync(LanguageAnalyzerContext context, LanguageComponentWriter writer, CancellationToken cancellationToken)
|
||||
{
|
||||
await Task.Yield();
|
||||
|
||||
var metadataA = new[]
|
||||
{
|
||||
new KeyValuePair<string, string?>("groupId", "example"),
|
||||
new KeyValuePair<string, string?>("artifactId", "acme")
|
||||
};
|
||||
|
||||
var metadataB = new[]
|
||||
{
|
||||
new KeyValuePair<string, string?>("artifactId", "acme"),
|
||||
new KeyValuePair<string, string?>("path", ".")
|
||||
};
|
||||
|
||||
var evidence = new[]
|
||||
{
|
||||
new LanguageComponentEvidence(LanguageEvidenceKind.File, "manifest", "META-INF/MANIFEST.MF", null, null),
|
||||
new LanguageComponentEvidence(LanguageEvidenceKind.Metadata, "pom", "pom.xml", "groupId=example", null)
|
||||
};
|
||||
|
||||
writer.AddFromPurl(
|
||||
analyzerId: Id,
|
||||
purl: "pkg:example/acme@2.0.0",
|
||||
name: "acme",
|
||||
version: "2.0.0",
|
||||
type: "example",
|
||||
metadata: metadataA,
|
||||
evidence: evidence,
|
||||
usedByEntrypoint: true);
|
||||
|
||||
// duplicate insert with different metadata ordering
|
||||
writer.AddFromPurl(
|
||||
analyzerId: Id,
|
||||
purl: "pkg:example/acme@2.0.0",
|
||||
name: "acme",
|
||||
version: "2.0.0",
|
||||
type: "example",
|
||||
metadata: metadataB,
|
||||
evidence: evidence,
|
||||
usedByEntrypoint: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
using StellaOps.Scanner.Core.Contracts;
|
||||
|
||||
namespace StellaOps.Scanner.Analyzers.Lang.Tests.Core;
|
||||
|
||||
public sealed class LanguageComponentMapperTests
|
||||
{
|
||||
[Fact]
|
||||
public void ToComponentRecordsProjectsDeterministicComponents()
|
||||
{
|
||||
// Arrange
|
||||
var analyzerId = "node";
|
||||
var records = new[]
|
||||
{
|
||||
LanguageComponentRecord.FromPurl(
|
||||
analyzerId: analyzerId,
|
||||
purl: "pkg:npm/example@1.0.0",
|
||||
name: "example",
|
||||
version: "1.0.0",
|
||||
type: "npm",
|
||||
metadata: new Dictionary<string, string?>()
|
||||
{
|
||||
["path"] = "packages/app",
|
||||
["license"] = "MIT"
|
||||
},
|
||||
evidence: new[]
|
||||
{
|
||||
new LanguageComponentEvidence(LanguageEvidenceKind.File, "package.json", "packages/app/package.json", null, "abc123")
|
||||
},
|
||||
usedByEntrypoint: true),
|
||||
LanguageComponentRecord.FromExplicitKey(
|
||||
analyzerId: analyzerId,
|
||||
componentKey: "bin::sha256:deadbeef",
|
||||
purl: null,
|
||||
name: "app-binary",
|
||||
version: null,
|
||||
type: "binary",
|
||||
metadata: new Dictionary<string, string?>()
|
||||
{
|
||||
["description"] = "Utility binary"
|
||||
},
|
||||
evidence: new[]
|
||||
{
|
||||
new LanguageComponentEvidence(LanguageEvidenceKind.Derived, "entrypoint", "/usr/local/bin/app", "ENTRYPOINT", null)
|
||||
})
|
||||
};
|
||||
|
||||
// Act
|
||||
var layerDigest = LanguageComponentMapper.ComputeLayerDigest(analyzerId);
|
||||
var results = LanguageComponentMapper.ToComponentRecords(analyzerId, records, layerDigest);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, results.Length);
|
||||
Assert.All(results, component => Assert.Equal(layerDigest, component.LayerDigest));
|
||||
|
||||
var first = results[0];
|
||||
Assert.Equal("bin::sha256:deadbeef", first.Identity.Key);
|
||||
Assert.Equal("Utility binary", first.Metadata!.Properties!["stellaops.lang.meta.description"]);
|
||||
Assert.Equal("derived", first.Evidence.Single().Kind);
|
||||
|
||||
var second = results[1];
|
||||
Assert.Equal("pkg:npm/example@1.0.0", second.Identity.Key); // prefix removed
|
||||
Assert.True(second.Usage.UsedByEntrypoint);
|
||||
Assert.Contains("MIT", second.Metadata!.Licenses!);
|
||||
Assert.Equal("packages/app", second.Metadata.Properties!["stellaops.lang.meta.path"]);
|
||||
Assert.Equal("abc123", second.Metadata.Properties!["stellaops.lang.evidence.0.sha256"]);
|
||||
Assert.Equal("file", second.Evidence.Single().Kind);
|
||||
Assert.Equal("packages/app/package.json", second.Evidence.Single().Value);
|
||||
Assert.Equal("package.json", second.Evidence.Single().Source);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
using StellaOps.Scanner.Analyzers.Lang;
|
||||
using StellaOps.Scanner.Analyzers.Lang.Tests.Harness;
|
||||
using StellaOps.Scanner.Analyzers.Lang.Tests.TestUtilities;
|
||||
|
||||
namespace StellaOps.Scanner.Analyzers.Lang.Tests.Determinism;
|
||||
|
||||
public sealed class LanguageAnalyzerHarnessTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task HarnessProducesDeterministicOutputAsync()
|
||||
{
|
||||
var fixturePath = TestPaths.ResolveFixture("determinism", "basic", "input");
|
||||
var goldenPath = TestPaths.ResolveFixture("determinism", "basic", "expected.json");
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
|
||||
var analyzers = new ILanguageAnalyzer[]
|
||||
{
|
||||
new FakeLanguageAnalyzer(
|
||||
"fake-java",
|
||||
LanguageComponentRecord.FromPurl(
|
||||
analyzerId: "fake-java",
|
||||
purl: "pkg:maven/org.example/example-lib@1.2.3",
|
||||
name: "example-lib",
|
||||
version: "1.2.3",
|
||||
type: "maven",
|
||||
metadata: new Dictionary<string, string?>
|
||||
{
|
||||
["groupId"] = "org.example",
|
||||
["artifactId"] = "example-lib",
|
||||
},
|
||||
evidence: new []
|
||||
{
|
||||
new LanguageComponentEvidence(LanguageEvidenceKind.File, "pom.properties", "META-INF/maven/org.example/example-lib/pom.properties", null, "abc123"),
|
||||
}),
|
||||
LanguageComponentRecord.FromExplicitKey(
|
||||
analyzerId: "fake-java",
|
||||
componentKey: "bin::sha256:deadbeef",
|
||||
purl: null,
|
||||
name: "example-cli",
|
||||
version: null,
|
||||
type: "bin",
|
||||
metadata: new Dictionary<string, string?>
|
||||
{
|
||||
["sha256"] = "deadbeef",
|
||||
},
|
||||
evidence: new []
|
||||
{
|
||||
new LanguageComponentEvidence(LanguageEvidenceKind.File, "binary", "usr/local/bin/example", null, "deadbeef"),
|
||||
})),
|
||||
new FakeLanguageAnalyzer(
|
||||
"fake-node",
|
||||
LanguageComponentRecord.FromPurl(
|
||||
analyzerId: "fake-node",
|
||||
purl: "pkg:npm/example-package@4.5.6",
|
||||
name: "example-package",
|
||||
version: "4.5.6",
|
||||
type: "npm",
|
||||
metadata: new Dictionary<string, string?>
|
||||
{
|
||||
["workspace"] = "packages/example",
|
||||
},
|
||||
evidence: new []
|
||||
{
|
||||
new LanguageComponentEvidence(LanguageEvidenceKind.File, "package.json", "packages/example/package.json", null, null),
|
||||
},
|
||||
usedByEntrypoint: true)),
|
||||
};
|
||||
|
||||
await LanguageAnalyzerTestHarness.AssertDeterministicAsync(fixturePath, goldenPath, analyzers, cancellationToken);
|
||||
|
||||
var first = await LanguageAnalyzerTestHarness.RunToJsonAsync(fixturePath, analyzers, cancellationToken);
|
||||
var second = await LanguageAnalyzerTestHarness.RunToJsonAsync(fixturePath, analyzers, cancellationToken);
|
||||
Assert.Equal(first, second);
|
||||
}
|
||||
|
||||
private sealed class FakeLanguageAnalyzer : ILanguageAnalyzer
|
||||
{
|
||||
private readonly IReadOnlyList<LanguageComponentRecord> _components;
|
||||
|
||||
public FakeLanguageAnalyzer(string id, params LanguageComponentRecord[] components)
|
||||
{
|
||||
Id = id;
|
||||
DisplayName = id;
|
||||
_components = components ?? Array.Empty<LanguageComponentRecord>();
|
||||
}
|
||||
|
||||
public string Id { get; }
|
||||
|
||||
public string DisplayName { get; }
|
||||
|
||||
public async ValueTask AnalyzeAsync(LanguageAnalyzerContext context, LanguageComponentWriter writer, CancellationToken cancellationToken)
|
||||
{
|
||||
await Task.Delay(5, cancellationToken).ConfigureAwait(false); // ensure asynchrony is handled
|
||||
|
||||
// Intentionally add in reverse order to prove determinism.
|
||||
foreach (var component in _components.Reverse())
|
||||
{
|
||||
writer.Add(component);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using StellaOps.Scanner.Analyzers.Lang.DotNet;
|
||||
using StellaOps.Scanner.Analyzers.Lang.Tests.Harness;
|
||||
using StellaOps.Scanner.Analyzers.Lang.Tests.TestUtilities;
|
||||
|
||||
namespace StellaOps.Scanner.Analyzers.Lang.Tests.DotNet;
|
||||
|
||||
public sealed class DotNetLanguageAnalyzerTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task SimpleFixtureProducesDeterministicOutputAsync()
|
||||
{
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
var fixturePath = TestPaths.ResolveFixture("lang", "dotnet", "simple");
|
||||
var goldenPath = Path.Combine(fixturePath, "expected.json");
|
||||
|
||||
var analyzers = new ILanguageAnalyzer[]
|
||||
{
|
||||
new DotNetLanguageAnalyzer()
|
||||
};
|
||||
|
||||
await LanguageAnalyzerTestHarness.AssertDeterministicAsync(
|
||||
fixturePath,
|
||||
goldenPath,
|
||||
analyzers,
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SignedFixtureCapturesAssemblyMetadataAsync()
|
||||
{
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
var fixturePath = TestPaths.ResolveFixture("lang", "dotnet", "signed");
|
||||
var goldenPath = Path.Combine(fixturePath, "expected.json");
|
||||
|
||||
var analyzers = new ILanguageAnalyzer[]
|
||||
{
|
||||
new DotNetLanguageAnalyzer()
|
||||
};
|
||||
|
||||
var inspector = new StubAuthenticodeInspector();
|
||||
var services = new SingleServiceProvider(inspector);
|
||||
|
||||
await LanguageAnalyzerTestHarness.AssertDeterministicAsync(
|
||||
fixturePath,
|
||||
goldenPath,
|
||||
analyzers,
|
||||
cancellationToken,
|
||||
usageHints: null,
|
||||
services: services);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SelfContainedFixtureHandlesNativeAssetsAndUsageAsync()
|
||||
{
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
var fixturePath = TestPaths.ResolveFixture("lang", "dotnet", "selfcontained");
|
||||
var goldenPath = Path.Combine(fixturePath, "expected.json");
|
||||
|
||||
var usageHints = new LanguageUsageHints(new[]
|
||||
{
|
||||
Path.Combine(fixturePath, "lib", "net10.0", "StellaOps.Toolkit.dll"),
|
||||
Path.Combine(fixturePath, "runtimes", "linux-x64", "native", "libstellaopsnative.so")
|
||||
});
|
||||
|
||||
var analyzers = new ILanguageAnalyzer[]
|
||||
{
|
||||
new DotNetLanguageAnalyzer()
|
||||
};
|
||||
|
||||
await LanguageAnalyzerTestHarness.AssertDeterministicAsync(
|
||||
fixturePath,
|
||||
goldenPath,
|
||||
analyzers,
|
||||
cancellationToken,
|
||||
usageHints);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AnalyzerIsThreadSafeUnderConcurrencyAsync()
|
||||
{
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
var fixturePath = TestPaths.ResolveFixture("lang", "dotnet", "selfcontained");
|
||||
|
||||
var analyzers = new ILanguageAnalyzer[]
|
||||
{
|
||||
new DotNetLanguageAnalyzer()
|
||||
};
|
||||
|
||||
var workers = Math.Max(Environment.ProcessorCount, 4);
|
||||
var tasks = Enumerable.Range(0, workers)
|
||||
.Select(_ => LanguageAnalyzerTestHarness.RunToJsonAsync(fixturePath, analyzers, cancellationToken));
|
||||
|
||||
var results = await Task.WhenAll(tasks);
|
||||
var first = results[0];
|
||||
foreach (var result in results)
|
||||
{
|
||||
Assert.Equal(first, result);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task MultiFixtureMergesRuntimeMetadataAsync()
|
||||
{
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
var fixturePath = TestPaths.ResolveFixture("lang", "dotnet", "multi");
|
||||
var goldenPath = Path.Combine(fixturePath, "expected.json");
|
||||
|
||||
var analyzers = new ILanguageAnalyzer[]
|
||||
{
|
||||
new DotNetLanguageAnalyzer()
|
||||
};
|
||||
|
||||
await LanguageAnalyzerTestHarness.AssertDeterministicAsync(
|
||||
fixturePath,
|
||||
goldenPath,
|
||||
analyzers,
|
||||
cancellationToken);
|
||||
|
||||
var json = await LanguageAnalyzerTestHarness.RunToJsonAsync(
|
||||
fixturePath,
|
||||
analyzers,
|
||||
cancellationToken);
|
||||
|
||||
using var document = JsonDocument.Parse(json);
|
||||
var root = document.RootElement;
|
||||
Assert.True(root.ValueKind == JsonValueKind.Array, "Result root should be an array.");
|
||||
Assert.Equal(2, root.GetArrayLength());
|
||||
|
||||
var loggingComponent = root.EnumerateArray()
|
||||
.First(element => element.GetProperty("name").GetString() == "StellaOps.Logging");
|
||||
|
||||
var metadata = loggingComponent.GetProperty("metadata");
|
||||
Assert.Equal("StellaOps.Logging", loggingComponent.GetProperty("name").GetString());
|
||||
Assert.Equal("2.5.1", loggingComponent.GetProperty("version").GetString());
|
||||
Assert.Equal("pkg:nuget/stellaops.logging@2.5.1", loggingComponent.GetProperty("purl").GetString());
|
||||
|
||||
var ridValues = metadata.EnumerateObject()
|
||||
.Where(property => property.Name.Contains(".rid", StringComparison.Ordinal))
|
||||
.Select(property => property.Value.GetString())
|
||||
.Where(value => !string.IsNullOrEmpty(value))
|
||||
.Select(value => value!)
|
||||
.ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
Assert.Contains("linux-x64", ridValues);
|
||||
Assert.Contains("osx-arm64", ridValues);
|
||||
Assert.Contains("win-arm64", ridValues);
|
||||
}
|
||||
|
||||
private sealed class StubAuthenticodeInspector : IDotNetAuthenticodeInspector
|
||||
{
|
||||
public DotNetAuthenticodeMetadata? TryInspect(string assemblyPath, CancellationToken cancellationToken)
|
||||
=> new DotNetAuthenticodeMetadata(
|
||||
Subject: "CN=StellaOps Test Signing",
|
||||
Issuer: "CN=StellaOps Root",
|
||||
NotBefore: new DateTimeOffset(2025, 1, 1, 0, 0, 0, TimeSpan.Zero),
|
||||
NotAfter: new DateTimeOffset(2026, 1, 1, 0, 0, 0, TimeSpan.Zero),
|
||||
Thumbprint: "AA11BB22CC33DD44EE55FF66GG77HH88II99JJ00",
|
||||
SerialNumber: "0123456789ABCDEF");
|
||||
}
|
||||
|
||||
private sealed class SingleServiceProvider : IServiceProvider
|
||||
{
|
||||
private readonly object _service;
|
||||
|
||||
public SingleServiceProvider(object service)
|
||||
{
|
||||
_service = service;
|
||||
}
|
||||
|
||||
public object? GetService(Type serviceType)
|
||||
=> serviceType == typeof(IDotNetAuthenticodeInspector) ? _service : null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
[
|
||||
{
|
||||
"analyzerId": "fake-java",
|
||||
"componentKey": "bin::sha256:deadbeef",
|
||||
"name": "example-cli",
|
||||
"type": "bin",
|
||||
"usedByEntrypoint": false,
|
||||
"metadata": {
|
||||
"sha256": "deadbeef"
|
||||
},
|
||||
"evidence": [
|
||||
{
|
||||
"kind": "file",
|
||||
"source": "binary",
|
||||
"locator": "usr/local/bin/example",
|
||||
"sha256": "deadbeef"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"analyzerId": "fake-java",
|
||||
"componentKey": "purl::pkg:maven/org.example/example-lib@1.2.3",
|
||||
"purl": "pkg:maven/org.example/example-lib@1.2.3",
|
||||
"name": "example-lib",
|
||||
"version": "1.2.3",
|
||||
"type": "maven",
|
||||
"usedByEntrypoint": false,
|
||||
"metadata": {
|
||||
"artifactId": "example-lib",
|
||||
"groupId": "org.example"
|
||||
},
|
||||
"evidence": [
|
||||
{
|
||||
"kind": "file",
|
||||
"source": "pom.properties",
|
||||
"locator": "META-INF/maven/org.example/example-lib/pom.properties",
|
||||
"sha256": "abc123"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"analyzerId": "fake-node",
|
||||
"componentKey": "purl::pkg:npm/example-package@4.5.6",
|
||||
"purl": "pkg:npm/example-package@4.5.6",
|
||||
"name": "example-package",
|
||||
"version": "4.5.6",
|
||||
"type": "npm",
|
||||
"usedByEntrypoint": true,
|
||||
"metadata": {
|
||||
"workspace": "packages/example"
|
||||
},
|
||||
"evidence": [
|
||||
{
|
||||
"kind": "file",
|
||||
"source": "package.json",
|
||||
"locator": "packages/example/package.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1 @@
|
||||
sample
|
||||
@@ -0,0 +1,84 @@
|
||||
{
|
||||
"runtimeTarget": {
|
||||
"name": ".NETCoreApp,Version=v10.0/osx-arm64"
|
||||
},
|
||||
"targets": {
|
||||
".NETCoreApp,Version=v10.0": {
|
||||
"AppA/2.0.0": {
|
||||
"dependencies": {
|
||||
"StellaOps.Toolkit": "1.2.3",
|
||||
"StellaOps.Logging": "2.5.1"
|
||||
}
|
||||
},
|
||||
"StellaOps.Toolkit/1.2.3": {
|
||||
"dependencies": {
|
||||
"StellaOps.Logging": "2.5.1"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net10.0/StellaOps.Toolkit.dll": {
|
||||
"assemblyVersion": "1.2.3.0",
|
||||
"fileVersion": "1.2.3.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"StellaOps.Logging/2.5.1": {
|
||||
"runtime": {
|
||||
"lib/net10.0/StellaOps.Logging.dll": {
|
||||
"assemblyVersion": "2.5.1.0",
|
||||
"fileVersion": "2.5.1.12345"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
".NETCoreApp,Version=v10.0/linux-x64": {
|
||||
"StellaOps.Toolkit/1.2.3": {
|
||||
"runtimeTargets": {
|
||||
"runtimes/linux-x64/native/libstellaops.toolkit.so": {
|
||||
"rid": "linux-x64",
|
||||
"assetType": "native"
|
||||
}
|
||||
}
|
||||
},
|
||||
"StellaOps.Logging/2.5.1": {
|
||||
"runtime": {
|
||||
"runtimes/linux-x64/lib/net10.0/StellaOps.Logging.dll": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
".NETCoreApp,Version=v10.0/osx-arm64": {
|
||||
"StellaOps.Toolkit/1.2.3": {
|
||||
"runtimeTargets": {
|
||||
"runtimes/osx-arm64/native/libstellaops.toolkit.dylib": {
|
||||
"rid": "osx-arm64",
|
||||
"assetType": "native"
|
||||
}
|
||||
}
|
||||
},
|
||||
"StellaOps.Logging/2.5.1": {
|
||||
"runtime": {
|
||||
"runtimes/osx-arm64/lib/net10.0/StellaOps.Logging.dll": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"libraries": {
|
||||
"AppA/2.0.0": {
|
||||
"type": "project",
|
||||
"serviceable": false
|
||||
},
|
||||
"StellaOps.Toolkit/1.2.3": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-FAKE_TOOLKIT_SHA==",
|
||||
"path": "stellaops.toolkit/1.2.3",
|
||||
"hashPath": "stellaops.toolkit.1.2.3.nupkg.sha512"
|
||||
},
|
||||
"StellaOps.Logging/2.5.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-FAKE_LOGGING_SHA==",
|
||||
"path": "stellaops.logging/2.5.1",
|
||||
"hashPath": "stellaops.logging.2.5.1.nupkg.sha512"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"runtimeOptions": {
|
||||
"tfm": "net10.0",
|
||||
"framework": {
|
||||
"name": "Microsoft.NETCore.App",
|
||||
"version": "10.0.1"
|
||||
},
|
||||
"frameworks": [
|
||||
{
|
||||
"name": "Microsoft.NETCore.App",
|
||||
"version": "10.0.1"
|
||||
},
|
||||
{
|
||||
"name": "Microsoft.AspNetCore.App",
|
||||
"version": "10.0.0"
|
||||
},
|
||||
{
|
||||
"name": "StellaOps.Hosting",
|
||||
"version": "2.0.0"
|
||||
}
|
||||
],
|
||||
"runtimeGraph": {
|
||||
"runtimes": {
|
||||
"osx-arm64": {
|
||||
"fallbacks": [
|
||||
"osx",
|
||||
"unix"
|
||||
]
|
||||
},
|
||||
"linux-x64": {
|
||||
"fallbacks": [
|
||||
"linux",
|
||||
"unix"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
{
|
||||
"runtimeTarget": {
|
||||
"name": ".NETCoreApp,Version=v10.0/win-arm64"
|
||||
},
|
||||
"targets": {
|
||||
".NETCoreApp,Version=v10.0": {
|
||||
"AppB/3.1.0": {
|
||||
"dependencies": {
|
||||
"StellaOps.Toolkit": "1.2.3",
|
||||
"StellaOps.Logging": "2.5.1"
|
||||
}
|
||||
},
|
||||
"StellaOps.Toolkit/1.2.3": {
|
||||
"runtime": {
|
||||
"lib/net10.0/StellaOps.Toolkit.dll": {
|
||||
"assemblyVersion": "1.2.3.0",
|
||||
"fileVersion": "1.2.3.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"StellaOps.Logging/2.5.1": {
|
||||
"runtime": {
|
||||
"lib/net10.0/StellaOps.Logging.dll": {
|
||||
"assemblyVersion": "2.5.1.0",
|
||||
"fileVersion": "2.5.1.12345"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
".NETCoreApp,Version=v10.0/win-arm64": {
|
||||
"StellaOps.Toolkit/1.2.3": {
|
||||
"runtimeTargets": {
|
||||
"runtimes/win-arm64/native/stellaops.toolkit.dll": {
|
||||
"rid": "win-arm64",
|
||||
"assetType": "native"
|
||||
}
|
||||
}
|
||||
},
|
||||
"StellaOps.Logging/2.5.1": {
|
||||
"runtimeTargets": {
|
||||
"runtimes/win-arm64/native/stellaops.logging.dll": {
|
||||
"rid": "win-arm64",
|
||||
"assetType": "native"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
".NETCoreApp,Version=v10.0/linux-arm64": {
|
||||
"StellaOps.Logging/2.5.1": {
|
||||
"runtime": {
|
||||
"runtimes/linux-arm64/lib/net10.0/StellaOps.Logging.dll": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"libraries": {
|
||||
"AppB/3.1.0": {
|
||||
"type": "project",
|
||||
"serviceable": false
|
||||
},
|
||||
"StellaOps.Toolkit/1.2.3": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-FAKE_TOOLKIT_SHA==",
|
||||
"path": "stellaops.toolkit/1.2.3",
|
||||
"hashPath": "stellaops.toolkit.1.2.3.nupkg.sha512"
|
||||
},
|
||||
"StellaOps.Logging/2.5.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-FAKE_LOGGING_SHA==",
|
||||
"path": "stellaops.logging/2.5.1",
|
||||
"hashPath": "stellaops.logging.2.5.1.nupkg.sha512"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"runtimeOptions": {
|
||||
"tfm": "net10.0",
|
||||
"framework": {
|
||||
"name": "Microsoft.NETCore.App",
|
||||
"version": "10.0.0"
|
||||
},
|
||||
"frameworks": [
|
||||
{
|
||||
"name": "Microsoft.NETCore.App",
|
||||
"version": "10.0.0"
|
||||
},
|
||||
{
|
||||
"name": "Microsoft.WindowsDesktop.App",
|
||||
"version": "10.0.0"
|
||||
}
|
||||
],
|
||||
"additionalProbingPaths": [
|
||||
"C:/Users/runner/.nuget/packages"
|
||||
],
|
||||
"runtimeGraph": {
|
||||
"runtimes": {
|
||||
"win-arm64": {
|
||||
"fallbacks": [
|
||||
"win",
|
||||
"any"
|
||||
]
|
||||
},
|
||||
"linux-arm64": {
|
||||
"fallbacks": [
|
||||
"linux",
|
||||
"unix"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
[
|
||||
{
|
||||
"analyzerId": "dotnet",
|
||||
"componentKey": "purl::pkg:nuget/stellaops.logging@2.5.1",
|
||||
"purl": "pkg:nuget/stellaops.logging@2.5.1",
|
||||
"name": "StellaOps.Logging",
|
||||
"version": "2.5.1",
|
||||
"type": "nuget",
|
||||
"usedByEntrypoint": false,
|
||||
"metadata": {
|
||||
"assembly[0].assetPath": "lib/net10.0/StellaOps.Logging.dll",
|
||||
"assembly[0].fileVersion": "2.5.1.12345",
|
||||
"assembly[0].tfm[0]": ".NETCoreApp,Version=v10.0",
|
||||
"assembly[0].version": "2.5.1.0",
|
||||
"assembly[1].assetPath": "runtimes/linux-arm64/lib/net10.0/StellaOps.Logging.dll",
|
||||
"assembly[1].rid[0]": "linux-arm64",
|
||||
"assembly[1].tfm[0]": ".NETCoreApp,Version=v10.0",
|
||||
"assembly[2].assetPath": "runtimes/linux-x64/lib/net10.0/StellaOps.Logging.dll",
|
||||
"assembly[2].rid[0]": "linux-x64",
|
||||
"assembly[2].tfm[0]": ".NETCoreApp,Version=v10.0",
|
||||
"assembly[3].assetPath": "runtimes/osx-arm64/lib/net10.0/StellaOps.Logging.dll",
|
||||
"assembly[3].rid[0]": "osx-arm64",
|
||||
"assembly[3].tfm[0]": ".NETCoreApp,Version=v10.0",
|
||||
"deps.path[0]": "AppA.deps.json",
|
||||
"deps.path[1]": "AppB.deps.json",
|
||||
"deps.rid[0]": "linux-arm64",
|
||||
"deps.rid[1]": "linux-x64",
|
||||
"deps.rid[2]": "osx-arm64",
|
||||
"deps.rid[3]": "win-arm64",
|
||||
"deps.tfm[0]": ".NETCoreApp,Version=v10.0",
|
||||
"license.expression[0]": "Apache-2.0",
|
||||
"native[0].assetPath": "runtimes/win-arm64/native/stellaops.logging.dll",
|
||||
"native[0].rid[0]": "win-arm64",
|
||||
"native[0].tfm[0]": ".NETCoreApp,Version=v10.0",
|
||||
"package.hashPath[0]": "stellaops.logging.2.5.1.nupkg.sha512",
|
||||
"package.id": "StellaOps.Logging",
|
||||
"package.id.normalized": "stellaops.logging",
|
||||
"package.path[0]": "stellaops.logging/2.5.1",
|
||||
"package.serviceable": "true",
|
||||
"package.sha512[0]": "sha512-FAKE_LOGGING_SHA==",
|
||||
"package.version": "2.5.1",
|
||||
"provenance": "manifest"
|
||||
},
|
||||
"evidence": [
|
||||
{
|
||||
"kind": "file",
|
||||
"source": "deps.json",
|
||||
"locator": "AppA.deps.json",
|
||||
"value": "StellaOps.Logging/2.5.1"
|
||||
},
|
||||
{
|
||||
"kind": "file",
|
||||
"source": "deps.json",
|
||||
"locator": "AppB.deps.json",
|
||||
"value": "StellaOps.Logging/2.5.1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"analyzerId": "dotnet",
|
||||
"componentKey": "purl::pkg:nuget/stellaops.toolkit@1.2.3",
|
||||
"purl": "pkg:nuget/stellaops.toolkit@1.2.3",
|
||||
"name": "StellaOps.Toolkit",
|
||||
"version": "1.2.3",
|
||||
"type": "nuget",
|
||||
"usedByEntrypoint": false,
|
||||
"metadata": {
|
||||
"assembly[0].assetPath": "lib/net10.0/StellaOps.Toolkit.dll",
|
||||
"assembly[0].fileVersion": "1.2.3.0",
|
||||
"assembly[0].tfm[0]": ".NETCoreApp,Version=v10.0",
|
||||
"assembly[0].version": "1.2.3.0",
|
||||
"deps.dependency[0]": "stellaops.logging",
|
||||
"deps.path[0]": "AppA.deps.json",
|
||||
"deps.path[1]": "AppB.deps.json",
|
||||
"deps.rid[0]": "linux-x64",
|
||||
"deps.rid[1]": "osx-arm64",
|
||||
"deps.rid[2]": "win-arm64",
|
||||
"deps.tfm[0]": ".NETCoreApp,Version=v10.0",
|
||||
"license.file.sha256[0]": "604e182900b0ecb1ffb911c817bcbd148a31b8f55ad392a3b770be8005048c5c",
|
||||
"license.file[0]": "packages/stellaops.toolkit/1.2.3/LICENSE.txt",
|
||||
"native[0].assetPath": "runtimes/linux-x64/native/libstellaops.toolkit.so",
|
||||
"native[0].rid[0]": "linux-x64",
|
||||
"native[0].tfm[0]": ".NETCoreApp,Version=v10.0",
|
||||
"native[1].assetPath": "runtimes/osx-arm64/native/libstellaops.toolkit.dylib",
|
||||
"native[1].rid[0]": "osx-arm64",
|
||||
"native[1].tfm[0]": ".NETCoreApp,Version=v10.0",
|
||||
"native[2].assetPath": "runtimes/win-arm64/native/stellaops.toolkit.dll",
|
||||
"native[2].rid[0]": "win-arm64",
|
||||
"native[2].tfm[0]": ".NETCoreApp,Version=v10.0",
|
||||
"package.hashPath[0]": "stellaops.toolkit.1.2.3.nupkg.sha512",
|
||||
"package.id": "StellaOps.Toolkit",
|
||||
"package.id.normalized": "stellaops.toolkit",
|
||||
"package.path[0]": "stellaops.toolkit/1.2.3",
|
||||
"package.serviceable": "true",
|
||||
"package.sha512[0]": "sha512-FAKE_TOOLKIT_SHA==",
|
||||
"package.version": "1.2.3",
|
||||
"provenance": "manifest"
|
||||
},
|
||||
"evidence": [
|
||||
{
|
||||
"kind": "file",
|
||||
"source": "deps.json",
|
||||
"locator": "AppA.deps.json",
|
||||
"value": "StellaOps.Toolkit/1.2.3"
|
||||
},
|
||||
{
|
||||
"kind": "file",
|
||||
"source": "deps.json",
|
||||
"locator": "AppB.deps.json",
|
||||
"value": "StellaOps.Toolkit/1.2.3"
|
||||
},
|
||||
{
|
||||
"kind": "file",
|
||||
"source": "license",
|
||||
"locator": "packages/stellaops.toolkit/1.2.3/LICENSE.txt",
|
||||
"sha256": "604e182900b0ecb1ffb911c817bcbd148a31b8f55ad392a3b770be8005048c5c"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,15 @@
|
||||
StellaOps Logging
|
||||
|
||||
Copyright (c) 2025 StellaOps.
|
||||
|
||||
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
|
||||
|
||||
https://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.
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>StellaOps.Logging</id>
|
||||
<version>2.5.1</version>
|
||||
<authors>StellaOps</authors>
|
||||
<description>Logging sample package for analyzer fixtures.</description>
|
||||
<license type="expression">Apache-2.0</license>
|
||||
<licenseUrl>https://stella-ops.example/licenses/logging</licenseUrl>
|
||||
<projectUrl>https://stella-ops.example/projects/logging</projectUrl>
|
||||
</metadata>
|
||||
</package>
|
||||
@@ -0,0 +1,7 @@
|
||||
StellaOps Toolkit License
|
||||
=========================
|
||||
|
||||
This sample license is provided for test fixtures only.
|
||||
|
||||
Permission is granted to use, copy, modify, and distribute this fixture
|
||||
for the purpose of automated testing.
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>StellaOps.Toolkit</id>
|
||||
<version>1.2.3</version>
|
||||
<authors>StellaOps</authors>
|
||||
<description>Toolkit sample package for analyzer fixtures.</description>
|
||||
<license type="file">LICENSE.txt</license>
|
||||
<licenseUrl>https://stella-ops.example/licenses/toolkit</licenseUrl>
|
||||
</metadata>
|
||||
</package>
|
||||
@@ -0,0 +1,85 @@
|
||||
{
|
||||
"runtimeTarget": {
|
||||
"name": ".NETCoreApp,Version=v10.0",
|
||||
"signature": null
|
||||
},
|
||||
"targets": {
|
||||
".NETCoreApp,Version=v10.0/linux-x64": {
|
||||
"MyApp/1.0.0": {
|
||||
"dependencies": {
|
||||
"StellaOps.Toolkit": "1.2.3",
|
||||
"StellaOps.Runtime.SelfContained": "2.1.0"
|
||||
},
|
||||
"runtime": {
|
||||
"MyApp.dll": {}
|
||||
}
|
||||
},
|
||||
"StellaOps.Toolkit/1.2.3": {
|
||||
"runtime": {
|
||||
"lib/net10.0/StellaOps.Toolkit.dll": {
|
||||
"assemblyVersion": "1.2.3.0",
|
||||
"fileVersion": "1.2.3.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"StellaOps.Runtime.SelfContained/2.1.0": {
|
||||
"runtimeTargets": {
|
||||
"runtimes/linux-x64/native/libstellaopsnative.so": {
|
||||
"rid": "linux-x64",
|
||||
"assetType": "native"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
".NETCoreApp,Version=v10.0/win-x64": {
|
||||
"MyApp/1.0.0": {
|
||||
"dependencies": {
|
||||
"StellaOps.Toolkit": "1.2.3",
|
||||
"StellaOps.Runtime.SelfContained": "2.1.0"
|
||||
},
|
||||
"runtime": {
|
||||
"MyApp.dll": {}
|
||||
}
|
||||
},
|
||||
"StellaOps.Toolkit/1.2.3": {
|
||||
"runtime": {
|
||||
"lib/net10.0/StellaOps.Toolkit.dll": {
|
||||
"assemblyVersion": "1.2.3.0",
|
||||
"fileVersion": "1.2.3.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"StellaOps.Runtime.SelfContained/2.1.0": {
|
||||
"runtimeTargets": {
|
||||
"runtimes/win-x64/native/stellaopsnative.dll": {
|
||||
"rid": "win-x64",
|
||||
"assetType": "native"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"libraries": {
|
||||
"MyApp/1.0.0": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": "",
|
||||
"path": null,
|
||||
"hashPath": null
|
||||
},
|
||||
"StellaOps.Toolkit/1.2.3": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-FAKE_TOOLKIT_SHA==",
|
||||
"path": "stellaops.toolkit/1.2.3",
|
||||
"hashPath": "stellaops.toolkit.1.2.3.nupkg.sha512"
|
||||
},
|
||||
"StellaOps.Runtime.SelfContained/2.1.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-FAKE_RUNTIME_SHA==",
|
||||
"path": "stellaops.runtime.selfcontained/2.1.0",
|
||||
"hashPath": "stellaops.runtime.selfcontained.2.1.0.nupkg.sha512"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"runtimeOptions": {
|
||||
"tfm": "net10.0",
|
||||
"framework": {
|
||||
"name": "Microsoft.NETCore.App",
|
||||
"version": "10.0.0"
|
||||
},
|
||||
"includedFrameworks": [
|
||||
{
|
||||
"name": "Microsoft.NETCore.DotNetAppHost",
|
||||
"version": "10.0.0"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
[
|
||||
{
|
||||
"analyzerId": "dotnet",
|
||||
"componentKey": "purl::pkg:nuget/stellaops.runtime.selfcontained@2.1.0",
|
||||
"purl": "pkg:nuget/stellaops.runtime.selfcontained@2.1.0",
|
||||
"name": "StellaOps.Runtime.SelfContained",
|
||||
"version": "2.1.0",
|
||||
"type": "nuget",
|
||||
"usedByEntrypoint": true,
|
||||
"metadata": {
|
||||
"deps.path[0]": "MyApp.deps.json",
|
||||
"deps.rid[0]": "linux-x64",
|
||||
"deps.rid[1]": "win-x64",
|
||||
"deps.tfm[0]": ".NETCoreApp,Version=v10.0",
|
||||
"license.expression[0]": "Apache-2.0",
|
||||
"native[0].assetPath": "runtimes/linux-x64/native/libstellaopsnative.so",
|
||||
"native[0].path": "runtimes/linux-x64/native/libstellaopsnative.so",
|
||||
"native[0].rid[0]": "linux-x64",
|
||||
"native[0].sha256": "6cf3d2a487d6a42fc7c3e2edbc452224e99a3656287a534f1164ee6ec9daadf0",
|
||||
"native[0].tfm[0]": ".NETCoreApp,Version=v10.0",
|
||||
"native[1].assetPath": "runtimes/win-x64/native/stellaopsnative.dll",
|
||||
"native[1].rid[0]": "win-x64",
|
||||
"native[1].tfm[0]": ".NETCoreApp,Version=v10.0",
|
||||
"package.hashPath[0]": "stellaops.runtime.selfcontained.2.1.0.nupkg.sha512",
|
||||
"package.id": "StellaOps.Runtime.SelfContained",
|
||||
"package.id.normalized": "stellaops.runtime.selfcontained",
|
||||
"package.path[0]": "stellaops.runtime.selfcontained/2.1.0",
|
||||
"package.serviceable": "true",
|
||||
"package.sha512[0]": "sha512-FAKE_RUNTIME_SHA==",
|
||||
"package.version": "2.1.0",
|
||||
"provenance": "manifest"
|
||||
},
|
||||
"evidence": [
|
||||
{
|
||||
"kind": "file",
|
||||
"source": "deps.json",
|
||||
"locator": "MyApp.deps.json",
|
||||
"value": "StellaOps.Runtime.SelfContained/2.1.0"
|
||||
},
|
||||
{
|
||||
"kind": "file",
|
||||
"source": "native",
|
||||
"locator": "runtimes/linux-x64/native/libstellaopsnative.so",
|
||||
"value": "runtimes/linux-x64/native/libstellaopsnative.so",
|
||||
"sha256": "6cf3d2a487d6a42fc7c3e2edbc452224e99a3656287a534f1164ee6ec9daadf0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"analyzerId": "dotnet",
|
||||
"componentKey": "purl::pkg:nuget/stellaops.toolkit@1.2.3",
|
||||
"purl": "pkg:nuget/stellaops.toolkit@1.2.3",
|
||||
"name": "StellaOps.Toolkit",
|
||||
"version": "1.2.3",
|
||||
"type": "nuget",
|
||||
"usedByEntrypoint": false,
|
||||
"metadata": {
|
||||
"assembly[0].assetPath": "lib/net10.0/StellaOps.Toolkit.dll",
|
||||
"assembly[0].fileVersion": "1.2.3.0",
|
||||
"assembly[0].rid[0]": "linux-x64",
|
||||
"assembly[0].rid[1]": "win-x64",
|
||||
"assembly[0].tfm[0]": ".NETCoreApp,Version=v10.0",
|
||||
"assembly[0].version": "1.2.3.0",
|
||||
"deps.path[0]": "MyApp.deps.json",
|
||||
"deps.rid[0]": "linux-x64",
|
||||
"deps.rid[1]": "win-x64",
|
||||
"deps.tfm[0]": ".NETCoreApp,Version=v10.0",
|
||||
"license.file.sha256[0]": "f94d89a576c63e8ba6ee01760c52fa7861ba609491d7c6e6c01ead5ca66b6048",
|
||||
"license.file[0]": "packages/stellaops.toolkit/1.2.3/LICENSE.txt",
|
||||
"package.hashPath[0]": "stellaops.toolkit.1.2.3.nupkg.sha512",
|
||||
"package.id": "StellaOps.Toolkit",
|
||||
"package.id.normalized": "stellaops.toolkit",
|
||||
"package.path[0]": "stellaops.toolkit/1.2.3",
|
||||
"package.serviceable": "true",
|
||||
"package.sha512[0]": "sha512-FAKE_TOOLKIT_SHA==",
|
||||
"package.version": "1.2.3",
|
||||
"provenance": "manifest"
|
||||
},
|
||||
"evidence": [
|
||||
{
|
||||
"kind": "file",
|
||||
"source": "deps.json",
|
||||
"locator": "MyApp.deps.json",
|
||||
"value": "StellaOps.Toolkit/1.2.3"
|
||||
},
|
||||
{
|
||||
"kind": "file",
|
||||
"source": "license",
|
||||
"locator": "packages/stellaops.toolkit/1.2.3/LICENSE.txt",
|
||||
"sha256": "f94d89a576c63e8ba6ee01760c52fa7861ba609491d7c6e6c01ead5ca66b6048"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>StellaOps.Runtime.SelfContained</id>
|
||||
<version>2.1.0</version>
|
||||
<authors>StellaOps</authors>
|
||||
<description>Runtime bundle used for self-contained analyzer fixtures.</description>
|
||||
<license type="expression">Apache-2.0</license>
|
||||
<licenseUrl>https://stella-ops.example/licenses/runtime</licenseUrl>
|
||||
</metadata>
|
||||
</package>
|
||||
@@ -0,0 +1,6 @@
|
||||
StellaOps Toolkit License
|
||||
=========================
|
||||
|
||||
Reusable toolkit licensing terms for analyzer fixtures.
|
||||
|
||||
This document is intentionally short for deterministic hashing tests.
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>StellaOps.Toolkit</id>
|
||||
<version>1.2.3</version>
|
||||
<authors>StellaOps</authors>
|
||||
<description>Toolkit package for self-contained analyzer fixtures.</description>
|
||||
<license type="file">LICENSE.txt</license>
|
||||
<licenseUrl>https://stella-ops.example/licenses/toolkit</licenseUrl>
|
||||
</metadata>
|
||||
</package>
|
||||
@@ -0,0 +1 @@
|
||||
ELF FAKE STELLAOPS NATIVE LIB
|
||||
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"runtimeTarget": {
|
||||
"name": ".NETCoreApp,Version=v10.0/linux-x64"
|
||||
},
|
||||
"targets": {
|
||||
".NETCoreApp,Version=v10.0": {
|
||||
"Signed.App/1.0.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Logging": "9.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Logging/9.0.0": {
|
||||
"runtime": {
|
||||
"lib/net9.0/Microsoft.Extensions.Logging.dll": {
|
||||
"assemblyVersion": "9.0.0.0",
|
||||
"fileVersion": "9.0.24.52809"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
".NETCoreApp,Version=v10.0/linux-x64": {
|
||||
"Microsoft.Extensions.Logging/9.0.0": {
|
||||
"runtime": {
|
||||
"runtimes/linux-x64/lib/net9.0/Microsoft.Extensions.Logging.dll": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"libraries": {
|
||||
"Signed.App/1.0.0": {
|
||||
"type": "project",
|
||||
"serviceable": false
|
||||
},
|
||||
"Microsoft.Extensions.Logging/9.0.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-FAKE_LOGGING_SHA==",
|
||||
"path": "microsoft.extensions.logging/9.0.0",
|
||||
"hashPath": "microsoft.extensions.logging.9.0.0.nupkg.sha512"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"runtimeOptions": {
|
||||
"tfm": "net10.0",
|
||||
"framework": {
|
||||
"name": "Microsoft.NETCore.App",
|
||||
"version": "10.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
[
|
||||
{
|
||||
"analyzerId": "dotnet",
|
||||
"componentKey": "purl::pkg:nuget/microsoft.extensions.logging@9.0.0",
|
||||
"purl": "pkg:nuget/microsoft.extensions.logging@9.0.0",
|
||||
"name": "Microsoft.Extensions.Logging",
|
||||
"version": "9.0.0",
|
||||
"type": "nuget",
|
||||
"usedByEntrypoint": false,
|
||||
"metadata": {
|
||||
"assembly[0].assetPath": "lib/net9.0/Microsoft.Extensions.Logging.dll",
|
||||
"assembly[0].fileVersion": "9.0.24.52809",
|
||||
"assembly[0].tfm[0]": ".NETCoreApp,Version=v10.0",
|
||||
"assembly[0].version": "9.0.0.0",
|
||||
"assembly[1].assetPath": "runtimes/linux-x64/lib/net9.0/Microsoft.Extensions.Logging.dll",
|
||||
"assembly[1].rid[0]": "linux-x64",
|
||||
"assembly[1].tfm[0]": ".NETCoreApp,Version=v10.0",
|
||||
"deps.path[0]": "Signed.App.deps.json",
|
||||
"deps.rid[0]": "linux-x64",
|
||||
"deps.tfm[0]": ".NETCoreApp,Version=v10.0",
|
||||
"license.expression[0]": "MIT",
|
||||
"package.hashPath[0]": "microsoft.extensions.logging.9.0.0.nupkg.sha512",
|
||||
"package.id": "Microsoft.Extensions.Logging",
|
||||
"package.id.normalized": "microsoft.extensions.logging",
|
||||
"package.path[0]": "microsoft.extensions.logging/9.0.0",
|
||||
"package.serviceable": "true",
|
||||
"package.sha512[0]": "sha512-FAKE_LOGGING_SHA==",
|
||||
"package.version": "9.0.0",
|
||||
"provenance": "manifest"
|
||||
},
|
||||
"evidence": [
|
||||
{
|
||||
"kind": "file",
|
||||
"source": "deps.json",
|
||||
"locator": "Signed.App.deps.json",
|
||||
"value": "Microsoft.Extensions.Logging/9.0.0"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Microsoft.Extensions.Logging</id>
|
||||
<version>9.0.0</version>
|
||||
<authors>Microsoft</authors>
|
||||
<description>Signed logging package fixture.</description>
|
||||
<license type="expression">MIT</license>
|
||||
<licenseUrl>https://licenses.nuget.org/MIT</licenseUrl>
|
||||
</metadata>
|
||||
</package>
|
||||
@@ -0,0 +1,73 @@
|
||||
{
|
||||
"runtimeTarget": {
|
||||
"name": ".NETCoreApp,Version=v10.0/linux-x64"
|
||||
},
|
||||
"targets": {
|
||||
".NETCoreApp,Version=v10.0": {
|
||||
"Sample.App/1.0.0": {
|
||||
"dependencies": {
|
||||
"StellaOps.Toolkit": "1.2.3",
|
||||
"Microsoft.Extensions.Logging": "9.0.0"
|
||||
}
|
||||
},
|
||||
"StellaOps.Toolkit/1.2.3": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Logging": "9.0.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net10.0/StellaOps.Toolkit.dll": {
|
||||
"assemblyVersion": "1.2.3.0",
|
||||
"fileVersion": "1.2.3.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Logging/9.0.0": {
|
||||
"runtime": {
|
||||
"lib/net9.0/Microsoft.Extensions.Logging.dll": {
|
||||
"assemblyVersion": "9.0.0.0",
|
||||
"fileVersion": "9.0.24.52809"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
".NETCoreApp,Version=v10.0/linux-x64": {
|
||||
"StellaOps.Toolkit/1.2.3": {
|
||||
"runtime": {
|
||||
"runtimes/linux-x64/native/libstellaops.toolkit.so": {}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Logging/9.0.0": {
|
||||
"runtime": {
|
||||
"runtimes/linux-x64/lib/net9.0/Microsoft.Extensions.Logging.dll": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
".NETCoreApp,Version=v10.0/win-x86": {
|
||||
"Microsoft.Extensions.Logging/9.0.0": {
|
||||
"runtime": {
|
||||
"runtimes/win-x86/lib/net9.0/Microsoft.Extensions.Logging.dll": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"libraries": {
|
||||
"Sample.App/1.0.0": {
|
||||
"type": "project",
|
||||
"serviceable": false
|
||||
},
|
||||
"StellaOps.Toolkit/1.2.3": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-FAKE_TOOLKIT_SHA==",
|
||||
"path": "stellaops.toolkit/1.2.3",
|
||||
"hashPath": "stellaops.toolkit.1.2.3.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.Logging/9.0.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-FAKE_LOGGING_SHA==",
|
||||
"path": "microsoft.extensions.logging/9.0.0",
|
||||
"hashPath": "microsoft.extensions.logging.9.0.0.nupkg.sha512"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"runtimeOptions": {
|
||||
"tfm": "net10.0",
|
||||
"framework": {
|
||||
"name": "Microsoft.NETCore.App",
|
||||
"version": "10.0.0"
|
||||
},
|
||||
"frameworks": [
|
||||
{
|
||||
"name": "Microsoft.NETCore.App",
|
||||
"version": "10.0.0"
|
||||
},
|
||||
{
|
||||
"name": "Microsoft.AspNetCore.App",
|
||||
"version": "10.0.0"
|
||||
}
|
||||
],
|
||||
"runtimeGraph": {
|
||||
"runtimes": {
|
||||
"linux-x64": {
|
||||
"fallbacks": [
|
||||
"linux",
|
||||
"unix"
|
||||
]
|
||||
},
|
||||
"win-x86": {
|
||||
"fallbacks": [
|
||||
"win",
|
||||
"any"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
[
|
||||
{
|
||||
"analyzerId": "dotnet",
|
||||
"componentKey": "purl::pkg:nuget/microsoft.extensions.logging@9.0.0",
|
||||
"purl": "pkg:nuget/microsoft.extensions.logging@9.0.0",
|
||||
"name": "Microsoft.Extensions.Logging",
|
||||
"version": "9.0.0",
|
||||
"type": "nuget",
|
||||
"usedByEntrypoint": false,
|
||||
"metadata": {
|
||||
"assembly[0].assetPath": "lib/net9.0/Microsoft.Extensions.Logging.dll",
|
||||
"assembly[0].fileVersion": "9.0.24.52809",
|
||||
"assembly[0].tfm[0]": ".NETCoreApp,Version=v10.0",
|
||||
"assembly[0].version": "9.0.0.0",
|
||||
"assembly[1].assetPath": "runtimes/linux-x64/lib/net9.0/Microsoft.Extensions.Logging.dll",
|
||||
"assembly[1].rid[0]": "linux-x64",
|
||||
"assembly[1].tfm[0]": ".NETCoreApp,Version=v10.0",
|
||||
"assembly[2].assetPath": "runtimes/win-x86/lib/net9.0/Microsoft.Extensions.Logging.dll",
|
||||
"assembly[2].rid[0]": "win-x86",
|
||||
"assembly[2].tfm[0]": ".NETCoreApp,Version=v10.0",
|
||||
"deps.path[0]": "Sample.App.deps.json",
|
||||
"deps.rid[0]": "linux-x64",
|
||||
"deps.rid[1]": "win-x86",
|
||||
"deps.tfm[0]": ".NETCoreApp,Version=v10.0",
|
||||
"license.expression[0]": "MIT",
|
||||
"package.hashPath[0]": "microsoft.extensions.logging.9.0.0.nupkg.sha512",
|
||||
"package.id": "Microsoft.Extensions.Logging",
|
||||
"package.id.normalized": "microsoft.extensions.logging",
|
||||
"package.path[0]": "microsoft.extensions.logging/9.0.0",
|
||||
"package.serviceable": "true",
|
||||
"package.sha512[0]": "sha512-FAKE_LOGGING_SHA==",
|
||||
"package.version": "9.0.0",
|
||||
"provenance": "manifest"
|
||||
},
|
||||
"evidence": [
|
||||
{
|
||||
"kind": "file",
|
||||
"source": "deps.json",
|
||||
"locator": "Sample.App.deps.json",
|
||||
"value": "Microsoft.Extensions.Logging/9.0.0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"analyzerId": "dotnet",
|
||||
"componentKey": "purl::pkg:nuget/stellaops.toolkit@1.2.3",
|
||||
"purl": "pkg:nuget/stellaops.toolkit@1.2.3",
|
||||
"name": "StellaOps.Toolkit",
|
||||
"version": "1.2.3",
|
||||
"type": "nuget",
|
||||
"usedByEntrypoint": false,
|
||||
"metadata": {
|
||||
"assembly[0].assetPath": "lib/net10.0/StellaOps.Toolkit.dll",
|
||||
"assembly[0].fileVersion": "1.2.3.0",
|
||||
"assembly[0].tfm[0]": ".NETCoreApp,Version=v10.0",
|
||||
"assembly[0].version": "1.2.3.0",
|
||||
"deps.dependency[0]": "microsoft.extensions.logging",
|
||||
"deps.path[0]": "Sample.App.deps.json",
|
||||
"deps.rid[0]": "linux-x64",
|
||||
"deps.tfm[0]": ".NETCoreApp,Version=v10.0",
|
||||
"license.file.sha256[0]": "604e182900b0ecb1ffb911c817bcbd148a31b8f55ad392a3b770be8005048c5c",
|
||||
"license.file[0]": "packages/stellaops.toolkit/1.2.3/LICENSE.txt",
|
||||
"package.hashPath[0]": "stellaops.toolkit.1.2.3.nupkg.sha512",
|
||||
"package.id": "StellaOps.Toolkit",
|
||||
"package.id.normalized": "stellaops.toolkit",
|
||||
"package.path[0]": "stellaops.toolkit/1.2.3",
|
||||
"package.serviceable": "true",
|
||||
"package.sha512[0]": "sha512-FAKE_TOOLKIT_SHA==",
|
||||
"package.version": "1.2.3",
|
||||
"provenance": "manifest"
|
||||
},
|
||||
"evidence": [
|
||||
{
|
||||
"kind": "file",
|
||||
"source": "deps.json",
|
||||
"locator": "Sample.App.deps.json",
|
||||
"value": "StellaOps.Toolkit/1.2.3"
|
||||
},
|
||||
{
|
||||
"kind": "file",
|
||||
"source": "license",
|
||||
"locator": "packages/stellaops.toolkit/1.2.3/LICENSE.txt",
|
||||
"sha256": "604e182900b0ecb1ffb911c817bcbd148a31b8f55ad392a3b770be8005048c5c"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Microsoft.Extensions.Logging</id>
|
||||
<version>9.0.0</version>
|
||||
<authors>Microsoft</authors>
|
||||
<description>Logging abstractions for StellaOps test fixture.</description>
|
||||
<license type="expression">MIT</license>
|
||||
<licenseUrl>https://licenses.nuget.org/MIT</licenseUrl>
|
||||
</metadata>
|
||||
</package>
|
||||
@@ -0,0 +1,7 @@
|
||||
StellaOps Toolkit License
|
||||
=========================
|
||||
|
||||
This sample license is provided for test fixtures only.
|
||||
|
||||
Permission is granted to use, copy, modify, and distribute this fixture
|
||||
for the purpose of automated testing.
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>StellaOps.Toolkit</id>
|
||||
<version>1.2.3</version>
|
||||
<authors>StellaOps</authors>
|
||||
<description>Toolkit sample package for analyzer fixtures.</description>
|
||||
<license type="file">LICENSE.txt</license>
|
||||
<licenseUrl>https://stella-ops.example/licenses/toolkit</licenseUrl>
|
||||
</metadata>
|
||||
</package>
|
||||
12
src/Scanner/__Tests/StellaOps.Scanner.Analyzers.Lang.Tests/Fixtures/lang/rust/simple/Cargo.lock
generated
Normal file
12
src/Scanner/__Tests/StellaOps.Scanner.Analyzers.Lang.Tests/Fixtures/lang/rust/simple/Cargo.lock
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
[[package]]
|
||||
name = "my_app"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.188"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abc123"
|
||||
@@ -0,0 +1,62 @@
|
||||
[
|
||||
{
|
||||
"analyzerId": "rust",
|
||||
"componentKey": "purl::pkg:cargo/my_app@0.1.0",
|
||||
"purl": "pkg:cargo/my_app@0.1.0",
|
||||
"name": "my_app",
|
||||
"version": "0.1.0",
|
||||
"type": "cargo",
|
||||
"usedByEntrypoint": false,
|
||||
"metadata": {
|
||||
"cargo.lock.path": "Cargo.lock",
|
||||
"fingerprint.profile": "debug",
|
||||
"fingerprint.targetKind": "bin",
|
||||
"source": "registry\u002Bhttps://github.com/rust-lang/crates.io-index"
|
||||
},
|
||||
"evidence": [
|
||||
{
|
||||
"kind": "file",
|
||||
"source": "cargo.fingerprint",
|
||||
"locator": "target/debug/.fingerprint/my_app-1234567890abcdef/bin-my_app-1234567890abcdef.json",
|
||||
"value": "bin"
|
||||
},
|
||||
{
|
||||
"kind": "file",
|
||||
"source": "cargo.lock",
|
||||
"locator": "Cargo.lock",
|
||||
"value": "my_app 0.1.0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"analyzerId": "rust",
|
||||
"componentKey": "purl::pkg:cargo/serde@1.0.188",
|
||||
"purl": "pkg:cargo/serde@1.0.188",
|
||||
"name": "serde",
|
||||
"version": "1.0.188",
|
||||
"type": "cargo",
|
||||
"usedByEntrypoint": false,
|
||||
"metadata": {
|
||||
"cargo.lock.path": "Cargo.lock",
|
||||
"checksum": "abc123",
|
||||
"fingerprint.profile": "release",
|
||||
"fingerprint.targetKind": "lib",
|
||||
"source": "registry\u002Bhttps://github.com/rust-lang/crates.io-index"
|
||||
},
|
||||
"evidence": [
|
||||
{
|
||||
"kind": "file",
|
||||
"source": "cargo.fingerprint",
|
||||
"locator": "target/debug/.fingerprint/serde-abcdef1234567890/libserde-abcdef1234567890.json",
|
||||
"value": "lib"
|
||||
},
|
||||
{
|
||||
"kind": "file",
|
||||
"source": "cargo.lock",
|
||||
"locator": "Cargo.lock",
|
||||
"value": "serde 1.0.188",
|
||||
"sha256": "abc123"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"pkgid": "my_app 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"profile": "debug",
|
||||
"target_kind": ["bin"]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"pkgid": "serde 1.0.188 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"profile": "release",
|
||||
"target_kind": ["lib"]
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using StellaOps.Scanner.Analyzers.Lang;
|
||||
|
||||
namespace StellaOps.Scanner.Analyzers.Lang.Tests.Harness;
|
||||
|
||||
public static class LanguageAnalyzerTestHarness
|
||||
{
|
||||
public static async Task<string> RunToJsonAsync(string fixturePath, IEnumerable<ILanguageAnalyzer> analyzers, CancellationToken cancellationToken = default, LanguageUsageHints? usageHints = null, IServiceProvider? services = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(fixturePath))
|
||||
{
|
||||
throw new ArgumentException("Fixture path is required", nameof(fixturePath));
|
||||
}
|
||||
|
||||
var engine = new LanguageAnalyzerEngine(analyzers ?? Array.Empty<ILanguageAnalyzer>());
|
||||
var context = new LanguageAnalyzerContext(fixturePath, TimeProvider.System, usageHints, services);
|
||||
var result = await engine.AnalyzeAsync(context, cancellationToken).ConfigureAwait(false);
|
||||
return result.ToJson(indent: true);
|
||||
}
|
||||
|
||||
public static async Task AssertDeterministicAsync(string fixturePath, string goldenPath, IEnumerable<ILanguageAnalyzer> analyzers, CancellationToken cancellationToken = default, LanguageUsageHints? usageHints = null, IServiceProvider? services = null)
|
||||
{
|
||||
var actual = await RunToJsonAsync(fixturePath, analyzers, cancellationToken, usageHints, services).ConfigureAwait(false);
|
||||
var expected = await File.ReadAllTextAsync(goldenPath, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// Normalize newlines for portability.
|
||||
actual = NormalizeLineEndings(actual).TrimEnd();
|
||||
expected = NormalizeLineEndings(expected).TrimEnd();
|
||||
|
||||
if (!string.Equals(expected, actual, StringComparison.Ordinal))
|
||||
{
|
||||
var actualPath = goldenPath + ".actual";
|
||||
var directory = Path.GetDirectoryName(actualPath);
|
||||
if (!string.IsNullOrEmpty(directory))
|
||||
{
|
||||
Directory.CreateDirectory(directory);
|
||||
}
|
||||
|
||||
await File.WriteAllTextAsync(actualPath, actual, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
private static string NormalizeLineEndings(string value)
|
||||
=> value.Replace("\r\n", "\n", StringComparison.Ordinal);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System.IO;
|
||||
using StellaOps.Scanner.Analyzers.Lang.Rust;
|
||||
using StellaOps.Scanner.Analyzers.Lang.Tests.Harness;
|
||||
using StellaOps.Scanner.Analyzers.Lang.Tests.TestUtilities;
|
||||
|
||||
namespace StellaOps.Scanner.Analyzers.Lang.Tests.Rust;
|
||||
|
||||
public sealed class RustLanguageAnalyzerTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task SimpleFixtureProducesDeterministicOutputAsync()
|
||||
{
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
var fixturePath = TestPaths.ResolveFixture("lang", "rust", "simple");
|
||||
var goldenPath = Path.Combine(fixturePath, "expected.json");
|
||||
|
||||
var usageHints = new LanguageUsageHints(new[]
|
||||
{
|
||||
Path.Combine(fixturePath, "usr/local/bin/my_app")
|
||||
});
|
||||
|
||||
var analyzers = new ILanguageAnalyzer[]
|
||||
{
|
||||
new RustLanguageAnalyzer()
|
||||
};
|
||||
|
||||
await LanguageAnalyzerTestHarness.AssertDeterministicAsync(
|
||||
fixturePath,
|
||||
goldenPath,
|
||||
analyzers,
|
||||
cancellationToken,
|
||||
usageHints);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<IsPackable>false</IsPackable>
|
||||
<OutputType>Exe</OutputType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Remove="Microsoft.NET.Test.Sdk" />
|
||||
<PackageReference Remove="xunit" />
|
||||
<PackageReference Remove="xunit.runner.visualstudio" />
|
||||
<PackageReference Remove="Microsoft.AspNetCore.Mvc.Testing" />
|
||||
<PackageReference Remove="Mongo2Go" />
|
||||
<PackageReference Remove="coverlet.collector" />
|
||||
<PackageReference Remove="Microsoft.Extensions.TimeProvider.Testing" />
|
||||
<ProjectReference Remove="..\StellaOps.Concelier.Testing\StellaOps.Concelier.Testing.csproj" />
|
||||
<Compile Remove="$(MSBuildThisFileDirectory)..\StellaOps.Concelier.Tests.Shared\AssemblyInfo.cs" />
|
||||
<Compile Remove="$(MSBuildThisFileDirectory)..\StellaOps.Concelier.Tests.Shared\MongoFixtureCollection.cs" />
|
||||
<Using Remove="StellaOps.Concelier.Testing" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||
<PackageReference Include="xunit.v3" Version="3.0.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../../__Libraries/StellaOps.Scanner.Analyzers.Lang/StellaOps.Scanner.Analyzers.Lang.csproj" />
|
||||
<ProjectReference Include="../../__Libraries/StellaOps.Scanner.Analyzers.Lang.DotNet/StellaOps.Scanner.Analyzers.Lang.DotNet.csproj" />
|
||||
<ProjectReference Include="../../__Libraries/StellaOps.Scanner.Analyzers.Lang.Rust/StellaOps.Scanner.Analyzers.Lang.Rust.csproj" />
|
||||
<ProjectReference Include="../../__Libraries/StellaOps.Scanner.Core/StellaOps.Scanner.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="Fixtures\**\*" CopyToOutputDirectory="PreserveNewest" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,202 @@
|
||||
using System.Buffers.Binary;
|
||||
using System.Text;
|
||||
|
||||
namespace StellaOps.Scanner.Analyzers.Lang.Tests.TestUtilities;
|
||||
|
||||
public static class JavaClassFileFactory
|
||||
{
|
||||
public static byte[] CreateClassForNameInvoker(string internalClassName, string targetClassName)
|
||||
{
|
||||
using var buffer = new MemoryStream();
|
||||
using var writer = new BigEndianWriter(buffer);
|
||||
|
||||
WriteClassFileHeader(writer, constantPoolCount: 16);
|
||||
|
||||
writer.WriteByte((byte)ConstantTag.Utf8); writer.WriteUtf8(internalClassName); // #1
|
||||
writer.WriteByte((byte)ConstantTag.Class); writer.WriteUInt16(1); // #2
|
||||
writer.WriteByte((byte)ConstantTag.Utf8); writer.WriteUtf8("java/lang/Object"); // #3
|
||||
writer.WriteByte((byte)ConstantTag.Class); writer.WriteUInt16(3); // #4
|
||||
writer.WriteByte((byte)ConstantTag.Utf8); writer.WriteUtf8("invoke"); // #5
|
||||
writer.WriteByte((byte)ConstantTag.Utf8); writer.WriteUtf8("()V"); // #6
|
||||
writer.WriteByte((byte)ConstantTag.Utf8); writer.WriteUtf8("Code"); // #7
|
||||
writer.WriteByte((byte)ConstantTag.Utf8); writer.WriteUtf8(targetClassName); // #8
|
||||
writer.WriteByte((byte)ConstantTag.String); writer.WriteUInt16(8); // #9
|
||||
writer.WriteByte((byte)ConstantTag.Utf8); writer.WriteUtf8("java/lang/Class"); // #10
|
||||
writer.WriteByte((byte)ConstantTag.Class); writer.WriteUInt16(10); // #11
|
||||
writer.WriteByte((byte)ConstantTag.Utf8); writer.WriteUtf8("forName"); // #12
|
||||
writer.WriteByte((byte)ConstantTag.Utf8); writer.WriteUtf8("(Ljava/lang/String;)Ljava/lang/Class;"); // #13
|
||||
writer.WriteByte((byte)ConstantTag.NameAndType); writer.WriteUInt16(12); writer.WriteUInt16(13); // #14
|
||||
writer.WriteByte((byte)ConstantTag.Methodref); writer.WriteUInt16(11); writer.WriteUInt16(14); // #15
|
||||
|
||||
writer.WriteUInt16(0x0001); // public
|
||||
writer.WriteUInt16(2); // this class
|
||||
writer.WriteUInt16(4); // super class
|
||||
|
||||
writer.WriteUInt16(0); // interfaces
|
||||
writer.WriteUInt16(0); // fields
|
||||
writer.WriteUInt16(1); // methods
|
||||
|
||||
WriteInvokeMethod(writer, methodNameIndex: 5, descriptorIndex: 6, ldcIndex: 9, methodRefIndex: 15);
|
||||
|
||||
writer.WriteUInt16(0); // class attributes
|
||||
|
||||
return buffer.ToArray();
|
||||
}
|
||||
|
||||
public static byte[] CreateTcclChecker(string internalClassName)
|
||||
{
|
||||
using var buffer = new MemoryStream();
|
||||
using var writer = new BigEndianWriter(buffer);
|
||||
|
||||
WriteClassFileHeader(writer, constantPoolCount: 18);
|
||||
|
||||
writer.WriteByte((byte)ConstantTag.Utf8); writer.WriteUtf8(internalClassName); // #1
|
||||
writer.WriteByte((byte)ConstantTag.Class); writer.WriteUInt16(1); // #2
|
||||
writer.WriteByte((byte)ConstantTag.Utf8); writer.WriteUtf8("java/lang/Object"); // #3
|
||||
writer.WriteByte((byte)ConstantTag.Class); writer.WriteUInt16(3); // #4
|
||||
writer.WriteByte((byte)ConstantTag.Utf8); writer.WriteUtf8("check"); // #5
|
||||
writer.WriteByte((byte)ConstantTag.Utf8); writer.WriteUtf8("()V"); // #6
|
||||
writer.WriteByte((byte)ConstantTag.Utf8); writer.WriteUtf8("Code"); // #7
|
||||
writer.WriteByte((byte)ConstantTag.Utf8); writer.WriteUtf8("java/lang/Thread"); // #8
|
||||
writer.WriteByte((byte)ConstantTag.Class); writer.WriteUInt16(8); // #9
|
||||
writer.WriteByte((byte)ConstantTag.Utf8); writer.WriteUtf8("currentThread"); // #10
|
||||
writer.WriteByte((byte)ConstantTag.Utf8); writer.WriteUtf8("()Ljava/lang/Thread;"); // #11
|
||||
writer.WriteByte((byte)ConstantTag.NameAndType); writer.WriteUInt16(10); writer.WriteUInt16(11); // #12
|
||||
writer.WriteByte((byte)ConstantTag.Methodref); writer.WriteUInt16(9); writer.WriteUInt16(12); // #13
|
||||
writer.WriteByte((byte)ConstantTag.Utf8); writer.WriteUtf8("getContextClassLoader"); // #14
|
||||
writer.WriteByte((byte)ConstantTag.Utf8); writer.WriteUtf8("()Ljava/lang/ClassLoader;"); // #15
|
||||
writer.WriteByte((byte)ConstantTag.NameAndType); writer.WriteUInt16(14); writer.WriteUInt16(15); // #16
|
||||
writer.WriteByte((byte)ConstantTag.Methodref); writer.WriteUInt16(9); writer.WriteUInt16(16); // #17
|
||||
|
||||
writer.WriteUInt16(0x0001); // public
|
||||
writer.WriteUInt16(2); // this
|
||||
writer.WriteUInt16(4); // super
|
||||
|
||||
writer.WriteUInt16(0); // interfaces
|
||||
writer.WriteUInt16(0); // fields
|
||||
writer.WriteUInt16(1); // methods
|
||||
|
||||
WriteTcclMethod(writer, methodNameIndex: 5, descriptorIndex: 6, currentThreadMethodRefIndex: 13, getContextMethodRefIndex: 17);
|
||||
|
||||
writer.WriteUInt16(0); // class attributes
|
||||
|
||||
return buffer.ToArray();
|
||||
}
|
||||
|
||||
private static void WriteClassFileHeader(BigEndianWriter writer, ushort constantPoolCount)
|
||||
{
|
||||
writer.WriteUInt32(0xCAFEBABE);
|
||||
writer.WriteUInt16(0);
|
||||
writer.WriteUInt16(52);
|
||||
writer.WriteUInt16(constantPoolCount);
|
||||
}
|
||||
|
||||
private static void WriteInvokeMethod(BigEndianWriter writer, ushort methodNameIndex, ushort descriptorIndex, ushort ldcIndex, ushort methodRefIndex)
|
||||
{
|
||||
writer.WriteUInt16(0x0009); // public static
|
||||
writer.WriteUInt16(methodNameIndex);
|
||||
writer.WriteUInt16(descriptorIndex);
|
||||
writer.WriteUInt16(1); // attributes_count
|
||||
|
||||
writer.WriteUInt16(7); // "Code"
|
||||
using var codeBuffer = new MemoryStream();
|
||||
using (var codeWriter = new BigEndianWriter(codeBuffer))
|
||||
{
|
||||
codeWriter.WriteUInt16(1); // max_stack
|
||||
codeWriter.WriteUInt16(0); // max_locals
|
||||
codeWriter.WriteUInt32(6); // code_length
|
||||
codeWriter.WriteByte(0x12);
|
||||
codeWriter.WriteByte((byte)ldcIndex);
|
||||
codeWriter.WriteByte(0xB8);
|
||||
codeWriter.WriteUInt16(methodRefIndex);
|
||||
codeWriter.WriteByte(0xB1);
|
||||
codeWriter.WriteUInt16(0); // exception table length
|
||||
codeWriter.WriteUInt16(0); // code attributes
|
||||
}
|
||||
|
||||
var codeBytes = codeBuffer.ToArray();
|
||||
writer.WriteUInt32((uint)codeBytes.Length);
|
||||
writer.WriteBytes(codeBytes);
|
||||
}
|
||||
|
||||
private static void WriteTcclMethod(BigEndianWriter writer, ushort methodNameIndex, ushort descriptorIndex, ushort currentThreadMethodRefIndex, ushort getContextMethodRefIndex)
|
||||
{
|
||||
writer.WriteUInt16(0x0009);
|
||||
writer.WriteUInt16(methodNameIndex);
|
||||
writer.WriteUInt16(descriptorIndex);
|
||||
writer.WriteUInt16(1);
|
||||
|
||||
writer.WriteUInt16(7);
|
||||
using var codeBuffer = new MemoryStream();
|
||||
using (var codeWriter = new BigEndianWriter(codeBuffer))
|
||||
{
|
||||
codeWriter.WriteUInt16(2);
|
||||
codeWriter.WriteUInt16(0);
|
||||
codeWriter.WriteUInt32(8);
|
||||
codeWriter.WriteByte(0xB8);
|
||||
codeWriter.WriteUInt16(currentThreadMethodRefIndex);
|
||||
codeWriter.WriteByte(0xB6);
|
||||
codeWriter.WriteUInt16(getContextMethodRefIndex);
|
||||
codeWriter.WriteByte(0x57);
|
||||
codeWriter.WriteByte(0xB1);
|
||||
codeWriter.WriteUInt16(0);
|
||||
codeWriter.WriteUInt16(0);
|
||||
}
|
||||
|
||||
var codeBytes = codeBuffer.ToArray();
|
||||
writer.WriteUInt32((uint)codeBytes.Length);
|
||||
writer.WriteBytes(codeBytes);
|
||||
}
|
||||
|
||||
private sealed class BigEndianWriter : IDisposable
|
||||
{
|
||||
private readonly BinaryWriter _writer;
|
||||
|
||||
public BigEndianWriter(Stream stream)
|
||||
{
|
||||
_writer = new BinaryWriter(stream, Encoding.UTF8, leaveOpen: true);
|
||||
}
|
||||
|
||||
public void WriteByte(byte value) => _writer.Write(value);
|
||||
|
||||
public void WriteBytes(byte[] data) => _writer.Write(data);
|
||||
|
||||
public void WriteUInt16(ushort value)
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[2];
|
||||
BinaryPrimitives.WriteUInt16BigEndian(buffer, value);
|
||||
_writer.Write(buffer);
|
||||
}
|
||||
|
||||
public void WriteUInt32(uint value)
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[4];
|
||||
BinaryPrimitives.WriteUInt32BigEndian(buffer, value);
|
||||
_writer.Write(buffer);
|
||||
}
|
||||
|
||||
public void WriteUtf8(string value)
|
||||
{
|
||||
var bytes = Encoding.UTF8.GetBytes(value);
|
||||
WriteUInt16((ushort)bytes.Length);
|
||||
_writer.Write(bytes);
|
||||
}
|
||||
|
||||
public void Dispose() => _writer.Dispose();
|
||||
}
|
||||
|
||||
private enum ConstantTag : byte
|
||||
{
|
||||
Utf8 = 1,
|
||||
Integer = 3,
|
||||
Float = 4,
|
||||
Long = 5,
|
||||
Double = 6,
|
||||
Class = 7,
|
||||
String = 8,
|
||||
Fieldref = 9,
|
||||
Methodref = 10,
|
||||
InterfaceMethodref = 11,
|
||||
NameAndType = 12,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
using System.IO.Compression;
|
||||
using System.Text;
|
||||
|
||||
namespace StellaOps.Scanner.Analyzers.Lang.Tests.TestUtilities;
|
||||
|
||||
public static class JavaFixtureBuilder
|
||||
{
|
||||
private static readonly DateTimeOffset DefaultTimestamp = new(2024, 01, 01, 0, 0, 0, TimeSpan.Zero);
|
||||
|
||||
public static string CreateSampleJar(string rootDirectory, string relativePath = "libs/demo.jar")
|
||||
=> CreateJar(rootDirectory, relativePath, static archive =>
|
||||
{
|
||||
var pomEntry = archive.CreateEntry("META-INF/maven/com.example/demo/pom.properties", CompressionLevel.NoCompression);
|
||||
pomEntry.LastWriteTime = DefaultTimestamp;
|
||||
using (var writer = new StreamWriter(pomEntry.Open(), Encoding.UTF8, leaveOpen: false))
|
||||
{
|
||||
writer.WriteLine("# Test pom.properties");
|
||||
writer.WriteLine("groupId=com.example");
|
||||
writer.WriteLine("artifactId=demo");
|
||||
writer.WriteLine("version=1.0.0");
|
||||
writer.WriteLine("name=Demo Library");
|
||||
writer.WriteLine("packaging=jar");
|
||||
}
|
||||
|
||||
var manifestEntry = archive.CreateEntry("META-INF/MANIFEST.MF", CompressionLevel.NoCompression);
|
||||
manifestEntry.LastWriteTime = DefaultTimestamp;
|
||||
using (var manifestWriter = new StreamWriter(manifestEntry.Open(), Encoding.UTF8, leaveOpen: false))
|
||||
{
|
||||
manifestWriter.WriteLine("Manifest-Version: 1.0");
|
||||
manifestWriter.WriteLine("Implementation-Title: Demo");
|
||||
manifestWriter.WriteLine("Implementation-Version: 1.0.0");
|
||||
manifestWriter.WriteLine("Implementation-Vendor: Example Corp");
|
||||
manifestWriter.WriteLine();
|
||||
}
|
||||
|
||||
var classEntry = archive.CreateEntry("com/example/Demo.class", CompressionLevel.NoCompression);
|
||||
classEntry.LastWriteTime = DefaultTimestamp;
|
||||
using (var classWriter = new BinaryWriter(classEntry.Open(), Encoding.UTF8, leaveOpen: false))
|
||||
{
|
||||
classWriter.Write(new byte[] { 0xCA, 0xFE, 0xBA, 0xBE });
|
||||
}
|
||||
});
|
||||
|
||||
public static string CreateSpringBootFatJar(string rootDirectory, string relativePath = "libs/app-fat.jar")
|
||||
=> CreateJar(rootDirectory, relativePath, static archive =>
|
||||
{
|
||||
var manifestEntry = archive.CreateEntry("META-INF/MANIFEST.MF", CompressionLevel.NoCompression);
|
||||
manifestEntry.LastWriteTime = DefaultTimestamp;
|
||||
using (var writer = new StreamWriter(manifestEntry.Open(), Encoding.UTF8, leaveOpen: false))
|
||||
{
|
||||
writer.WriteLine("Manifest-Version: 1.0");
|
||||
writer.WriteLine("Main-Class: org.springframework.boot.loader.JarLauncher");
|
||||
writer.WriteLine();
|
||||
}
|
||||
|
||||
var bootClasses = archive.CreateEntry("BOOT-INF/classes/com/example/App.class", CompressionLevel.NoCompression);
|
||||
bootClasses.LastWriteTime = DefaultTimestamp;
|
||||
var appClassBytes = JavaClassFileFactory.CreateClassForNameInvoker("com/example/App", "com.example.boot.Plugin");
|
||||
using (var bootStream = bootClasses.Open())
|
||||
{
|
||||
bootStream.Write(appClassBytes);
|
||||
}
|
||||
|
||||
var bootService = archive.CreateEntry("BOOT-INF/classes/META-INF/services/java.sql.Driver", CompressionLevel.NoCompression);
|
||||
bootService.LastWriteTime = DefaultTimestamp;
|
||||
using (var serviceWriter = new StreamWriter(bootService.Open(), Encoding.UTF8, leaveOpen: false))
|
||||
{
|
||||
serviceWriter.WriteLine("com.example.AppDriver");
|
||||
}
|
||||
|
||||
using var libBuffer = new MemoryStream();
|
||||
using (var nested = new ZipArchive(libBuffer, ZipArchiveMode.Create, leaveOpen: true))
|
||||
{
|
||||
var libClass = nested.CreateEntry("com/example/Lib.class", CompressionLevel.NoCompression);
|
||||
libClass.LastWriteTime = DefaultTimestamp;
|
||||
var libClassBytes = JavaClassFileFactory.CreateClassForNameInvoker("com/example/Lib", "com.example.boot.Library");
|
||||
using (var libStream = libClass.Open())
|
||||
{
|
||||
libStream.Write(libClassBytes);
|
||||
}
|
||||
|
||||
var libService = nested.CreateEntry("META-INF/services/java.sql.Driver", CompressionLevel.NoCompression);
|
||||
libService.LastWriteTime = DefaultTimestamp;
|
||||
using (var libServiceWriter = new StreamWriter(libService.Open(), Encoding.UTF8, leaveOpen: false))
|
||||
{
|
||||
libServiceWriter.WriteLine("com.example.LibDriver");
|
||||
}
|
||||
}
|
||||
|
||||
libBuffer.Position = 0;
|
||||
var libEntry = archive.CreateEntry("BOOT-INF/lib/library.jar", CompressionLevel.NoCompression);
|
||||
libEntry.LastWriteTime = DefaultTimestamp;
|
||||
using var libEntryStream = libEntry.Open();
|
||||
libBuffer.CopyTo(libEntryStream);
|
||||
});
|
||||
|
||||
public static string CreateWarArchive(string rootDirectory, string relativePath = "apps/sample.war")
|
||||
=> CreateJar(rootDirectory, relativePath, static archive =>
|
||||
{
|
||||
var manifestEntry = archive.CreateEntry("META-INF/MANIFEST.MF", CompressionLevel.NoCompression);
|
||||
manifestEntry.LastWriteTime = DefaultTimestamp;
|
||||
using (var manifestWriter = new StreamWriter(manifestEntry.Open(), Encoding.UTF8, leaveOpen: false))
|
||||
{
|
||||
manifestWriter.WriteLine("Manifest-Version: 1.0");
|
||||
manifestWriter.WriteLine();
|
||||
}
|
||||
|
||||
var webXml = archive.CreateEntry("WEB-INF/web.xml", CompressionLevel.NoCompression);
|
||||
webXml.LastWriteTime = DefaultTimestamp;
|
||||
using (var webXmlWriter = new StreamWriter(webXml.Open(), Encoding.UTF8, leaveOpen: false))
|
||||
{
|
||||
webXmlWriter.WriteLine("<web-app/>");
|
||||
}
|
||||
|
||||
var webClass = archive.CreateEntry("WEB-INF/classes/com/example/Servlet.class", CompressionLevel.NoCompression);
|
||||
webClass.LastWriteTime = DefaultTimestamp;
|
||||
using (var classWriter = new BinaryWriter(webClass.Open(), Encoding.UTF8, leaveOpen: false))
|
||||
{
|
||||
classWriter.Write(new byte[] { 0xCA, 0xFE, 0xBA, 0xBE });
|
||||
}
|
||||
|
||||
using var libBuffer = new MemoryStream();
|
||||
using (var nested = new ZipArchive(libBuffer, ZipArchiveMode.Create, leaveOpen: true))
|
||||
{
|
||||
var libClass = nested.CreateEntry("com/example/WebLib.class", CompressionLevel.NoCompression);
|
||||
libClass.LastWriteTime = DefaultTimestamp;
|
||||
using var libWriter = new BinaryWriter(libClass.Open(), Encoding.UTF8, leaveOpen: false);
|
||||
libWriter.Write(new byte[] { 0xCA, 0xFE, 0xBA, 0xBE });
|
||||
}
|
||||
|
||||
libBuffer.Position = 0;
|
||||
var libEntry = archive.CreateEntry("WEB-INF/lib/web-lib.jar", CompressionLevel.NoCompression);
|
||||
libEntry.LastWriteTime = DefaultTimestamp;
|
||||
using var libStream = libEntry.Open();
|
||||
libBuffer.CopyTo(libStream);
|
||||
});
|
||||
|
||||
public static string CreateMultiReleaseJar(string rootDirectory, string relativePath = "libs/mr.jar")
|
||||
=> CreateJar(rootDirectory, relativePath, static archive =>
|
||||
{
|
||||
var manifestEntry = archive.CreateEntry("META-INF/MANIFEST.MF", CompressionLevel.NoCompression);
|
||||
manifestEntry.LastWriteTime = DefaultTimestamp;
|
||||
using (var writer = new StreamWriter(manifestEntry.Open(), Encoding.UTF8, leaveOpen: false))
|
||||
{
|
||||
writer.WriteLine("Manifest-Version: 1.0");
|
||||
writer.WriteLine("Multi-Release: true");
|
||||
writer.WriteLine();
|
||||
}
|
||||
|
||||
var baseClass = archive.CreateEntry("com/example/App.class", CompressionLevel.NoCompression);
|
||||
baseClass.LastWriteTime = DefaultTimestamp;
|
||||
using (var baseWriter = new BinaryWriter(baseClass.Open(), Encoding.UTF8, leaveOpen: false))
|
||||
{
|
||||
baseWriter.Write(new byte[] { 0xCA, 0xFE, 0xBA, 0xBE });
|
||||
}
|
||||
|
||||
var overlayClass = archive.CreateEntry("META-INF/versions/11/com/example/App.class", CompressionLevel.NoCompression);
|
||||
overlayClass.LastWriteTime = DefaultTimestamp.AddMinutes(1);
|
||||
using (var overlayWriter = new BinaryWriter(overlayClass.Open(), Encoding.UTF8, leaveOpen: false))
|
||||
{
|
||||
overlayWriter.Write(new byte[] { 0xFE, 0xED, 0xFA, 0xCE });
|
||||
}
|
||||
});
|
||||
|
||||
public static string CreateRuntimeImage(string rootDirectory, string relativePath = "runtime/jre")
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(rootDirectory);
|
||||
ArgumentException.ThrowIfNullOrEmpty(relativePath);
|
||||
|
||||
var runtimeRoot = Path.Combine(rootDirectory, relativePath.Replace('/', Path.DirectorySeparatorChar));
|
||||
Directory.CreateDirectory(runtimeRoot);
|
||||
Directory.CreateDirectory(Path.Combine(runtimeRoot, "bin"));
|
||||
|
||||
var javaBinary = OperatingSystem.IsWindows() ? "java.exe" : "java";
|
||||
File.WriteAllText(Path.Combine(runtimeRoot, "bin", javaBinary), string.Empty);
|
||||
|
||||
File.WriteAllText(
|
||||
Path.Combine(runtimeRoot, "release"),
|
||||
"JAVA_VERSION=\"17.0.8\"\nIMPLEMENTOR=\"Eclipse Adoptium\"\n");
|
||||
|
||||
return runtimeRoot;
|
||||
}
|
||||
|
||||
private static string CreateJar(string rootDirectory, string relativePath, Action<ZipArchive> configure)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(rootDirectory);
|
||||
ArgumentException.ThrowIfNullOrEmpty(relativePath);
|
||||
|
||||
var jarPath = Path.Combine(rootDirectory, relativePath.Replace('/', Path.DirectorySeparatorChar));
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(jarPath)!);
|
||||
|
||||
using var fileStream = new FileStream(jarPath, FileMode.Create, FileAccess.ReadWrite, FileShare.None);
|
||||
using var archive = new ZipArchive(fileStream, ZipArchiveMode.Create, leaveOpen: false);
|
||||
|
||||
configure(archive);
|
||||
|
||||
return jarPath;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
namespace StellaOps.Scanner.Analyzers.Lang.Tests.TestUtilities;
|
||||
|
||||
public static class TestPaths
|
||||
{
|
||||
public static string ResolveFixture(params string[] segments)
|
||||
{
|
||||
var baseDirectory = AppContext.BaseDirectory;
|
||||
var parts = new List<string> { baseDirectory };
|
||||
parts.AddRange(new[] { "Fixtures" });
|
||||
parts.AddRange(segments);
|
||||
return Path.GetFullPath(Path.Combine(parts.ToArray()));
|
||||
}
|
||||
|
||||
public static string CreateTemporaryDirectory()
|
||||
{
|
||||
var root = Path.Combine(AppContext.BaseDirectory, "tmp", Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(root);
|
||||
return root;
|
||||
}
|
||||
|
||||
public static void SafeDelete(string directory)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(directory) || !Directory.Exists(directory))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Directory.Delete(directory, recursive: true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Swallow cleanup exceptions to avoid masking test failures.
|
||||
}
|
||||
}
|
||||
|
||||
public static string ResolveProjectRoot()
|
||||
{
|
||||
var directory = AppContext.BaseDirectory;
|
||||
while (!string.IsNullOrEmpty(directory))
|
||||
{
|
||||
var matches = Directory.EnumerateFiles(directory, "StellaOps.Scanner.Analyzers.Lang*.Tests.csproj", SearchOption.TopDirectoryOnly);
|
||||
if (matches.Any())
|
||||
{
|
||||
return directory;
|
||||
}
|
||||
|
||||
directory = Path.GetDirectoryName(directory) ?? string.Empty;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Unable to locate project root.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"$schema": "https://xunit.net/schema/current/xunit.runner.schema.json"
|
||||
}
|
||||
Reference in New Issue
Block a user