feat(ruby): Implement RubyManifestParser for parsing gem groups and dependencies
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
feat(ruby): Add RubyVendorArtifactCollector to collect vendor artifacts test(deno): Add golden tests for Deno analyzer with various fixtures test(deno): Create Deno module and package files for testing test(deno): Implement Deno lock and import map for dependency management test(deno): Add FFI and worker scripts for Deno testing feat(ruby): Set up Ruby workspace with Gemfile and dependencies feat(ruby): Add expected output for Ruby workspace tests feat(signals): Introduce CallgraphManifest model for signal processing
This commit is contained in:
@@ -0,0 +1 @@
|
||||
export const dynamicValue = 42;
|
||||
@@ -0,0 +1 @@
|
||||
export const dayjs = () => ({ iso: () => "2024-09-01" });
|
||||
@@ -0,0 +1,3 @@
|
||||
export function dayjs() {
|
||||
return { iso: () => "2024-09-01" };
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
module.exports = function dayjs() {
|
||||
return { iso: () => "2024-09-01" };
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "dayjs",
|
||||
"version": "1.11.12",
|
||||
"exports": {
|
||||
".": {
|
||||
"deno": "./deno.mod.ts",
|
||||
"import": "./esm/index.js",
|
||||
"default": "./lib/index.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "tslib",
|
||||
"version": "2.6.3"
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"ok": true
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// Deterministic Deno workspace exercising vendor, npm, FFI, worker, and fetch flows.
|
||||
{
|
||||
"importMap": "./import_map.json",
|
||||
"lock": {
|
||||
"enabled": true,
|
||||
"path": "./deno.lock"
|
||||
},
|
||||
"nodeModulesDir": false,
|
||||
"tasks": {
|
||||
"serve": "deno run --allow-net ./src/main.ts"
|
||||
},
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"noUncheckedIndexedAccess": true
|
||||
},
|
||||
"vendor": {
|
||||
"enabled": true,
|
||||
"path": "./vendor"
|
||||
},
|
||||
"fmt": {
|
||||
"useTabs": false,
|
||||
"lineWidth": 100
|
||||
}
|
||||
}
|
||||
28
src/Scanner/__Tests/StellaOps.Scanner.Analyzers.Lang.Tests/Fixtures/lang/deno/full/deno.lock
generated
Normal file
28
src/Scanner/__Tests/StellaOps.Scanner.Analyzers.Lang.Tests/Fixtures/lang/deno/full/deno.lock
generated
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"version": "4",
|
||||
"remote": {
|
||||
"https://deno.land/std@0.207.0/http/server.ts": "sha256-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef",
|
||||
"https://cdn.example.com/dynamic/mod.ts": "sha256-feedfacefeedfacefeedfacefeedfacefeedfacefeedfacefeedfacefeedface",
|
||||
"https://api.example.com/data.json": "sha256-0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"
|
||||
},
|
||||
"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-dayjs-integrity",
|
||||
"dependencies": {
|
||||
"tslib": "tslib@2.6.3"
|
||||
}
|
||||
},
|
||||
"tslib@2.6.3": {
|
||||
"integrity": "sha512-sample-tslib",
|
||||
"dependencies": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
"pending"
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"imports": {
|
||||
"app/": "./src/",
|
||||
"ffi/": "./src/ffi/",
|
||||
"workers/": "./src/workers/",
|
||||
"npmDynamic": "npm:dayjs@1",
|
||||
"nodeFs": "node:fs",
|
||||
"nodeCrypto": "node:crypto",
|
||||
"nodeWorker": "node:worker_threads",
|
||||
"denoFfi": "deno:ffi"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
export function openBridge() {
|
||||
const lib = Deno.dlopen("./ffi/libexample.so", {
|
||||
add: { parameters: ["i32", "i32"], result: "i32" }
|
||||
});
|
||||
lib.close();
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
FAKEELF
|
||||
@@ -0,0 +1,41 @@
|
||||
import dayjs from "npmDynamic";
|
||||
import { serve } from "https://deno.land/std@0.207.0/http/server.ts";
|
||||
import { Worker } from "nodeWorker";
|
||||
import { dlopen } from "denoFfi";
|
||||
import "workers/metrics.ts";
|
||||
|
||||
const dynamicTarget = "https://cdn.example.com/dynamic/mod.ts";
|
||||
const fetchTarget = "https://api.example.com/data.json";
|
||||
|
||||
async function spinWorkers() {
|
||||
const worker = new Worker(new URL("./workers/child.ts", import.meta.url), { type: "module" });
|
||||
worker.postMessage({ kind: "child", payload: "ping" });
|
||||
|
||||
const shared = new SharedWorker(new URL("./workers/shared.ts", import.meta.url), { type: "module" });
|
||||
shared.port.postMessage({ kind: "shared", payload: "metrics" });
|
||||
}
|
||||
|
||||
function loadFfi() {
|
||||
const lib = dlopen("./ffi/libexample.so", {
|
||||
add: { parameters: ["i32", "i32"], result: "i32" }
|
||||
});
|
||||
try {
|
||||
return lib.symbols;
|
||||
} finally {
|
||||
lib.close();
|
||||
}
|
||||
}
|
||||
|
||||
export async function main() {
|
||||
await spinWorkers();
|
||||
loadFfi();
|
||||
|
||||
await import(dynamicTarget);
|
||||
await fetch(fetchTarget);
|
||||
|
||||
await serve(() => new Response(dayjs().format()), { hostname: "127.0.0.1", port: 8088 });
|
||||
}
|
||||
|
||||
if (import.meta.main) {
|
||||
await main();
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
self.onmessage = (event) => {
|
||||
const payload = event.data ?? {};
|
||||
self.postMessage({ ...payload, worker: "child" });
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
addEventListener("message", (event) => {
|
||||
console.log("metric", event.data);
|
||||
});
|
||||
@@ -0,0 +1,6 @@
|
||||
onconnect = (event) => {
|
||||
const [port] = event.ports;
|
||||
port.onmessage = (message) => {
|
||||
port.postMessage({ kind: "shared", payload: message.data });
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
export async function serve(handler: () => Response, _options?: { hostname?: string; port?: number }) {
|
||||
return handler();
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
---
|
||||
BUNDLE_GEMFILE: "apps/api/Gemfile"
|
||||
BUNDLE_PATH: "apps/api/vendor/bundle"
|
||||
@@ -0,0 +1,12 @@
|
||||
source "https://rubygems.org"
|
||||
|
||||
gem "rails", "~> 7.1.0"
|
||||
|
||||
group :development, :test do
|
||||
gem "pry"
|
||||
gem "rubocop", require: false
|
||||
end
|
||||
|
||||
group :production, :console do
|
||||
gem "puma", "~> 6.4"
|
||||
end
|
||||
@@ -0,0 +1,19 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
pry (1.0.0)
|
||||
puma (6.4.2)
|
||||
rails (7.1.3)
|
||||
rubocop (1.60.0)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
pry
|
||||
puma (~> 6.4)
|
||||
rails (~> 7.1.0)
|
||||
rubocop
|
||||
|
||||
BUNDLED WITH
|
||||
2.5.10
|
||||
@@ -0,0 +1,6 @@
|
||||
require "rails"
|
||||
require "puma"
|
||||
require "bootsnap"
|
||||
require "sidekiq"
|
||||
|
||||
puts "workspace"
|
||||
@@ -0,0 +1,7 @@
|
||||
source "https://rubygems.org"
|
||||
|
||||
group :jobs do
|
||||
gem "sidekiq"
|
||||
end
|
||||
|
||||
gem "bootsnap"
|
||||
@@ -0,0 +1,15 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
bootsnap (1.18.4)
|
||||
sidekiq (7.2.4)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
bootsnap
|
||||
sidekiq
|
||||
|
||||
BUNDLED WITH
|
||||
2.5.10
|
||||
@@ -0,0 +1 @@
|
||||
[]
|
||||
@@ -21,4 +21,17 @@ public sealed class RubyLanguageAnalyzerTests
|
||||
cancellationToken: TestContext.Current.CancellationToken,
|
||||
usageHints: usageHints);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WorkspaceLockfilesAndVendorArtifactsAsync()
|
||||
{
|
||||
var fixture = TestPaths.ResolveFixture("lang", "ruby", "workspace");
|
||||
var golden = Path.Combine(fixture, "expected.json");
|
||||
|
||||
await LanguageAnalyzerTestHarness.AssertDeterministicAsync(
|
||||
fixture,
|
||||
golden,
|
||||
new ILanguageAnalyzer[] { new RubyLanguageAnalyzer() },
|
||||
cancellationToken: TestContext.Current.CancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ public static class JavaClassFileFactory
|
||||
using var buffer = new MemoryStream();
|
||||
using var writer = new BigEndianWriter(buffer);
|
||||
|
||||
WriteClassFileHeader(writer, constantPoolCount: 18);
|
||||
WriteClassFileHeader(writer, constantPoolCount: 20);
|
||||
|
||||
writer.WriteByte((byte)ConstantTag.Utf8); writer.WriteUtf8(internalClassName); // #1
|
||||
writer.WriteByte((byte)ConstantTag.Class); writer.WriteUInt16(1); // #2
|
||||
@@ -59,14 +59,16 @@ public static class JavaClassFileFactory
|
||||
writer.WriteByte((byte)ConstantTag.Utf8); writer.WriteUtf8("Code"); // #7
|
||||
writer.WriteByte((byte)ConstantTag.Utf8); writer.WriteUtf8(resourcePath); // #8
|
||||
writer.WriteByte((byte)ConstantTag.String); writer.WriteUInt16(8); // #9
|
||||
writer.WriteByte((byte)ConstantTag.Utf8); writer.WriteUtf8("java/lang/Class"); // #10
|
||||
writer.WriteByte((byte)ConstantTag.Utf8); writer.WriteUtf8("java/lang/ClassLoader"); // #10
|
||||
writer.WriteByte((byte)ConstantTag.Class); writer.WriteUInt16(10); // #11
|
||||
writer.WriteByte((byte)ConstantTag.Utf8); writer.WriteUtf8("getResource"); // #12
|
||||
writer.WriteByte((byte)ConstantTag.Utf8); writer.WriteUtf8("(Ljava/lang/String;)Ljava/net/URL;"); // #13
|
||||
writer.WriteByte((byte)ConstantTag.Utf8); writer.WriteUtf8("getSystemClassLoader"); // #12
|
||||
writer.WriteByte((byte)ConstantTag.Utf8); writer.WriteUtf8("()Ljava/lang/ClassLoader;"); // #13
|
||||
writer.WriteByte((byte)ConstantTag.NameAndType); writer.WriteUInt16(12); writer.WriteUInt16(13); // #14
|
||||
writer.WriteByte((byte)ConstantTag.Methodref); writer.WriteUInt16(11); writer.WriteUInt16(14); // #15
|
||||
writer.WriteByte((byte)ConstantTag.Utf8); writer.WriteUtf8("dummy"); // #16
|
||||
writer.WriteByte((byte)ConstantTag.String); writer.WriteUInt16(16); // #17
|
||||
writer.WriteByte((byte)ConstantTag.Utf8); writer.WriteUtf8("getResource"); // #16
|
||||
writer.WriteByte((byte)ConstantTag.Utf8); writer.WriteUtf8("(Ljava/lang/String;)Ljava/net/URL;"); // #17
|
||||
writer.WriteByte((byte)ConstantTag.NameAndType); writer.WriteUInt16(16); writer.WriteUInt16(17); // #18
|
||||
writer.WriteByte((byte)ConstantTag.Methodref); writer.WriteUInt16(11); writer.WriteUInt16(18); // #19
|
||||
|
||||
writer.WriteUInt16(0x0001); // public
|
||||
writer.WriteUInt16(2); // this class
|
||||
@@ -76,7 +78,7 @@ public static class JavaClassFileFactory
|
||||
writer.WriteUInt16(0); // fields
|
||||
writer.WriteUInt16(1); // methods
|
||||
|
||||
WriteResourceLookupMethod(writer, methodNameIndex: 5, descriptorIndex: 6, classConstantIndex: 4, stringIndex: 9, methodRefIndex: 15);
|
||||
WriteResourceLookupMethod(writer, methodNameIndex: 5, descriptorIndex: 6, systemLoaderMethodRefIndex: 15, stringIndex: 9, getResourceMethodRefIndex: 19);
|
||||
|
||||
writer.WriteUInt16(0); // class attributes
|
||||
|
||||
@@ -188,7 +190,13 @@ public static class JavaClassFileFactory
|
||||
writer.WriteBytes(codeBytes);
|
||||
}
|
||||
|
||||
private static void WriteResourceLookupMethod(BigEndianWriter writer, ushort methodNameIndex, ushort descriptorIndex, ushort classConstantIndex, ushort stringIndex, ushort methodRefIndex)
|
||||
private static void WriteResourceLookupMethod(
|
||||
BigEndianWriter writer,
|
||||
ushort methodNameIndex,
|
||||
ushort descriptorIndex,
|
||||
ushort systemLoaderMethodRefIndex,
|
||||
ushort stringIndex,
|
||||
ushort getResourceMethodRefIndex)
|
||||
{
|
||||
writer.WriteUInt16(0x0009);
|
||||
writer.WriteUInt16(methodNameIndex);
|
||||
@@ -201,13 +209,13 @@ public static class JavaClassFileFactory
|
||||
{
|
||||
codeWriter.WriteUInt16(2);
|
||||
codeWriter.WriteUInt16(0);
|
||||
codeWriter.WriteUInt32(8);
|
||||
codeWriter.WriteByte(0x13); // ldc_w for class literal
|
||||
codeWriter.WriteUInt16(classConstantIndex);
|
||||
codeWriter.WriteByte(0x12);
|
||||
codeWriter.WriteUInt32(10);
|
||||
codeWriter.WriteByte(0xB8); // invokestatic
|
||||
codeWriter.WriteUInt16(systemLoaderMethodRefIndex);
|
||||
codeWriter.WriteByte(0x12); // ldc
|
||||
codeWriter.WriteByte((byte)stringIndex);
|
||||
codeWriter.WriteByte(0xB6);
|
||||
codeWriter.WriteUInt16(methodRefIndex);
|
||||
codeWriter.WriteByte(0xB6); // invokevirtual
|
||||
codeWriter.WriteUInt16(getResourceMethodRefIndex);
|
||||
codeWriter.WriteByte(0x57);
|
||||
codeWriter.WriteByte(0xB1);
|
||||
codeWriter.WriteUInt16(0);
|
||||
|
||||
Reference in New Issue
Block a user