Add unit tests for PackRunAttestation and SealedInstallEnforcer
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
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
Policy Lint & Smoke / policy-lint (push) Has been cancelled
release-manifest-verify / verify (push) Has been cancelled

- Implement comprehensive tests for PackRunAttestationService, covering attestation generation, verification, and event emission.
- Add tests for SealedInstallEnforcer to validate sealed install requirements and enforcement logic.
- Introduce a MonacoLoaderService stub for testing purposes to prevent Monaco workers/styles from loading during Karma runs.
This commit is contained in:
StellaOps Bot
2025-12-06 22:25:30 +02:00
parent dd0067ea0b
commit 4042fc2184
110 changed files with 20084 additions and 639 deletions

View File

@@ -0,0 +1,108 @@
using System.Collections.Immutable;
using StellaOps.Scanner.Analyzers.Lang.Java.Internal.Gradle;
namespace StellaOps.Scanner.Analyzers.Lang.Java.Tests.Parsers;
public sealed class GradleGroovyParserTests
{
[Fact]
public async Task ParsesStringNotationDependenciesAsync()
{
var cancellationToken = TestContext.Current.CancellationToken;
var content = """
dependencies {
implementation 'org.slf4j:slf4j-api:1.7.36'
api "com.google.guava:guava:31.1-jre"
testImplementation 'junit:junit:4.13.2'
}
""";
var tempFile = Path.GetTempFileName();
try
{
await File.WriteAllTextAsync(tempFile, content, cancellationToken);
var result = await GradleGroovyParser.ParseAsync(tempFile, null, cancellationToken);
Assert.Equal(3, result.Dependencies.Length);
var slf4j = result.Dependencies.First(d => d.ArtifactId == "slf4j-api");
Assert.Equal("org.slf4j", slf4j.GroupId);
Assert.Equal("1.7.36", slf4j.Version);
Assert.Equal("implementation", slf4j.Scope);
var guava = result.Dependencies.First(d => d.ArtifactId == "guava");
Assert.Equal("com.google.guava", guava.GroupId);
Assert.Equal("31.1-jre", guava.Version);
Assert.Equal("api", guava.Scope);
var junit = result.Dependencies.First(d => d.ArtifactId == "junit");
Assert.Equal("junit", junit.GroupId);
Assert.Equal("4.13.2", junit.Version);
Assert.Equal("testImplementation", junit.Scope);
}
finally
{
File.Delete(tempFile);
}
}
[Fact]
public async Task ParsesMapNotationDependenciesAsync()
{
var cancellationToken = TestContext.Current.CancellationToken;
var content = """
dependencies {
implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.12.0'
compileOnly(group: "javax.servlet", name: "servlet-api", version: "2.5")
}
""";
var tempFile = Path.GetTempFileName();
try
{
await File.WriteAllTextAsync(tempFile, content, cancellationToken);
var result = await GradleGroovyParser.ParseAsync(tempFile, null, cancellationToken);
Assert.Equal(2, result.Dependencies.Length);
var commons = result.Dependencies.First(d => d.ArtifactId == "commons-lang3");
Assert.Equal("org.apache.commons", commons.GroupId);
Assert.Equal("3.12.0", commons.Version);
Assert.Equal("implementation", commons.Scope);
}
finally
{
File.Delete(tempFile);
}
}
[Fact]
public async Task ResolvesPropertyPlaceholdersAsync()
{
var cancellationToken = TestContext.Current.CancellationToken;
var content = """
dependencies {
implementation "org.slf4j:slf4j-api:${slf4jVersion}"
}
""";
var tempFile = Path.GetTempFileName();
try
{
await File.WriteAllTextAsync(tempFile, content, cancellationToken);
var properties = new GradleProperties(
new Dictionary<string, string> { ["slf4jVersion"] = "2.0.7" }.ToImmutableDictionary(),
ImmutableDictionary<string, string>.Empty);
var result = await GradleGroovyParser.ParseAsync(tempFile, properties, cancellationToken);
Assert.Single(result.Dependencies);
var dep = result.Dependencies[0];
Assert.Equal("2.0.7", dep.Version);
}
finally
{
File.Delete(tempFile);
}
}
}

View File

