feat: Add initial implementation of Vulnerability Resolver Jobs
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
- Created project for StellaOps.Scanner.Analyzers.Native.Tests with necessary dependencies. - Documented roles and guidelines in AGENTS.md for Scheduler module. - Implemented IResolverJobService interface and InMemoryResolverJobService for handling resolver jobs. - Added ResolverBacklogNotifier and ResolverBacklogService for monitoring job metrics. - Developed API endpoints for managing resolver jobs and retrieving metrics. - Defined models for resolver job requests and responses. - Integrated dependency injection for resolver job services. - Implemented ImpactIndexSnapshot for persisting impact index data. - Introduced SignalsScoringOptions for configurable scoring weights in reachability scoring. - Added unit tests for ReachabilityScoringService and RuntimeFactsIngestionService. - Created dotnet-filter.sh script to handle command-line arguments for dotnet. - Established nuget-prime project for managing package downloads.
This commit is contained in:
@@ -0,0 +1,175 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using StellaOps.Scanner.Analyzers.Native;
|
||||
|
||||
namespace StellaOps.Scanner.Analyzers.Native.Tests;
|
||||
|
||||
public class NativeFormatDetectorTests
|
||||
{
|
||||
[Fact]
|
||||
public void DetectsElf64LittleEndian()
|
||||
{
|
||||
var bytes = new byte[64];
|
||||
bytes[0] = 0x7F; bytes[1] = (byte)'E'; bytes[2] = (byte)'L'; bytes[3] = (byte)'F';
|
||||
bytes[4] = 0x02; // 64-bit
|
||||
bytes[5] = 0x01; // little endian
|
||||
bytes[7] = 0x00; // System V / Linux
|
||||
bytes[18] = 0x3E; // e_machine low byte (x86_64)
|
||||
bytes[19] = 0x00;
|
||||
|
||||
using var stream = new MemoryStream(bytes);
|
||||
var detected = NativeFormatDetector.TryDetect(stream, out var id);
|
||||
|
||||
Assert.True(detected);
|
||||
Assert.Equal(NativeFormat.Elf, id.Format);
|
||||
Assert.Equal("x86_64", id.CpuArchitecture);
|
||||
Assert.Equal("linux", id.OperatingSystem);
|
||||
Assert.Equal("le", id.Endianness);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DetectsElfInterpreterAndBuildId()
|
||||
{
|
||||
// Minimal ELF64 with two program headers: PT_INTERP and PT_NOTE (GNU build-id)
|
||||
var buffer = new byte[512];
|
||||
|
||||
// ELF header
|
||||
buffer[0] = 0x7F; buffer[1] = (byte)'E'; buffer[2] = (byte)'L'; buffer[3] = (byte)'F';
|
||||
buffer[4] = 0x02; // 64-bit
|
||||
buffer[5] = 0x01; // little endian
|
||||
buffer[7] = 0x00; // System V
|
||||
buffer[18] = 0x3E; buffer[19] = 0x00; // x86_64
|
||||
|
||||
// e_phoff (offset 32) = 0x40
|
||||
BitConverter.GetBytes((ulong)0x40).CopyTo(buffer, 32);
|
||||
// e_phentsize (offset 54) = 56, e_phnum (56) = 2
|
||||
BitConverter.GetBytes((ushort)56).CopyTo(buffer, 54);
|
||||
BitConverter.GetBytes((ushort)2).CopyTo(buffer, 56);
|
||||
|
||||
// Program header 0: PT_INTERP
|
||||
var ph0 = 0x40;
|
||||
BitConverter.GetBytes((uint)3).CopyTo(buffer, ph0); // p_type
|
||||
BitConverter.GetBytes((uint)0).CopyTo(buffer, ph0 + 4); // p_flags
|
||||
BitConverter.GetBytes((ulong)0x100).CopyTo(buffer, ph0 + 8); // p_offset
|
||||
BitConverter.GetBytes((ulong)0).CopyTo(buffer, ph0 + 16); // p_vaddr
|
||||
BitConverter.GetBytes((ulong)0).CopyTo(buffer, ph0 + 24); // p_paddr
|
||||
BitConverter.GetBytes((ulong)0x18).CopyTo(buffer, ph0 + 32); // p_filesz
|
||||
BitConverter.GetBytes((ulong)0x18).CopyTo(buffer, ph0 + 40); // p_memsz
|
||||
BitConverter.GetBytes((ulong)0).CopyTo(buffer, ph0 + 48); // p_align
|
||||
|
||||
// Program header 1: PT_NOTE
|
||||
var ph1 = ph0 + 56;
|
||||
BitConverter.GetBytes((uint)4).CopyTo(buffer, ph1); // p_type
|
||||
BitConverter.GetBytes((uint)0).CopyTo(buffer, ph1 + 4); // p_flags
|
||||
BitConverter.GetBytes((ulong)0x120).CopyTo(buffer, ph1 + 8); // p_offset
|
||||
BitConverter.GetBytes((ulong)0).CopyTo(buffer, ph1 + 16); // p_vaddr
|
||||
BitConverter.GetBytes((ulong)0).CopyTo(buffer, ph1 + 24); // p_paddr
|
||||
BitConverter.GetBytes((ulong)0x20).CopyTo(buffer, ph1 + 32); // p_filesz
|
||||
BitConverter.GetBytes((ulong)0x20).CopyTo(buffer, ph1 + 40); // p_memsz
|
||||
BitConverter.GetBytes((ulong)0).CopyTo(buffer, ph1 + 48); // p_align
|
||||
|
||||
// PT_INTERP data
|
||||
var interpBytes = System.Text.Encoding.ASCII.GetBytes("/lib64/ld-linux-x86-64.so.2\0");
|
||||
Array.Copy(interpBytes, 0, buffer, 0x100, interpBytes.Length);
|
||||
|
||||
// PT_NOTE data (GNU build-id type 3)
|
||||
var note = new byte[0x20];
|
||||
BitConverter.GetBytes((uint)4).CopyTo(note, 0); // namesz
|
||||
BitConverter.GetBytes((uint)16).CopyTo(note, 4); // descsz
|
||||
BitConverter.GetBytes((uint)3).CopyTo(note, 8); // type
|
||||
Array.Copy(System.Text.Encoding.ASCII.GetBytes("GNU\0"), 0, note, 12, 4);
|
||||
var buildId = Enumerable.Range(1, 16).Select(i => (byte)i).ToArray();
|
||||
Array.Copy(buildId, 0, note, 16, 16);
|
||||
Array.Copy(note, 0, buffer, 0x120, note.Length);
|
||||
|
||||
using var stream = new MemoryStream(buffer);
|
||||
var detected = NativeFormatDetector.TryDetect(stream, out var id);
|
||||
|
||||
Assert.True(detected);
|
||||
Assert.Equal(NativeFormat.Elf, id.Format);
|
||||
Assert.Equal("x86_64", id.CpuArchitecture);
|
||||
Assert.Equal("/lib64/ld-linux-x86-64.so.2", id.InterpreterPath);
|
||||
Assert.Equal("0102030405060708090a0b0c0d0e0f10", id.BuildId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DetectsPe()
|
||||
{
|
||||
var bytes = new byte[256];
|
||||
bytes[0] = (byte)'M'; bytes[1] = (byte)'Z';
|
||||
var peOffset = 0x80;
|
||||
BitConverter.GetBytes(peOffset).CopyTo(bytes, 0x3C);
|
||||
bytes[peOffset] = (byte)'P';
|
||||
bytes[peOffset + 1] = (byte)'E';
|
||||
bytes[peOffset + 2] = 0; bytes[peOffset + 3] = 0;
|
||||
bytes[peOffset + 4] = 0x64; // machine 0x8664 little-endian
|
||||
bytes[peOffset + 5] = 0x86;
|
||||
|
||||
using var stream = new MemoryStream(bytes);
|
||||
var detected = NativeFormatDetector.TryDetect(stream, out var id);
|
||||
|
||||
Assert.True(detected);
|
||||
Assert.Equal(NativeFormat.Pe, id.Format);
|
||||
Assert.Equal("x86_64", id.CpuArchitecture);
|
||||
Assert.Equal("windows", id.OperatingSystem);
|
||||
Assert.Equal("le", id.Endianness);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DetectsMachO64()
|
||||
{
|
||||
var bytes = new byte[32];
|
||||
// 0xFEEDFACF (little-endian 64-bit)
|
||||
bytes[0] = 0xFE; bytes[1] = 0xED; bytes[2] = 0xFA; bytes[3] = 0xCF;
|
||||
// cputype 0x01000007 (x86_64) big endian ordering for this magic
|
||||
bytes[4] = 0x01; bytes[5] = 0x00; bytes[6] = 0x00; bytes[7] = 0x07;
|
||||
|
||||
using var stream = new MemoryStream(bytes);
|
||||
var detected = NativeFormatDetector.TryDetect(stream, out var id);
|
||||
|
||||
Assert.True(detected);
|
||||
Assert.Equal(NativeFormat.MachO, id.Format);
|
||||
Assert.Equal("x86_64", id.CpuArchitecture);
|
||||
Assert.Equal("darwin", id.OperatingSystem);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExtractsMachOUuid()
|
||||
{
|
||||
var buffer = new byte[128];
|
||||
// Mach-O 64 little endian magic 0xCFFAEDFE
|
||||
buffer[0] = 0xCF; buffer[1] = 0xFA; buffer[2] = 0xED; buffer[3] = 0xFE;
|
||||
// cputype (little endian path) write 0x01000007 at bytes 4-7
|
||||
buffer[4] = 0x07; buffer[5] = 0x00; buffer[6] = 0x00; buffer[7] = 0x01;
|
||||
// ncmds at offset 16 (little endian)
|
||||
BitConverter.GetBytes((uint)1).CopyTo(buffer, 16);
|
||||
// sizeofcmds at offset 20
|
||||
BitConverter.GetBytes((uint)32).CopyTo(buffer, 20);
|
||||
// load command starts at 32
|
||||
var cmdOffset = 32;
|
||||
BitConverter.GetBytes((uint)0x1B).CopyTo(buffer, cmdOffset); // LC_UUID
|
||||
BitConverter.GetBytes((uint)32).CopyTo(buffer, cmdOffset + 4); // cmdsize
|
||||
var uuid = Guid.NewGuid();
|
||||
uuid.ToByteArray().CopyTo(buffer, cmdOffset + 8);
|
||||
|
||||
using var stream = new MemoryStream(buffer);
|
||||
var detected = NativeFormatDetector.TryDetect(stream, out var id);
|
||||
|
||||
Assert.True(detected);
|
||||
Assert.Equal(NativeFormat.MachO, id.Format);
|
||||
Assert.Equal(uuid.ToString(), id.Uuid);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReturnsUnknownForUnsupported()
|
||||
{
|
||||
var bytes = new byte[] { 0x00, 0x01, 0x02, 0x03 };
|
||||
using var stream = new MemoryStream(bytes);
|
||||
|
||||
var detected = NativeFormatDetector.TryDetect(stream, out var id);
|
||||
|
||||
Assert.False(detected);
|
||||
Assert.Equal(NativeFormat.Unknown, id.Format);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<IsPackable>false</IsPackable>
|
||||
<UseConcelierTestInfra>false</UseConcelierTestInfra>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../../StellaOps.Scanner.Analyzers.Native/StellaOps.Scanner.Analyzers.Native.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.0" />
|
||||
<PackageReference Include="xunit" Version="2.9.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="FluentAssertions" Version="6.12.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user