feat: Implement Runtime Facts ingestion service and NDJSON reader
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled

- Added RuntimeFactsNdjsonReader for reading NDJSON formatted runtime facts.
- Introduced IRuntimeFactsIngestionService interface and its implementation.
- Enhanced Program.cs to register new services and endpoints for runtime facts.
- Updated CallgraphIngestionService to include CAS URI in stored artifacts.
- Created RuntimeFactsValidationException for validation errors during ingestion.
- Added tests for RuntimeFactsIngestionService and RuntimeFactsNdjsonReader.
- Implemented SignalsSealedModeMonitor for compliance checks in sealed mode.
- Updated project dependencies for testing utilities.
This commit is contained in:
master
2025-11-10 07:56:15 +02:00
parent 9df52d84aa
commit 69c59defdc
132 changed files with 19718 additions and 9334 deletions

View File

@@ -0,0 +1,121 @@
using System.Linq;
using StellaOps.Scanner.Analyzers.Lang.Deno.Internal;
using StellaOps.Scanner.Analyzers.Lang.Deno.Tests.TestFixtures;
using StellaOps.Scanner.Analyzers.Lang.Tests.TestUtilities;
namespace StellaOps.Scanner.Analyzers.Lang.Deno.Tests.Deno;
public sealed class DenoWorkspaceNormalizerTests
{
[Fact]
public async Task WorkspaceFixtureProducesDeterministicOutputAsync()
{
var (root, envDenoDir) = DenoWorkspaceTestFixture.Create();
var previousDenoDir = Environment.GetEnvironmentVariable("DENO_DIR");
try
{
Environment.SetEnvironmentVariable("DENO_DIR", envDenoDir);
var context = new LanguageAnalyzerContext(root, TimeProvider.System);
var workspace = await DenoWorkspaceNormalizer.NormalizeAsync(context, CancellationToken.None);
var config = Assert.Single(workspace.Configurations);
Assert.EndsWith("deno.jsonc", config.AbsolutePath, StringComparison.OrdinalIgnoreCase);
Assert.True(config.LockEnabled);
Assert.NotNull(config.InlineImportMap);
Assert.NotNull(config.ImportMapPath);
Assert.NotNull(config.VendorDirectoryPath);
Assert.Contains(workspace.ImportMaps, map => map.IsInline);
Assert.Contains(
workspace.ImportMaps,
map => map.AbsolutePath is not null && map.AbsolutePath.EndsWith("import_map.json", StringComparison.OrdinalIgnoreCase));
Assert.Contains(workspace.LockFiles, file => file.AbsolutePath.EndsWith("deno.lock", StringComparison.OrdinalIgnoreCase));
Assert.Contains(workspace.Vendors, vendor => vendor.AbsolutePath.EndsWith(Path.Combine("vendor"), StringComparison.OrdinalIgnoreCase));
Assert.Contains(workspace.CacheLocations, cache => cache.Kind == DenoCacheLocationKind.Env);
Assert.Contains(
workspace.CacheLocations,
cache => cache.Kind == DenoCacheLocationKind.Workspace && cache.AbsolutePath.EndsWith(".deno", StringComparison.OrdinalIgnoreCase));
Assert.Contains(workspace.FileSystem.Files, file => file.VirtualPath == "workspace://deno.jsonc");
Assert.Contains(workspace.FileSystem.Files, file => file.VirtualPath.StartsWith("vendor://", StringComparison.Ordinal));
Assert.Contains(
workspace.FileSystem.Files,
file => file.VirtualPath.StartsWith("deno-dir://", StringComparison.Ordinal) ||
file.VirtualPath.StartsWith("layer://", StringComparison.Ordinal));
}
finally
{
Environment.SetEnvironmentVariable("DENO_DIR", previousDenoDir);
DenoWorkspaceTestFixture.Cleanup(root);
}
}
[Fact]
public async Task GraphResolverCapturesImportAndCacheEdgesAsync()
{
var (root, envDenoDir) = DenoWorkspaceTestFixture.Create();
var previousDenoDir = Environment.GetEnvironmentVariable("DENO_DIR");
try
{
Environment.SetEnvironmentVariable("DENO_DIR", envDenoDir);
var context = new LanguageAnalyzerContext(root, TimeProvider.System);
var workspace = await DenoWorkspaceNormalizer.NormalizeAsync(context, CancellationToken.None);
var lockFile = workspace.LockFiles.Single(lf => string.Equals(lf.RelativePath, "deno.lock", StringComparison.OrdinalIgnoreCase));
Assert.Contains(lockFile.RemoteEntries, entry => entry.Key.Contains("server.ts", StringComparison.Ordinal));
var graph = DenoModuleGraphResolver.Resolve(workspace, CancellationToken.None);
var compatibility = DenoNpmCompatibilityAdapter.Analyze(workspace, graph, CancellationToken.None);
Assert.NotEmpty(graph.Nodes);
Assert.NotEmpty(graph.Edges);
var remoteNode = graph.Nodes.FirstOrDefault(
node => node.Kind == DenoModuleKind.RemoteModule &&
node.Id == "remote::https://deno.land/std@0.207.0/http/server.ts");
Assert.NotNull(remoteNode);
Assert.Equal("sha256-deadbeef", remoteNode!.Integrity);
Assert.Contains(
graph.Edges,
edge => edge.ImportKind == DenoImportKind.Cache &&
edge.Provenance.StartsWith("vendor-cache:", StringComparison.Ordinal) &&
edge.Specifier.Contains("https://deno.land/std@0.207.0/http/server.ts", StringComparison.Ordinal));
Assert.Contains(
graph.Edges,
edge => edge.ImportKind == DenoImportKind.NpmBridge &&
edge.Specifier == "npm:dayjs@1" &&
edge.Resolution == "dayjs@1.11.12");
Assert.Contains(
graph.Edges,
edge => edge.ImportKind == DenoImportKind.JsonAssertion &&
edge.Specifier == "data" &&
edge.Resolution?.EndsWith("data/data.json", StringComparison.OrdinalIgnoreCase) == true);
Assert.Contains(
graph.Edges,
edge => edge.ImportKind == DenoImportKind.Redirect &&
edge.Specifier == "https://deno.land/std/http/server.ts");
Assert.Contains(
compatibility.BuiltinUsages,
usage => usage.Specifier == "node:fs");
var npmResolution = compatibility.NpmResolutions.First(res => res.Specifier == "npm:dayjs@1");
Assert.True(npmResolution.ExistsOnDisk);
Assert.Equal("deno", npmResolution.Condition);
Assert.True(npmResolution.ResolvedPath?.EndsWith("deno.mod.ts", StringComparison.OrdinalIgnoreCase));
}
finally
{
Environment.SetEnvironmentVariable("DENO_DIR", previousDenoDir);
DenoWorkspaceTestFixture.Cleanup(root);
}
}
}