@@ -0,0 +1,211 @@
using StellaOps.Scanner.Analyzers.Lang.Java.Internal.Maven;
namespace StellaOps.Scanner.Analyzers.Lang.Java.Tests.Parsers;
public sealed class MavenPomParserTests
{
[Fact]
public async Task ParsesDependenciesAsync()
{
var cancellationToken = TestContext.Current.CancellationToken;
var content = """
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>1.0.0</version>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.36</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
""";
var tempFile = Path.GetTempFileName();
try
{
await File.WriteAllTextAsync(tempFile, content, cancellationToken);
var result = await MavenPomParser.ParseAsync(tempFile, cancellationToken);
Assert.NotEqual(MavenPom.Empty, result);
Assert.Equal("com.example", result.GroupId);
Assert.Equal("demo", result.ArtifactId);
Assert.Equal("1.0.0", result.Version);
Assert.Equal(2, result.Dependencies.Length);
var slf4j = result.Dependencies.First(d => d.ArtifactId == "slf4j-api");
Assert.Equal("org.slf4j", slf4j.GroupId);
Assert.Equal("1.7.36", slf4j.Version);
Assert.Null(slf4j.Scope);
var junit = result.Dependencies.First(d => d.ArtifactId == "junit");
Assert.Equal("test", junit.Scope);
}
finally
{
File.Delete(tempFile);
}
}
[Fact]
public async Task ParsesPropertiesAsync()
{
var cancellationToken = TestContext.Current.CancellationToken;
var content = """
<?xml version="1.0" encoding="UTF-8"?>
<project>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>1.0.0</version>
<properties>
<slf4j.version>2.0.7</slf4j.version>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
</dependencies>
</project>
""";
var tempFile = Path.GetTempFileName();
try
{
await File.WriteAllTextAsync(tempFile, content, cancellationToken);
var result = await MavenPomParser.ParseAsync(tempFile, cancellationToken);
Assert.Equal(2, result.Properties.Count);
Assert.Equal("2.0.7", result.Properties["slf4j.version"]);
Assert.Equal("17", result.Properties["java.version"]);
}
finally
{
File.Delete(tempFile);
}
}
[Fact]
public async Task ParsesLicensesAsync()
{
var cancellationToken = TestContext.Current.CancellationToken;
var content = """
<?xml version="1.0" encoding="UTF-8"?>
<project>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>1.0.0</version>
<licenses>
<license>
<name>Apache License, Version 2.0</name>
<url>https://www.apache.org/licenses/LICENSE-2.0</url>
</license>
</licenses>
</project>
""";
var tempFile = Path.GetTempFileName();
try
{
await File.WriteAllTextAsync(tempFile, content, cancellationToken);
var result = await MavenPomParser.ParseAsync(tempFile, cancellationToken);
Assert.Single(result.Licenses);
var license = result.Licenses[0];
Assert.Equal("Apache License, Version 2.0", license.Name);
Assert.Equal("https://www.apache.org/licenses/LICENSE-2.0", license.Url);
Assert.Equal("Apache-2.0", license.SpdxId);
}
finally
{
File.Delete(tempFile);
}
}
[Fact]
public async Task ParsesParentReferenceAsync()
{
var cancellationToken = TestContext.Current.CancellationToken;
var content = """
<?xml version="1.0" encoding="UTF-8"?>
<project>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.0</version>
</parent>
<artifactId>demo</artifactId>
</project>
""";
var tempFile = Path.GetTempFileName();
try
{
await File.WriteAllTextAsync(tempFile, content, cancellationToken);
var result = await MavenPomParser.ParseAsync(tempFile, cancellationToken);
Assert.NotNull(result.Parent);
Assert.Equal("org.springframework.boot", result.Parent.GroupId);
Assert.Equal("spring-boot-starter-parent", result.Parent.ArtifactId);
Assert.Equal("3.1.0", result.Parent.Version);
}
finally
{
File.Delete(tempFile);
}
}
[Fact]
public async Task ParsesDependencyManagementAsync()
{
var cancellationToken = TestContext.Current.CancellationToken;
var content = """
<?xml version="1.0" encoding="UTF-8"?>
<project>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>1.0.0</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>3.1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
""";
var tempFile = Path.GetTempFileName();
try
{
await File.WriteAllTextAsync(tempFile, content, cancellationToken);
var result = await MavenPomParser.ParseAsync(tempFile, cancellationToken);
Assert.Single(result.DependencyManagement);
var bom = result.DependencyManagement[0];
Assert.Equal("org.springframework.boot", bom.GroupId);
Assert.Equal("spring-boot-dependencies", bom.ArtifactId);
Assert.Equal("pom", bom.Type);
Assert.Equal("import", bom.Scope);
}
finally
{
File.Delete(tempFile);
}
}
}

