Files
git.stella-ops.org/src/Scanner/__Tests/StellaOps.Scanner.Analyzers.Native.Tests/NativeResolverTests.cs
StellaOps Bot ea970ead2a
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
sdk-generator-smoke / sdk-smoke (push) Has been cancelled
SDK Publish & Sign / sdk-publish (push) Has been cancelled
api-governance / spectral-lint (push) Has been cancelled
oas-ci / oas-validate (push) Has been cancelled
Mirror Thin Bundle Sign & Verify / mirror-sign (push) Has been cancelled
up
2025-11-27 07:46:56 +02:00

536 lines
17 KiB
C#

using FluentAssertions;
using Xunit;
namespace StellaOps.Scanner.Analyzers.Native.Tests;
public class ElfResolverTests
{
[Fact]
public void Resolve_WithRpath_FindsLibraryInRpathDirectory()
{
// Arrange
var fs = new VirtualFileSystem(["/opt/myapp/lib/libfoo.so.1"]);
var rpaths = new[] { "/opt/myapp/lib" };
var runpaths = Array.Empty<string>();
// Act
var result = ElfResolver.Resolve("libfoo.so.1", rpaths, runpaths, null, null, fs);
// Assert
result.Resolved.Should().BeTrue();
result.ResolvedPath.Should().Be("/opt/myapp/lib/libfoo.so.1");
result.Steps.Should().ContainSingle()
.Which.Should().Match<ResolveStep>(s =>
s.SearchPath == "/opt/myapp/lib" &&
s.SearchReason == "rpath" &&
s.Found == true);
}
[Fact]
public void Resolve_WithRunpath_IgnoresRpath()
{
// Arrange - library exists in rpath but not runpath
var fs = new VirtualFileSystem([
"/opt/rpath/lib/libfoo.so.1",
"/opt/runpath/lib/libfoo.so.1"
]);
var rpaths = new[] { "/opt/rpath/lib" };
var runpaths = new[] { "/opt/runpath/lib" };
// Act
var result = ElfResolver.Resolve("libfoo.so.1", rpaths, runpaths, null, null, fs);
// Assert
result.Resolved.Should().BeTrue();
result.ResolvedPath.Should().Be("/opt/runpath/lib/libfoo.so.1");
result.Steps.Should().NotContain(s => s.SearchReason == "rpath");
result.Steps.Should().Contain(s => s.SearchReason == "runpath");
}
[Fact]
public void Resolve_WithLdLibraryPath_SearchesBeforeRunpath()
{
// Arrange
var fs = new VirtualFileSystem([
"/custom/lib/libfoo.so.1",
"/opt/runpath/lib/libfoo.so.1"
]);
var rpaths = Array.Empty<string>();
var runpaths = new[] { "/opt/runpath/lib" };
var ldLibraryPath = new[] { "/custom/lib" };
// Act
var result = ElfResolver.Resolve("libfoo.so.1", rpaths, runpaths, ldLibraryPath, null, fs);
// Assert
result.Resolved.Should().BeTrue();
result.ResolvedPath.Should().Be("/custom/lib/libfoo.so.1");
result.Steps.First().SearchReason.Should().Be("ld_library_path");
}
[Fact]
public void Resolve_WithOriginExpansion_ExpandsOriginVariable()
{
// Arrange
var fs = new VirtualFileSystem(["/app/bin/../lib/libfoo.so.1"]);
var rpaths = new[] { "$ORIGIN/../lib" };
var runpaths = Array.Empty<string>();
// Act
var result = ElfResolver.Resolve("libfoo.so.1", rpaths, runpaths, null, "/app/bin", fs);
// Assert
result.Resolved.Should().BeTrue();
result.ResolvedPath.Should().Be("/app/bin/../lib/libfoo.so.1");
}
[Fact]
public void Resolve_WithOriginBraceSyntax_ExpandsOriginVariable()
{
// Arrange
var fs = new VirtualFileSystem(["/app/bin/../lib/libbar.so.2"]);
var rpaths = new[] { "${ORIGIN}/../lib" };
var runpaths = Array.Empty<string>();
// Act
var result = ElfResolver.Resolve("libbar.so.2", rpaths, runpaths, null, "/app/bin", fs);
// Assert
result.Resolved.Should().BeTrue();
result.ResolvedPath.Should().Be("/app/bin/../lib/libbar.so.2");
}
[Fact]
public void Resolve_NotFound_ReturnsUnresolvedWithSteps()
{
// Arrange
var fs = new VirtualFileSystem([]);
var rpaths = new[] { "/opt/lib" };
var runpaths = Array.Empty<string>();
// Act
var result = ElfResolver.Resolve("libmissing.so.1", rpaths, runpaths, null, null, fs);
// Assert
result.Resolved.Should().BeFalse();
result.ResolvedPath.Should().BeNull();
result.Steps.Should().NotBeEmpty();
result.Steps.Should().Contain(s => s.SearchReason == "rpath" && !s.Found);
result.Steps.Should().Contain(s => s.SearchReason == "default" && !s.Found);
}
[Fact]
public void Resolve_WithDefaultPaths_SearchesSystemDirectories()
{
// Arrange
var fs = new VirtualFileSystem(["/usr/lib/libc.so.6"]);
// Act
var result = ElfResolver.Resolve("libc.so.6", [], [], null, null, fs);
// Assert
result.Resolved.Should().BeTrue();
result.ResolvedPath.Should().Be("/usr/lib/libc.so.6");
result.Steps.Should().Contain(s => s.SearchReason == "default");
}
[Fact]
public void Resolve_SearchOrder_FollowsCorrectPriority()
{
// Arrange - library exists in all locations
var fs = new VirtualFileSystem([
"/rpath/libfoo.so",
"/ldpath/libfoo.so",
"/usr/lib/libfoo.so"
]);
var rpaths = new[] { "/rpath" };
var ldLibraryPath = new[] { "/ldpath" };
// Act - no runpath, so rpath should be checked first
var result = ElfResolver.Resolve("libfoo.so", rpaths, [], ldLibraryPath, null, fs);
// Assert
result.Resolved.Should().BeTrue();
result.ResolvedPath.Should().Be("/rpath/libfoo.so");
result.Steps.First().SearchReason.Should().Be("rpath");
}
}
public class PeResolverTests
{
[Fact]
public void Resolve_InApplicationDirectory_FindsDll()
{
// Arrange
var fs = new VirtualFileSystem(["C:/MyApp/mylib.dll"]);
// Act
var result = PeResolver.Resolve("mylib.dll", "C:/MyApp", null, null, fs);
// Assert
result.Resolved.Should().BeTrue();
result.ResolvedPath.Should().Be("C:/MyApp/mylib.dll");
result.Steps.Should().ContainSingle()
.Which.SearchReason.Should().Be("application_directory");
}
[Fact]
public void Resolve_InSystem32_FindsDll()
{
// Arrange
var fs = new VirtualFileSystem(["C:/Windows/System32/kernel32.dll"]);
// Act
var result = PeResolver.Resolve("kernel32.dll", "C:/MyApp", null, null, fs);
// Assert
result.Resolved.Should().BeTrue();
result.ResolvedPath.Should().Be("C:/Windows/System32/kernel32.dll");
result.Steps.Should().Contain(s => s.SearchReason == "system_directory");
}
[Fact]
public void Resolve_InSysWOW64_FindsDll()
{
// Arrange
var fs = new VirtualFileSystem(["C:/Windows/SysWOW64/wow64.dll"]);
// Act
var result = PeResolver.Resolve("wow64.dll", null, null, null, fs);
// Assert
result.Resolved.Should().BeTrue();
result.ResolvedPath.Should().Be("C:/Windows/SysWOW64/wow64.dll");
}
[Fact]
public void Resolve_InCurrentDirectory_FindsDll()
{
// Arrange
var fs = new VirtualFileSystem(["C:/WorkDir/plugin.dll"]);
// Act
var result = PeResolver.Resolve("plugin.dll", "C:/MyApp", "C:/WorkDir", null, fs);
// Assert
result.Resolved.Should().BeTrue();
result.ResolvedPath.Should().Be("C:/WorkDir/plugin.dll");
result.Steps.Should().Contain(s => s.SearchReason == "current_directory" && s.Found);
}
[Fact]
public void Resolve_InPathEnvironment_FindsDll()
{
// Arrange
var fs = new VirtualFileSystem(["D:/Tools/bin/tool.dll"]);
var pathEnv = new[] { "D:/Tools/bin", "D:/Other" };
// Act
var result = PeResolver.Resolve("tool.dll", "C:/MyApp", null, pathEnv, fs);
// Assert
result.Resolved.Should().BeTrue();
result.ResolvedPath.Should().Be("D:/Tools/bin/tool.dll");
result.Steps.Should().Contain(s => s.SearchReason == "path_environment" && s.Found);
}
[Fact]
public void Resolve_SafeDllSearchOrder_ApplicationBeforeSystem()
{
// Arrange - DLL exists in both app dir and system32
var fs = new VirtualFileSystem([
"C:/MyApp/common.dll",
"C:/Windows/System32/common.dll"
]);
// Act
var result = PeResolver.Resolve("common.dll", "C:/MyApp", null, null, fs);
// Assert
result.Resolved.Should().BeTrue();
result.ResolvedPath.Should().Be("C:/MyApp/common.dll");
result.Steps.First().SearchReason.Should().Be("application_directory");
}
[Fact]
public void Resolve_NotFound_ReturnsAllSearchedPaths()
{
// Arrange
var fs = new VirtualFileSystem([]);
var pathEnv = new[] { "D:/Tools" };
// Act
var result = PeResolver.Resolve("missing.dll", "C:/MyApp", "C:/Work", pathEnv, fs);
// Assert
result.Resolved.Should().BeFalse();
result.ResolvedPath.Should().BeNull();
result.Steps.Should().HaveCountGreaterThan(4);
result.Steps.Should().Contain(s => s.SearchReason == "application_directory");
result.Steps.Should().Contain(s => s.SearchReason == "system_directory");
result.Steps.Should().Contain(s => s.SearchReason == "current_directory");
result.Steps.Should().Contain(s => s.SearchReason == "path_environment");
}
[Fact]
public void Resolve_WithNullApplicationDirectory_SkipsAppDirSearch()
{
// Arrange
var fs = new VirtualFileSystem(["C:/Windows/System32/test.dll"]);
// Act
var result = PeResolver.Resolve("test.dll", null, null, null, fs);
// Assert
result.Resolved.Should().BeTrue();
result.Steps.Should().NotContain(s => s.SearchReason == "application_directory");
}
}
public class MachOResolverTests
{
[Fact]
public void Resolve_WithRpath_ExpandsAndFindsLibrary()
{
// Arrange
var fs = new VirtualFileSystem(["/opt/myapp/Frameworks/libfoo.dylib"]);
var rpaths = new[] { "/opt/myapp/Frameworks" };
// Act
var result = MachOResolver.Resolve("@rpath/libfoo.dylib", rpaths, null, null, fs);
// Assert
result.Resolved.Should().BeTrue();
result.ResolvedPath.Should().Be("/opt/myapp/Frameworks/libfoo.dylib");
result.Steps.Should().ContainSingle()
.Which.SearchReason.Should().Be("rpath");
}
[Fact]
public void Resolve_WithMultipleRpaths_SearchesInOrder()
{
// Arrange
var fs = new VirtualFileSystem(["/second/path/libfoo.dylib"]);
var rpaths = new[] { "/first/path", "/second/path" };
// Act
var result = MachOResolver.Resolve("@rpath/libfoo.dylib", rpaths, null, null, fs);
// Assert
result.Resolved.Should().BeTrue();
result.ResolvedPath.Should().Be("/second/path/libfoo.dylib");
result.Steps.Should().HaveCount(2);
result.Steps[0].Found.Should().BeFalse();
result.Steps[1].Found.Should().BeTrue();
}
[Fact]
public void Resolve_WithLoaderPath_ExpandsPlaceholder()
{
// Arrange
var fs = new VirtualFileSystem(["/app/Contents/MacOS/../Frameworks/libbar.dylib"]);
// Act
var result = MachOResolver.Resolve(
"@loader_path/../Frameworks/libbar.dylib",
[],
"/app/Contents/MacOS",
null,
fs);
// Assert
result.Resolved.Should().BeTrue();
result.ResolvedPath.Should().Be("/app/Contents/MacOS/../Frameworks/libbar.dylib");
result.Steps.Should().ContainSingle()
.Which.SearchReason.Should().Be("loader_path");
}
[Fact]
public void Resolve_WithExecutablePath_ExpandsPlaceholder()
{
// Arrange
var fs = new VirtualFileSystem(["/Applications/MyApp.app/Contents/MacOS/../Frameworks/lib.dylib"]);
// Act
var result = MachOResolver.Resolve(
"@executable_path/../Frameworks/lib.dylib",
[],
null,
"/Applications/MyApp.app/Contents/MacOS",
fs);
// Assert
result.Resolved.Should().BeTrue();
result.Steps.Should().ContainSingle()
.Which.SearchReason.Should().Be("executable_path");
}
[Fact]
public void Resolve_WithRpathContainingLoaderPath_ExpandsBoth()
{
// Arrange
var fs = new VirtualFileSystem(["/app/bin/../lib/libfoo.dylib"]);
var rpaths = new[] { "@loader_path/../lib" };
// Act
var result = MachOResolver.Resolve("@rpath/libfoo.dylib", rpaths, "/app/bin", null, fs);
// Assert
result.Resolved.Should().BeTrue();
result.ResolvedPath.Should().Be("/app/bin/../lib/libfoo.dylib");
}
[Fact]
public void Resolve_AbsolutePath_ChecksDirectly()
{
// Arrange
var fs = new VirtualFileSystem(["/usr/lib/libSystem.B.dylib"]);
// Act
var result = MachOResolver.Resolve("/usr/lib/libSystem.B.dylib", [], null, null, fs);
// Assert
result.Resolved.Should().BeTrue();
result.ResolvedPath.Should().Be("/usr/lib/libSystem.B.dylib");
result.Steps.Should().ContainSingle()
.Which.SearchReason.Should().Be("absolute_path");
}
[Fact]
public void Resolve_RelativePath_SearchesDefaultPaths()
{
// Arrange
var fs = new VirtualFileSystem(["/usr/local/lib/libcustom.dylib"]);
// Act
var result = MachOResolver.Resolve("libcustom.dylib", [], null, null, fs);
// Assert
result.Resolved.Should().BeTrue();
result.ResolvedPath.Should().Be("/usr/local/lib/libcustom.dylib");
result.Steps.Should().Contain(s => s.SearchReason == "default_library_path");
}
[Fact]
public void Resolve_RpathNotFound_FallsBackToDefaultPaths()
{
// Arrange - library not in rpath but in default path
var fs = new VirtualFileSystem(["/usr/lib/libfoo.dylib"]);
var rpaths = new[] { "/nonexistent/path" };
// Act
var result = MachOResolver.Resolve("@rpath/libfoo.dylib", rpaths, null, null, fs);
// Assert
result.Resolved.Should().BeTrue();
result.ResolvedPath.Should().Be("/usr/lib/libfoo.dylib");
result.Steps.Should().Contain(s => s.SearchReason == "rpath" && !s.Found);
result.Steps.Should().Contain(s => s.SearchReason == "default_library_path" && s.Found);
}
[Fact]
public void Resolve_NotFound_ReturnsAllSearchedPaths()
{
// Arrange
var fs = new VirtualFileSystem([]);
var rpaths = new[] { "/opt/lib" };
// Act
var result = MachOResolver.Resolve("@rpath/missing.dylib", rpaths, null, null, fs);
// Assert
result.Resolved.Should().BeFalse();
result.ResolvedPath.Should().BeNull();
result.Steps.Should().NotBeEmpty();
result.Steps.Should().OnlyContain(s => !s.Found);
}
[Fact]
public void Resolve_LoaderPathNotFound_ReturnsFalse()
{
// Arrange
var fs = new VirtualFileSystem([]);
// Act
var result = MachOResolver.Resolve("@loader_path/missing.dylib", [], "/app", null, fs);
// Assert
result.Resolved.Should().BeFalse();
result.Steps.Should().ContainSingle()
.Which.SearchReason.Should().Be("loader_path");
}
}
public class VirtualFileSystemTests
{
[Fact]
public void FileExists_WithExistingFile_ReturnsTrue()
{
// Arrange
var fs = new VirtualFileSystem(["/usr/lib/libc.so.6"]);
// Act & Assert
fs.FileExists("/usr/lib/libc.so.6").Should().BeTrue();
}
[Fact]
public void FileExists_WithNonExistingFile_ReturnsFalse()
{
// Arrange
var fs = new VirtualFileSystem(["/usr/lib/libc.so.6"]);
// Act & Assert
fs.FileExists("/usr/lib/missing.so").Should().BeFalse();
}
[Fact]
public void FileExists_IsCaseInsensitive()
{
// Arrange
var fs = new VirtualFileSystem(["/USR/LIB/libc.so.6"]);
// Act & Assert
fs.FileExists("/usr/lib/LIBC.SO.6").Should().BeTrue();
}
[Fact]
public void DirectoryExists_WithExistingDirectory_ReturnsTrue()
{
// Arrange
var fs = new VirtualFileSystem(["/usr/lib/x86_64-linux-gnu/libc.so.6"]);
// Act & Assert
fs.DirectoryExists("/usr/lib").Should().BeTrue();
fs.DirectoryExists("/usr/lib/x86_64-linux-gnu").Should().BeTrue();
}
[Fact]
public void NormalizePath_HandlesBackslashes()
{
// Arrange
var fs = new VirtualFileSystem(["C:/Windows/System32/kernel32.dll"]);
// Act & Assert
fs.FileExists("C:\\Windows\\System32\\kernel32.dll").Should().BeTrue();
}
[Fact]
public void EnumerateFiles_ReturnsFilesInDirectory()
{
// Arrange
var fs = new VirtualFileSystem([
"/usr/lib/liba.so",
"/usr/lib/libb.so",
"/usr/local/lib/libc.so"
]);
// Act
var files = fs.EnumerateFiles("/usr/lib", "*").ToList();
// Assert
files.Should().HaveCount(2);
files.Should().Contain("/usr/lib/liba.so");
files.Should().Contain("/usr/lib/libb.so");
}
}