up
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Notify Smoke Test / Notify Unit Tests (push) Has been cancelled
Notify Smoke Test / Notifier Service Tests (push) Has been cancelled
Notify Smoke Test / Notification Smoke Test (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Scanner Analyzers / Discover Analyzers (push) Has been cancelled
Scanner Analyzers / Build Analyzers (push) Has been cancelled
Scanner Analyzers / Test Language Analyzers (push) Has been cancelled
Scanner Analyzers / Validate Test Fixtures (push) Has been cancelled
Scanner Analyzers / Verify Deterministic Output (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled
Signals Reachability Scoring & Events / reachability-smoke (push) Has been cancelled
Signals Reachability Scoring & Events / sign-and-upload (push) Has been cancelled
Manifest Integrity / Validate Schema Integrity (push) Has been cancelled
Manifest Integrity / Validate Contract Documents (push) Has been cancelled
Manifest Integrity / Validate Pack Fixtures (push) Has been cancelled
Manifest Integrity / Audit SHA256SUMS Files (push) Has been cancelled
Manifest Integrity / Verify Merkle Roots (push) Has been cancelled
devportal-offline / build-offline (push) Has been cancelled
Mirror Thin Bundle Sign & Verify / mirror-sign (push) Has been cancelled

This commit is contained in:
StellaOps Bot
2025-12-13 18:08:55 +02:00
parent 6e45066e37
commit f1a39c4ce3
234 changed files with 24038 additions and 6910 deletions

View File

@@ -645,6 +645,211 @@ public sealed class JavaLanguageAnalyzerTests
#endregion
#region Multi-Module Gradle Lock & Runtime Image Tests (Sprint 0403)
[Fact]
public async Task MultiModuleGradleLockFilesEmitLockModulePathMetadataAsync()
{
var cancellationToken = TestContext.Current.CancellationToken;
var root = TestPaths.CreateTemporaryDirectory();
try
{
// Create root lockfile
var rootLockPath = Path.Combine(root, "gradle.lockfile");
await File.WriteAllTextAsync(rootLockPath, """
# Root lockfile
com.example:root-dep:1.0.0=compileClasspath
com.example:shared-dep:2.0.0=runtimeClasspath
""", cancellationToken);
// Create submodule directory and lockfile
var appModuleDir = Path.Combine(root, "app");
Directory.CreateDirectory(appModuleDir);
var appLockPath = Path.Combine(appModuleDir, "gradle.lockfile");
await File.WriteAllTextAsync(appLockPath, """
# App module lockfile
com.example:app-dep:3.0.0=compileClasspath
com.example:shared-dep:2.5.0=runtimeClasspath
""", cancellationToken);
// Create lib submodule directory and lockfile
var libModuleDir = Path.Combine(root, "lib");
Directory.CreateDirectory(libModuleDir);
var libLockPath = Path.Combine(libModuleDir, "gradle.lockfile");
await File.WriteAllTextAsync(libLockPath, """
# Lib module lockfile
com.example:lib-dep:4.0.0=testCompileClasspath
""", cancellationToken);
var analyzers = new ILanguageAnalyzer[] { new JavaLanguageAnalyzer() };
var json = await LanguageAnalyzerTestHarness.RunToJsonAsync(
root,
analyzers,
cancellationToken);
using var document = JsonDocument.Parse(json);
var components = document.RootElement.EnumerateArray().ToArray();
// Verify root-dep has lockModulePath="."
var rootDep = components.FirstOrDefault(c => c.GetProperty("name").GetString() == "root-dep");
Assert.NotEqual(JsonValueKind.Undefined, rootDep.ValueKind);
Assert.Equal(".", rootDep.GetProperty("metadata").GetProperty("lockModulePath").GetString());
Assert.Equal("gradle.lockfile", rootDep.GetProperty("metadata").GetProperty("lockLocator").GetString());
// Verify app-dep has lockModulePath="app"
var appDep = components.FirstOrDefault(c => c.GetProperty("name").GetString() == "app-dep");
Assert.NotEqual(JsonValueKind.Undefined, appDep.ValueKind);
Assert.Equal("app", appDep.GetProperty("metadata").GetProperty("lockModulePath").GetString());
Assert.Equal("app/gradle.lockfile", appDep.GetProperty("metadata").GetProperty("lockLocator").GetString());
// Verify lib-dep has lockModulePath="lib"
var libDep = components.FirstOrDefault(c => c.GetProperty("name").GetString() == "lib-dep");
Assert.NotEqual(JsonValueKind.Undefined, libDep.ValueKind);
Assert.Equal("lib", libDep.GetProperty("metadata").GetProperty("lockModulePath").GetString());
// Verify shared-dep: different versions result in both being emitted with conflict detection
// (first-wins only applies to identical GAV, different versions are separate entries)
var sharedDeps = components.Where(c => c.GetProperty("name").GetString() == "shared-dep").ToArray();
Assert.Equal(2, sharedDeps.Length);
// Verify version conflict is detected
foreach (var sharedDep in sharedDeps)
{
var metadata = sharedDep.GetProperty("metadata");
Assert.Equal("true", metadata.GetProperty("conflict.detected").GetString());
}
}
finally
{
TestPaths.SafeDelete(root);
}
}
[Fact]
public async Task RuntimeImageEmitsExplicitKeyComponentAsync()
{
var cancellationToken = TestContext.Current.CancellationToken;
var root = TestPaths.CreateTemporaryDirectory();
try
{
// Create a runtime image with release file
var runtimeRoot = Path.Combine(root, "jdk", "jdk-21.0.1");
Directory.CreateDirectory(runtimeRoot);
Directory.CreateDirectory(Path.Combine(runtimeRoot, "bin"));
Directory.CreateDirectory(Path.Combine(runtimeRoot, "lib"));
var javaBinary = OperatingSystem.IsWindows() ? "java.exe" : "java";
await File.WriteAllTextAsync(Path.Combine(runtimeRoot, "bin", javaBinary), string.Empty, cancellationToken);
await File.WriteAllTextAsync(Path.Combine(runtimeRoot, "lib", "modules"), string.Empty, cancellationToken);
await File.WriteAllTextAsync(
Path.Combine(runtimeRoot, "release"),
"JAVA_VERSION=\"21.0.1\"\nIMPLEMENTOR=\"Eclipse Adoptium\"\n",
cancellationToken);
var analyzers = new ILanguageAnalyzer[] { new JavaLanguageAnalyzer() };
var json = await LanguageAnalyzerTestHarness.RunToJsonAsync(
root,
analyzers,
cancellationToken);
using var document = JsonDocument.Parse(json);
var components = document.RootElement.EnumerateArray().ToArray();
// Find the runtime component
var runtimeComponent = components.FirstOrDefault(c =>
c.TryGetProperty("type", out var typeElement) &&
typeElement.GetString() == "java-runtime");
Assert.NotEqual(JsonValueKind.Undefined, runtimeComponent.ValueKind);
// Verify no PURL (explicit-key)
if (runtimeComponent.TryGetProperty("purl", out var purlElement))
{
Assert.Equal(JsonValueKind.Null, purlElement.ValueKind);
}
// Verify metadata
var metadata = runtimeComponent.GetProperty("metadata");
Assert.Equal("21.0.1", metadata.GetProperty("java.version").GetString());
Assert.Equal("Eclipse Adoptium", metadata.GetProperty("java.vendor").GetString());
Assert.Equal("java-runtime", metadata.GetProperty("componentType").GetString());
Assert.Equal("jdk/jdk-21.0.1", metadata.GetProperty("runtimeImagePath").GetString());
// Verify name format
Assert.Equal("java-runtime-21.0.1 (Eclipse Adoptium)", runtimeComponent.GetProperty("name").GetString());
Assert.Equal("21.0.1", runtimeComponent.GetProperty("version").GetString());
// Verify evidence references release file
var evidence = runtimeComponent.GetProperty("evidence").EnumerateArray().ToArray();
var releaseEvidence = evidence.FirstOrDefault(e =>
e.GetProperty("source").GetString() == "release");
Assert.NotEqual(JsonValueKind.Undefined, releaseEvidence.ValueKind);
Assert.Equal("jdk/jdk-21.0.1/release", releaseEvidence.GetProperty("locator").GetString());
Assert.True(releaseEvidence.TryGetProperty("sha256", out var sha256) && !string.IsNullOrWhiteSpace(sha256.GetString()));
}
finally
{
TestPaths.SafeDelete(root);
}
}
[Fact]
public async Task DuplicateRuntimeImagesAreDeduplicatedAsync()
{
var cancellationToken = TestContext.Current.CancellationToken;
var root = TestPaths.CreateTemporaryDirectory();
try
{
// Create two identical runtime images in different locations
foreach (var subPath in new[] { "runtime1/jdk", "runtime2/jdk" })
{
var runtimeRoot = Path.Combine(root, subPath);
Directory.CreateDirectory(runtimeRoot);
Directory.CreateDirectory(Path.Combine(runtimeRoot, "bin"));
Directory.CreateDirectory(Path.Combine(runtimeRoot, "lib"));
var javaBinary = OperatingSystem.IsWindows() ? "java.exe" : "java";
await File.WriteAllTextAsync(Path.Combine(runtimeRoot, "bin", javaBinary), string.Empty, cancellationToken);
await File.WriteAllTextAsync(Path.Combine(runtimeRoot, "lib", "modules"), string.Empty, cancellationToken);
await File.WriteAllTextAsync(
Path.Combine(runtimeRoot, "release"),
"JAVA_VERSION=\"17.0.8\"\nIMPLEMENTOR=\"Azul Systems\"\n",
cancellationToken);
}
var analyzers = new ILanguageAnalyzer[] { new JavaLanguageAnalyzer() };
var json = await LanguageAnalyzerTestHarness.RunToJsonAsync(
root,
analyzers,
cancellationToken);
using var document = JsonDocument.Parse(json);
var components = document.RootElement.EnumerateArray().ToArray();
// Both should be emitted because they have different paths
var runtimeComponents = components.Where(c =>
c.TryGetProperty("type", out var typeElement) &&
typeElement.GetString() == "java-runtime").ToArray();
Assert.Equal(2, runtimeComponents.Length);
// Verify they have different runtimeImagePath
var paths = runtimeComponents.Select(c =>
c.GetProperty("metadata").GetProperty("runtimeImagePath").GetString()).ToHashSet();
Assert.Contains("runtime1/jdk", paths);
Assert.Contains("runtime2/jdk", paths);
}
finally
{
TestPaths.SafeDelete(root);
}
}
#endregion
private static bool ComponentHasMetadata(JsonElement root, string componentName, string key, string expected)
{
foreach (var element in root.EnumerateArray())