View File

@@ -0,0 +1,140 @@
using StellaOps.Scanner.Analyzers.Lang.Java.Internal.Osgi;
namespace StellaOps.Scanner.Analyzers.Lang.Java.Tests.Parsers;
public sealed class OsgiBundleParserTests
{
[Fact]
public void ParsesBasicBundleManifest()
{
var manifest = """
Manifest-Version: 1.0
Bundle-SymbolicName: com.example.bundle
Bundle-Version: 1.0.0.SNAPSHOT
Bundle-Name: Example Bundle
Bundle-Vendor: Example Corp
""";
var dict = OsgiBundleParser.ParseManifest(manifest);
var result = OsgiBundleParser.Parse(dict);
Assert.NotNull(result);
Assert.Equal("com.example.bundle", result.SymbolicName);
Assert.Equal("1.0.0.SNAPSHOT", result.Version);
Assert.Equal("Example Bundle", result.Name);
Assert.Equal("Example Corp", result.Vendor);
}
[Fact]
public void ParsesImportPackage()
{
var manifest = """
Manifest-Version: 1.0
Bundle-SymbolicName: com.example.bundle
Bundle-Version: 1.0.0
Import-Package: org.osgi.framework;version="[1.8,2)",
org.slf4j;version="[1.7,2)",
javax.servlet;resolution:=optional
""";
var dict = OsgiBundleParser.ParseManifest(manifest);
var result = OsgiBundleParser.Parse(dict);
Assert.NotNull(result);
Assert.Equal(3, result.ImportPackage.Length);
var osgi = result.ImportPackage.First(p => p.PackageName == "org.osgi.framework");
Assert.Equal("[1.8,2)", osgi.Version);
Assert.False(osgi.IsOptional);
var servlet = result.ImportPackage.First(p => p.PackageName == "javax.servlet");
Assert.True(servlet.IsOptional);
}
[Fact]
public void ParsesExportPackage()
{
var manifest = """
Manifest-Version: 1.0
Bundle-SymbolicName: com.example.bundle
Bundle-Version: 1.0.0
Export-Package: com.example.api;version="1.0.0",
com.example.impl;version="1.0.0"
""";
var dict = OsgiBundleParser.ParseManifest(manifest);
var result = OsgiBundleParser.Parse(dict);
Assert.NotNull(result);
Assert.Equal(2, result.ExportPackage.Length);
var api = result.ExportPackage.First(p => p.PackageName == "com.example.api");
Assert.Equal("1.0.0", api.Version);
}
[Fact]
public void ParsesSingletonBundle()
{
var manifest = """
Manifest-Version: 1.0
Bundle-SymbolicName: com.example.singleton;singleton:=true
Bundle-Version: 1.0.0
""";
var dict = OsgiBundleParser.ParseManifest(manifest);
var result = OsgiBundleParser.Parse(dict);
Assert.NotNull(result);
Assert.Equal("com.example.singleton", result.SymbolicName);
Assert.True(result.IsSingleton);
}
[Fact]
public void ParsesFragmentHost()
{
var manifest = """
Manifest-Version: 1.0
Bundle-SymbolicName: com.example.fragment
Bundle-Version: 1.0.0
Fragment-Host: com.example.host;bundle-version="[1.0,2.0)"
""";
var dict = OsgiBundleParser.ParseManifest(manifest);
var result = OsgiBundleParser.Parse(dict);
Assert.NotNull(result);
Assert.True(result.IsFragment);
Assert.Contains("com.example.host", result.FragmentHost);
}
[Fact]
public void ReturnsNullForNonOsgiManifest()
{
var manifest = """
Manifest-Version: 1.0
Implementation-Title: Regular JAR
Implementation-Version: 1.0.0
""";
var dict = OsgiBundleParser.ParseManifest(manifest);
var result = OsgiBundleParser.Parse(dict);
Assert.Null(result);
}
[Fact]
public void HandlesManifestContinuationLines()
{
var manifest = "Manifest-Version: 1.0\r\n" +
"Bundle-SymbolicName: com.example.bundle\r\n" +
"Import-Package: org.osgi.framework;version=\"[1.8,2)\",org.slf4j;v\r\n" +
" ersion=\"[1.7,2)\"\r\n" +
"Bundle-Version: 1.0.0\r\n";
var dict = OsgiBundleParser.ParseManifest(manifest);
var result = OsgiBundleParser.Parse(dict);
Assert.NotNull(result);
Assert.Equal(2, result.ImportPackage.Length);
}
}

