feat: Implement Runtime Facts ingestion service and NDJSON reader
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
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:
@@ -0,0 +1,74 @@
|
||||
using System.IO.Compression;
|
||||
|
||||
namespace StellaOps.Scanner.Analyzers.Lang.Deno.Tests.TestFixtures;
|
||||
|
||||
internal static class BundleFixtureBuilder
|
||||
{
|
||||
public static string CreateSampleEszip(string directory)
|
||||
{
|
||||
Directory.CreateDirectory(directory);
|
||||
var bundlePath = Path.Combine(directory, "sample.eszip");
|
||||
|
||||
using (var archive = ZipFile.Open(bundlePath, ZipArchiveMode.Create))
|
||||
{
|
||||
var manifest = archive.CreateEntry("manifest.json", CompressionLevel.NoCompression);
|
||||
using (var writer = new StreamWriter(manifest.Open(), Encoding.UTF8))
|
||||
{
|
||||
writer.Write("""
|
||||
{
|
||||
"entry": "mod.ts",
|
||||
"modules": {
|
||||
"mod.ts": {
|
||||
"specifier": "file:///mod.ts",
|
||||
"path": "modules/mod.ts",
|
||||
"mediaType": "application/typescript"
|
||||
},
|
||||
"deps.ts": {
|
||||
"specifier": "https://example.com/deps.ts",
|
||||
"path": "modules/deps.ts",
|
||||
"mediaType": "application/typescript"
|
||||
}
|
||||
},
|
||||
"resources": [
|
||||
{
|
||||
"name": "assets/config.json",
|
||||
"mediaType": "application/json",
|
||||
"size": 42
|
||||
}
|
||||
]
|
||||
}
|
||||
""");
|
||||
}
|
||||
|
||||
AddTextEntry(archive, "modules/mod.ts", "import \"./deps.ts\";\nconsole.log('hello');\n");
|
||||
AddTextEntry(archive, "modules/deps.ts", "export const value = 42;\n");
|
||||
AddTextEntry(archive, "assets/config.json", "{ \"ok\": true }\n");
|
||||
}
|
||||
|
||||
return bundlePath;
|
||||
}
|
||||
|
||||
public static string CreateSampleCompiledBinary(string directory)
|
||||
{
|
||||
Directory.CreateDirectory(directory);
|
||||
var binaryPath = Path.Combine(directory, "sample.deno");
|
||||
var eszipPath = CreateSampleEszip(directory);
|
||||
var eszipBytes = File.ReadAllBytes(eszipPath);
|
||||
|
||||
using var stream = File.Create(binaryPath);
|
||||
using var writer = new BinaryWriter(stream, Encoding.UTF8, leaveOpen: true);
|
||||
writer.Write(Encoding.UTF8.GetBytes("FAKE_DENO_COMPILE_HEADER"));
|
||||
writer.Write(Encoding.UTF8.GetBytes(DenoCompileInspector.EszipMarker));
|
||||
writer.Flush();
|
||||
stream.Write(eszipBytes, 0, eszipBytes.Length);
|
||||
|
||||
return binaryPath;
|
||||
}
|
||||
|
||||
private static void AddTextEntry(ZipArchive archive, string entryPath, string contents)
|
||||
{
|
||||
var entry = archive.CreateEntry(entryPath, CompressionLevel.NoCompression);
|
||||
using var writer = new StreamWriter(entry.Open(), Encoding.UTF8);
|
||||
writer.Write(contents);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
using StellaOps.Scanner.Analyzers.Lang.Tests.TestUtilities;
|
||||
|
||||
namespace StellaOps.Scanner.Analyzers.Lang.Deno.Tests.TestFixtures;
|
||||
|
||||
internal static class DenoWorkspaceTestFixture
|
||||
{
|
||||
public static (string RootPath, string EnvDenoDir) Create()
|
||||
{
|
||||
var root = TestPaths.CreateTemporaryDirectory();
|
||||
CreateDenoFixture(root, out var envDir);
|
||||
return (root, envDir);
|
||||
}
|
||||
|
||||
public static void Cleanup(string root)
|
||||
{
|
||||
TestPaths.SafeDelete(root);
|
||||
}
|
||||
|
||||
private static void CreateDenoFixture(string root, out string envDenoDir)
|
||||
{
|
||||
Directory.CreateDirectory(root);
|
||||
|
||||
File.WriteAllText(Path.Combine(root, "deno.jsonc"), """
|
||||
// sample deno config
|
||||
{
|
||||
"importMap": "./import_map.json",
|
||||
"lock": {
|
||||
"enabled": true,
|
||||
"path": "./deno.lock"
|
||||
},
|
||||
"vendor": {
|
||||
"enabled": true,
|
||||
"path": "./vendor"
|
||||
},
|
||||
"nodeModulesDir": false,
|
||||
"imports": {
|
||||
"$std/": "https://deno.land/std@0.207.0/",
|
||||
"app/": "./src/app/",
|
||||
"data": "./data/data.json",
|
||||
"npmDynamic": "npm:dayjs@1",
|
||||
"nodeFs": "node:fs"
|
||||
},
|
||||
"scopes": {
|
||||
"https://deno.land/": {
|
||||
"fmt/": "https://deno.land/std@0.207.0/fmt/"
|
||||
}
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
Directory.CreateDirectory(Path.Combine(root, "src", "app"));
|
||||
Directory.CreateDirectory(Path.Combine(root, "data"));
|
||||
File.WriteAllText(Path.Combine(root, "data", "data.json"), "{ \"ok\": true }");
|
||||
File.WriteAllText(
|
||||
Path.Combine(root, "import_map.json"),
|
||||
"""
|
||||
{
|
||||
"imports": {
|
||||
"app/": "./src/app/main.ts",
|
||||
"vendor/": "https://deno.land/std@0.207.0/"
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
File.WriteAllText(
|
||||
Path.Combine(root, "deno.lock"),
|
||||
"""
|
||||
{
|
||||
"version": "4",
|
||||
"remote": {
|
||||
"https://deno.land/std@0.207.0/http/server.ts": "sha256-deadbeef",
|
||||
"https://example.com/mod.ts": "sha256-feedface",
|
||||
"node:fs": "builtin"
|
||||
},
|
||||
"redirects": {
|
||||
"https://deno.land/std/http/server.ts": "https://deno.land/std@0.207.0/http/server.ts"
|
||||
},
|
||||
"npm": {
|
||||
"specifiers": {
|
||||
"npm:dayjs@1": "dayjs@1.11.12"
|
||||
},
|
||||
"packages": {
|
||||
"dayjs@1.11.12": {
|
||||
"integrity": "sha512-sample",
|
||||
"dependencies": {
|
||||
"tslib": "tslib@2.6.3"
|
||||
}
|
||||
},
|
||||
"tslib@2.6.3": {
|
||||
"integrity": "sha512-tslib",
|
||||
"dependencies": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
var vendorRoot = Path.Combine(root, "vendor", "https", "deno.land", "std@0.207.0", "http");
|
||||
Directory.CreateDirectory(vendorRoot);
|
||||
File.WriteAllText(Path.Combine(vendorRoot, "server.ts"), "export const vendor = true;");
|
||||
|
||||
var vendorBase = Path.Combine(root, "vendor");
|
||||
File.WriteAllText(
|
||||
Path.Combine(vendorBase, "import_map.json"),
|
||||
"""
|
||||
{
|
||||
"imports": {
|
||||
"std/http/server.ts": "https://deno.land/std@0.207.0/http/server.ts"
|
||||
}
|
||||
}
|
||||
""");
|
||||
File.WriteAllText(
|
||||
Path.Combine(vendorBase, "deno.lock"),
|
||||
"""
|
||||
{
|
||||
"version": "1",
|
||||
"remote": {}
|
||||
}
|
||||
""");
|
||||
|
||||
CreateDenoDir(Path.Combine(root, ".deno"), "workspace.ts", includeRegistry: true);
|
||||
|
||||
envDenoDir = Path.Combine(root, "env-deno");
|
||||
CreateDenoDir(envDenoDir, "env.ts");
|
||||
|
||||
var layerFs = Path.Combine(root, "layers", "sha256-deadbeef", "fs");
|
||||
Directory.CreateDirectory(layerFs);
|
||||
CreateDenoDir(Path.Combine(layerFs, ".deno"), "layer.ts");
|
||||
|
||||
var layerVendor = Path.Combine(layerFs, "vendor", "https", "layer.example");
|
||||
Directory.CreateDirectory(layerVendor);
|
||||
File.WriteAllText(Path.Combine(layerFs, "vendor", "import_map.json"), "{\"imports\":{\"layer/\": \"https://layer.example/\"}}");
|
||||
}
|
||||
|
||||
private static void CreateDenoDir(string root, string fileName, bool includeRegistry = false)
|
||||
{
|
||||
var deps = Path.Combine(root, "deps", "https", "example.com");
|
||||
var gen = Path.Combine(root, "gen");
|
||||
var npm = Path.Combine(root, "npm");
|
||||
Directory.CreateDirectory(deps);
|
||||
Directory.CreateDirectory(gen);
|
||||
Directory.CreateDirectory(npm);
|
||||
|
||||
File.WriteAllText(Path.Combine(deps, fileName), "export const cache = true;");
|
||||
File.WriteAllText(Path.Combine(gen, $"{Path.GetFileNameWithoutExtension(fileName)}.js"), "console.log('gen');");
|
||||
File.WriteAllText(Path.Combine(npm, "package.json"), "{}");
|
||||
|
||||
if (includeRegistry)
|
||||
{
|
||||
CreateNpmRegistryPackage(root);
|
||||
}
|
||||
}
|
||||
|
||||
private static void CreateNpmRegistryPackage(string denoDirRoot)
|
||||
{
|
||||
var registryRoot = Path.Combine(denoDirRoot, "npm", "registry.npmjs.org");
|
||||
var dayjsRoot = Path.Combine(registryRoot, "dayjs", "1.11.12");
|
||||
Directory.CreateDirectory(dayjsRoot);
|
||||
|
||||
File.WriteAllText(
|
||||
Path.Combine(dayjsRoot, "package.json"),
|
||||
"""
|
||||
{
|
||||
"name": "dayjs",
|
||||
"version": "1.11.12",
|
||||
"exports": {
|
||||
".": {
|
||||
"deno": "./deno.mod.ts",
|
||||
"import": "./esm/index.js",
|
||||
"default": "./lib/index.js"
|
||||
},
|
||||
"./plugin": "./plugin/index.js"
|
||||
},
|
||||
"main": "./lib/index.js"
|
||||
}
|
||||
""");
|
||||
|
||||
File.WriteAllText(Path.Combine(dayjsRoot, "deno.mod.ts"), "export const deno = true;");
|
||||
Directory.CreateDirectory(Path.Combine(dayjsRoot, "esm"));
|
||||
File.WriteAllText(Path.Combine(dayjsRoot, "esm", "index.js"), "export const esm = true;");
|
||||
Directory.CreateDirectory(Path.Combine(dayjsRoot, "lib"));
|
||||
File.WriteAllText(Path.Combine(dayjsRoot, "lib", "index.js"), "module.exports = true;");
|
||||
Directory.CreateDirectory(Path.Combine(dayjsRoot, "plugin"));
|
||||
File.WriteAllText(Path.Combine(dayjsRoot, "plugin", "index.js"), "export const plugin = true;");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user