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,31 @@
|
||||
using StellaOps.Scanner.Analyzers.Lang.Deno.Internal.Runtime;
|
||||
|
||||
namespace StellaOps.Scanner.Analyzers.Lang.Deno.Tests.Deno;
|
||||
|
||||
public sealed class DenoPolicySignalEmitterTests
|
||||
{
|
||||
[Fact]
|
||||
public void EmitsSignalsFromMetadata()
|
||||
{
|
||||
var metadata = new DenoRuntimeTraceMetadata(
|
||||
EventCount: 5,
|
||||
ModuleLoads: 2,
|
||||
PermissionUses: 3,
|
||||
RemoteOrigins: new[] { "https://deno.land", "https://esm.sh" },
|
||||
UniquePermissions: new[] { "env", "fs" },
|
||||
NpmResolutions: 4,
|
||||
WasmLoads: 1,
|
||||
DynamicImports: 2);
|
||||
|
||||
var signals = DenoPolicySignalEmitter.FromTrace("abc123", metadata);
|
||||
|
||||
Assert.Equal("abc123", signals["surface.lang.deno.runtime.hash"]);
|
||||
Assert.Equal("env,fs", signals["surface.lang.deno.permissions"]);
|
||||
Assert.Equal("https://deno.land,https://esm.sh", signals["surface.lang.deno.remote_origins"]);
|
||||
Assert.Equal("4", signals["surface.lang.deno.npm_modules"]);
|
||||
Assert.Equal("1", signals["surface.lang.deno.wasm_modules"]);
|
||||
Assert.Equal("2", signals["surface.lang.deno.dynamic_imports"]);
|
||||
Assert.Equal("2", signals["surface.lang.deno.module_loads"]);
|
||||
Assert.Equal("3", signals["surface.lang.deno.permission_uses"]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using StellaOps.Scanner.Analyzers.Lang.Deno.Internal.Runtime;
|
||||
|
||||
namespace StellaOps.Scanner.Analyzers.Lang.Deno.Tests.Deno;
|
||||
|
||||
public sealed class DenoRuntimePathHasherTests
|
||||
{
|
||||
[Fact]
|
||||
public void ProducesNormalizedRelativePathAndStableHash()
|
||||
{
|
||||
var root = TestPaths.CreateTemporaryDirectory();
|
||||
try
|
||||
{
|
||||
var absolute = Path.Combine(root, "subdir", "main.ts");
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(absolute)!);
|
||||
File.WriteAllText(absolute, "// sample");
|
||||
|
||||
var identity = DenoRuntimePathHasher.Create(root, absolute);
|
||||
|
||||
Assert.Equal("subdir/main.ts", identity.Normalized);
|
||||
Assert.Equal("2d0ef79c25b433a216f41853e89d8e1e1e1ef0b0e77d12b37a7f4f7c2a25f635", identity.PathSha256);
|
||||
}
|
||||
finally
|
||||
{
|
||||
TestPaths.SafeDelete(root);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UsesDotForRootPath()
|
||||
{
|
||||
var root = TestPaths.CreateTemporaryDirectory();
|
||||
try
|
||||
{
|
||||
var identity = DenoRuntimePathHasher.Create(root, root);
|
||||
Assert.Equal(".", identity.Normalized);
|
||||
Assert.Equal("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", identity.PathSha256);
|
||||
}
|
||||
finally
|
||||
{
|
||||
TestPaths.SafeDelete(root);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
using StellaOps.Scanner.Analyzers.Lang.Deno.Internal.Runtime;
|
||||
|
||||
namespace StellaOps.Scanner.Analyzers.Lang.Deno.Tests.Deno;
|
||||
|
||||
public sealed class DenoRuntimeTraceRecorderTests
|
||||
{
|
||||
[Fact]
|
||||
public void BuildsOrderedSnapshotAndHash()
|
||||
{
|
||||
var root = TestPaths.CreateTemporaryDirectory();
|
||||
try
|
||||
{
|
||||
var recorder = new DenoRuntimeTraceRecorder(root);
|
||||
|
||||
recorder.AddPermissionUse(
|
||||
absoluteModulePath: Path.Combine(root, "c.ts"),
|
||||
permission: "NET",
|
||||
details: "fetch",
|
||||
timestamp: DateTimeOffset.Parse("2025-11-17T12:00:02Z"));
|
||||
|
||||
recorder.AddModuleLoad(
|
||||
absoluteModulePath: Path.Combine(root, "b.ts"),
|
||||
reason: "dynamic-import",
|
||||
permissions: new[] { "fs" },
|
||||
origin: null,
|
||||
timestamp: DateTimeOffset.Parse("2025-11-17T12:00:01Z"));
|
||||
|
||||
recorder.AddModuleLoad(
|
||||
absoluteModulePath: Path.Combine(root, "a.ts"),
|
||||
reason: "static-import",
|
||||
permissions: Array.Empty<string>(),
|
||||
origin: "https://deno.land/x/std",
|
||||
timestamp: DateTimeOffset.Parse("2025-11-17T12:00:00Z"));
|
||||
|
||||
var snapshot = recorder.Build();
|
||||
|
||||
// Ensure ordering by timestamp then type
|
||||
var ndjson = System.Text.Encoding.UTF8.GetString(snapshot.Content);
|
||||
var lines = ndjson.Split('\n', StringSplitOptions.RemoveEmptyEntries);
|
||||
Assert.StartsWith("{\"type\":\"deno.module.load\",\"ts\":\"2025-11-17T12:00:00+00:00\"", lines[0]);
|
||||
Assert.StartsWith("{\"type\":\"deno.module.load\",\"ts\":\"2025-11-17T12:00:01+00:00\"", lines[1]);
|
||||
Assert.StartsWith("{\"type\":\"deno.permission.use\",\"ts\":\"2025-11-17T12:00:02+00:00\"", lines[2]);
|
||||
|
||||
Assert.Equal(3, snapshot.Metadata.EventCount);
|
||||
Assert.Equal(2, snapshot.Metadata.ModuleLoads);
|
||||
Assert.Equal(1, snapshot.Metadata.PermissionUses);
|
||||
Assert.Equal(new[] { "https://deno.land/x/std" }, snapshot.Metadata.RemoteOrigins);
|
||||
Assert.Equal(new[] { "net" }, snapshot.Metadata.UniquePermissions);
|
||||
Assert.Equal(0, snapshot.Metadata.NpmResolutions);
|
||||
Assert.Equal(0, snapshot.Metadata.WasmLoads);
|
||||
Assert.Equal(1, snapshot.Metadata.DynamicImports);
|
||||
|
||||
// Stable hash check
|
||||
Assert.Equal("198c6e038f1c39a78a52b844f051bfa6eaa5312faa66f1bc73d2f6d1048d8a7a", snapshot.Sha256);
|
||||
}
|
||||
finally
|
||||
{
|
||||
TestPaths.SafeDelete(root);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using System.Text;
|
||||
using StellaOps.Scanner.Analyzers.Lang.Deno.Internal.Runtime;
|
||||
using StellaOps.Scanner.Analyzers.Lang.Tests.TestUtilities;
|
||||
|
||||
namespace StellaOps.Scanner.Analyzers.Lang.Deno.Tests.Deno;
|
||||
|
||||
public sealed class DenoRuntimeTraceSerializerTests
|
||||
{
|
||||
[Fact]
|
||||
public void ProducesDeterministicNdjsonAndMetadata()
|
||||
{
|
||||
// Arrange
|
||||
var events = new DenoRuntimeEvent[]
|
||||
{
|
||||
new DenoModuleLoadEvent(
|
||||
Ts: DateTimeOffset.Parse("2025-11-17T12:00:00.123Z"),
|
||||
Module: new DenoModuleIdentity("app/main.ts", "abc123"),
|
||||
Reason: "dynamic-import",
|
||||
Permissions: new[] {"fs", "net"},
|
||||
Origin: "https://deno.land/x/std@0.208.0/http/server.ts"),
|
||||
new DenoPermissionUseEvent(
|
||||
Ts: DateTimeOffset.Parse("2025-11-17T12:00:01.234Z"),
|
||||
Permission: "ffi",
|
||||
Module: new DenoModuleIdentity("native/mod.ts", "def456"),
|
||||
Details: "Deno.dlopen")
|
||||
};
|
||||
|
||||
// Act
|
||||
var (content, hash, metadata) = DenoRuntimeTraceSerializer.Serialize(events);
|
||||
|
||||
// Assert
|
||||
var text = Encoding.UTF8.GetString(content);
|
||||
|
||||
Assert.Equal(2, metadata.EventCount);
|
||||
Assert.Equal(1, metadata.ModuleLoads);
|
||||
Assert.Equal(1, metadata.PermissionUses);
|
||||
Assert.Equal(new[] { "https://deno.land/x/std@0.208.0/http/server.ts" }, metadata.RemoteOrigins);
|
||||
Assert.Equal(new[] { "ffi", "fs", "net" }, metadata.UniquePermissions);
|
||||
Assert.Equal(0, metadata.NpmResolutions);
|
||||
Assert.Equal(0, metadata.WasmLoads);
|
||||
Assert.Equal(1, metadata.DynamicImports);
|
||||
|
||||
// Stable hash and NDJSON ordering
|
||||
const string expectedNdjson =
|
||||
@"{\""type\"":\"\"deno.module.load\"",\""ts\"":\"\"2025-11-17T12:00:00.123+00:00\"",\""module\"":{\""normalized\"":\"\"app/main.ts\"",\""path_sha256\"":\"\"abc123\""},\""reason\"":\"\"dynamic-import\"",\""permissions\"":[\"\"fs\"\", \""net\""],\""origin\"":\"\"https://deno.land/x/std@0.208.0/http/server.ts\""}
|
||||
{\""type\"":\"\"deno.permission.use\"",\""ts\"":\"\"2025-11-17T12:00:01.234+00:00\"",\""permission\"":\"\"ffi\"",\""module\"":{\""normalized\"":\"\"native/mod.ts\"",\""path_sha256\"":\"\"def456\""},\""details\"":\"\"Deno.dlopen\""}
|
||||
";
|
||||
|
||||
Assert.Equal(expectedNdjson.Replace("\r\n", "\n"), text.Replace("\r\n", "\n"));
|
||||
Assert.Equal("fdc6f07fe6b18b4cdd228c44b83e61d63063b7bd3422a2d3ab8000ac8420ceb0", hash);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user