View File

@@ -0,0 +1,134 @@
using System.IO.Compression;
using System.Text;
using StellaOps.Scanner.Analyzers.Lang.Java.Internal.Shading;
namespace StellaOps.Scanner.Analyzers.Lang.Java.Tests.Parsers;
public sealed class ShadedJarDetectorTests
{
[Fact]
public async Task DetectsMultiplePomPropertiesAsync()
{
var cancellationToken = TestContext.Current.CancellationToken;
var jarPath = Path.Combine(Path.GetTempPath(), $"shaded-{Guid.NewGuid()}.jar");
try
{
using (var archive = ZipFile.Open(jarPath, ZipArchiveMode.Create))
{
WritePomProperties(archive, "com.example", "shaded", "1.0.0");
WritePomProperties(archive, "org.slf4j", "slf4j-api", "1.7.36");
WritePomProperties(archive, "com.google.guava", "guava", "31.1-jre");
}
var result = await ShadedJarDetector.AnalyzeAsync(jarPath, cancellationToken);
Assert.True(result.IsShaded);
Assert.Contains("multiple-pom-properties", result.Markers);
Assert.Equal(3, result.EmbeddedArtifacts.Length);
}
finally
{
File.Delete(jarPath);
}
}
[Fact]
public async Task DetectsDependencyReducedPomAsync()
{
var cancellationToken = TestContext.Current.CancellationToken;
var jarPath = Path.Combine(Path.GetTempPath(), $"shade-plugin-{Guid.NewGuid()}.jar");
try
{
using (var archive = ZipFile.Open(jarPath, ZipArchiveMode.Create))
{
WritePomProperties(archive, "com.example", "shaded", "1.0.0");
var entry = archive.CreateEntry("META-INF/maven/com.example/shaded/dependency-reduced-pom.xml");
using var writer = new StreamWriter(entry.Open(), Encoding.UTF8);
writer.Write("<project></project>");
}
var result = await ShadedJarDetector.AnalyzeAsync(jarPath, cancellationToken);
Assert.True(result.IsShaded);
Assert.Contains("dependency-reduced-pom.xml", result.Markers);
}
finally
{
File.Delete(jarPath);
}
}
[Fact]
public async Task DetectsRelocatedPackagesAsync()
{
var cancellationToken = TestContext.Current.CancellationToken;
var jarPath = Path.Combine(Path.GetTempPath(), $"relocated-{Guid.NewGuid()}.jar");
try
{
using (var archive = ZipFile.Open(jarPath, ZipArchiveMode.Create))
{
WritePomProperties(archive, "com.example", "shaded", "1.0.0");
// Create relocated class files
CreateEmptyClass(archive, "shaded/com/google/common/collect/ImmutableList.class");
CreateEmptyClass(archive, "shaded/com/google/common/base/Preconditions.class");
}
var result = await ShadedJarDetector.AnalyzeAsync(jarPath, cancellationToken);
Assert.True(result.IsShaded);
Assert.Contains("relocated-packages", result.Markers);
Assert.NotEmpty(result.RelocatedPrefixes);
}
finally
{
File.Delete(jarPath);
}
}
[Fact]
public async Task ReturnsNotShadedForRegularJarAsync()
{
var cancellationToken = TestContext.Current.CancellationToken;
var jarPath = Path.Combine(Path.GetTempPath(), $"regular-{Guid.NewGuid()}.jar");
try
{
using (var archive = ZipFile.Open(jarPath, ZipArchiveMode.Create))
{
WritePomProperties(archive, "com.example", "regular", "1.0.0");
CreateEmptyClass(archive, "com/example/Main.class");
}
var result = await ShadedJarDetector.AnalyzeAsync(jarPath, cancellationToken);
Assert.False(result.IsShaded);
Assert.Empty(result.Markers);
Assert.Equal(ShadingConfidence.None, result.Confidence);
}
finally
{
File.Delete(jarPath);
}
}
private static void WritePomProperties(ZipArchive archive, string groupId, string artifactId, string version)
{
var path = $"META-INF/maven/{groupId}/{artifactId}/pom.properties";
var entry = archive.CreateEntry(path);
using var writer = new StreamWriter(entry.Open(), Encoding.UTF8);
writer.WriteLine($"groupId={groupId}");
writer.WriteLine($"artifactId={artifactId}");
writer.WriteLine($"version={version}");
}
private static void CreateEmptyClass(ZipArchive archive, string path)
{
var entry = archive.CreateEntry(path);
using var stream = entry.Open();
// Minimal class file header
stream.Write([0xCA, 0xFE, 0xBA, 0xBE]);
}
}

View File

@@ -0,0 +1,118 @@
using StellaOps.Scanner.Analyzers.Lang.Java.Internal.BuildMetadata;
using StellaOps.Scanner.Analyzers.Lang.Java.Internal.Conflicts;
namespace StellaOps.Scanner.Analyzers.Lang.Java.Tests.Parsers;
public sealed class VersionConflictDetectorTests
{
[Fact]
public void DetectsMajorVersionConflicts()
{
var dependencies = new[]
{
CreateDependency("org.slf4j", "slf4j-api", "1.7.36", "pom.xml"),
CreateDependency("org.slf4j", "slf4j-api", "2.0.7", "gradle.lockfile")
};
var result = VersionConflictDetector.Analyze(dependencies);
Assert.True(result.HasConflicts);
Assert.Equal(1, result.TotalConflicts);
Assert.Equal(ConflictSeverity.High, result.MaxSeverity);
var conflict = result.Conflicts[0];
Assert.Equal("org.slf4j", conflict.GroupId);
Assert.Equal("slf4j-api", conflict.ArtifactId);
Assert.Contains("1.7.36", conflict.UniqueVersions);
Assert.Contains("2.0.7", conflict.UniqueVersions);
}
[Fact]
public void DetectsMinorVersionConflicts()
{
var dependencies = new[]
{
CreateDependency("com.google.guava", "guava", "31.0-jre", "pom.xml"),
CreateDependency("com.google.guava", "guava", "31.1-jre", "gradle.lockfile")
};
var result = VersionConflictDetector.Analyze(dependencies);
Assert.True(result.HasConflicts);
Assert.Equal(ConflictSeverity.Medium, result.MaxSeverity);
}
[Fact]
public void IgnoresIdenticalVersions()
{
var dependencies = new[]
{
CreateDependency("org.slf4j", "slf4j-api", "1.7.36", "pom.xml"),
CreateDependency("org.slf4j", "slf4j-api", "1.7.36", "gradle.lockfile")
};
var result = VersionConflictDetector.Analyze(dependencies);
Assert.False(result.HasConflicts);
Assert.Equal(0, result.TotalConflicts);
}
[Fact]
public void ReturnsEmptyForNoDependencies()
{
var result = VersionConflictDetector.Analyze(Array.Empty<JavaDependencyDeclaration>());
Assert.False(result.HasConflicts);
Assert.Equal(VersionConflictAnalysis.Empty, result);
}
[Fact]
public void GetConflictReturnsNullForNonConflicting()
{
var dependencies = new[]
{
CreateDependency("org.slf4j", "slf4j-api", "1.7.36", "pom.xml"),
CreateDependency("com.google.guava", "guava", "31.1-jre", "pom.xml")
};
var result = VersionConflictDetector.Analyze(dependencies);
Assert.Null(result.GetConflict("org.slf4j", "slf4j-api"));
Assert.Null(result.GetConflict("com.google.guava", "guava"));
}
[Fact]
public void GetConflictFindsConflictingArtifact()
{
var dependencies = new[]
{
CreateDependency("org.slf4j", "slf4j-api", "1.7.36", "pom.xml"),
CreateDependency("org.slf4j", "slf4j-api", "2.0.7", "gradle.lockfile"),
CreateDependency("com.google.guava", "guava", "31.1-jre", "pom.xml")
};
var result = VersionConflictDetector.Analyze(dependencies);
var conflict = result.GetConflict("org.slf4j", "slf4j-api");
Assert.NotNull(conflict);
Assert.Equal(2, conflict.UniqueVersions.Count());
Assert.Null(result.GetConflict("com.google.guava", "guava"));
}
private static JavaDependencyDeclaration CreateDependency(
string groupId,
string artifactId,
string version,
string source)
{
return new JavaDependencyDeclaration
{
GroupId = groupId,
ArtifactId = artifactId,
Version = version,
Source = source,
Locator = source
};
}
}