mirror of
https://github.com/morluto/rea.git
synced 2026-10-12 02:19:24 +00:00
Validate declared artifact and MVID scopes at managed Evidence admission, and reject conflicting known module declarations across graph inputs. Join boundary tokens to members only under matching known MVID scopes; preserve facts and report partial coverage when scope is unknown. Prefer an observed MVID-bearing declaration with its supplying Evidence. Normalize GUID casing for module node identity while preserving original strings in observations. Validation: 285 tests across 34 focused suites passed, followed by the final 12-test managed graph suite and managed CLI/MCP regressions. check:fast and architecture guards passed; no real native providers were run.
632 lines
22 KiB
TypeScript
632 lines
22 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
|
|
import { projectManagedApplicationGraphEvidence } from "../../../src/application/managed/ManagedApplicationGraphService.js";
|
|
import { managedApplicationGraphReferenceInputSchema } from "../../../src/contracts/managed/managedWorkflowToolContracts.js";
|
|
import { MANAGED_APPLICATION_GRAPH_EXAMPLE } from "../../../src/contracts/managed/managedWorkflowExamples.js";
|
|
import { traceApplicationFeatureEvidence } from "../../../src/application/javascript/JavaScriptApplicationWorkflowService.js";
|
|
import { MANAGED_STATIC_PROVIDER } from "../../../src/application/InvestigationProviders.js";
|
|
import { createEvidence, parseEvidence } from "../../../src/domain/evidence.js";
|
|
import { parseJavaScriptApplicationGraph } from "../../../src/domain/javascript/javascriptApplicationGraph.js";
|
|
import { managedApplicationGraphResultSchema } from "../../../src/domain/managed/managedApplicationGraph.js";
|
|
import {
|
|
managedMemberInspectionSchema,
|
|
managedNativeBoundaryInspectionSchema,
|
|
} from "../../../src/domain/managed/managedArtifact.js";
|
|
import { inspectManagedArtifactBytes } from "../../../src/dotnet/ManagedArtifactInspector.js";
|
|
import { inspectManagedMembersBytes } from "../../../src/dotnet/ManagedMemberInspector.js";
|
|
import { inspectManagedNativeBoundariesBytes } from "../../../src/dotnet/ManagedNativeBoundaryInspector.js";
|
|
import {
|
|
buildManagedPeFixture,
|
|
managedPeFixtureTarget,
|
|
} from "../../../src/dotnet/ManagedPe.fixture.js";
|
|
|
|
const createManagedInteropEvidence = () => {
|
|
const bytes = buildManagedPeFixture({
|
|
pinvoke: {
|
|
moduleName: "user32.dll",
|
|
importName: "MessageBoxW",
|
|
mappingFlags: 0x0345,
|
|
},
|
|
});
|
|
const binary = managedPeFixtureTarget(bytes, "/fixture/ManagedInterop.exe");
|
|
const managedArtifact = inspectManagedArtifactBytes(bytes, binary);
|
|
const members = inspectManagedMembersBytes(bytes, binary);
|
|
const boundaries = inspectManagedNativeBoundariesBytes(bytes, binary);
|
|
|
|
return {
|
|
artifactEvidence: createEvidence(binary, MANAGED_STATIC_PROVIDER, {
|
|
operation: "inspect_managed_artifact",
|
|
parameters: {},
|
|
result: managedArtifact,
|
|
rawResult: null,
|
|
limitations: managedArtifact.limitations,
|
|
locations: [{ kind: "artifact-path", path: binary.path }],
|
|
}),
|
|
memberEvidence: createEvidence(binary, MANAGED_STATIC_PROVIDER, {
|
|
operation: "inspect_managed_members",
|
|
parameters: {},
|
|
result: members,
|
|
rawResult: null,
|
|
limitations: members.limitations,
|
|
locations: [{ kind: "artifact-path", path: binary.path }],
|
|
}),
|
|
boundaryEvidence: createEvidence(binary, MANAGED_STATIC_PROVIDER, {
|
|
operation: "inspect_managed_native_boundaries",
|
|
parameters: {},
|
|
result: boundaries,
|
|
rawResult: null,
|
|
limitations: boundaries.limitations,
|
|
locations: [{ kind: "artifact-path", path: binary.path }],
|
|
}),
|
|
};
|
|
};
|
|
|
|
describe("managed application graph projection", () => {
|
|
it("projects managed metadata and native declarations into authenticated graph Evidence", () => {
|
|
const { artifactEvidence, memberEvidence, boundaryEvidence } =
|
|
createManagedInteropEvidence();
|
|
|
|
const evidence = projectManagedApplicationGraphEvidence({
|
|
managed_artifact: artifactEvidence,
|
|
managed_members: memberEvidence,
|
|
managed_native_boundaries: boundaryEvidence,
|
|
});
|
|
|
|
expect(
|
|
evidence.ok,
|
|
evidence.ok
|
|
? undefined
|
|
: `${JSON.stringify(evidence.error)} cause=${String(evidence.error.cause)}`,
|
|
).toBe(true);
|
|
if (!evidence.ok) throw new Error("projection failed");
|
|
const parsed = parseEvidence(evidence.value);
|
|
expect(parsed).toMatchObject({
|
|
operation: "project_managed_application_graph",
|
|
predicate_type: "rea.managed-application-graph",
|
|
provider: { id: "rea-dotnet-workflows" },
|
|
confidence: "inferred",
|
|
authority: "analyst-inference",
|
|
evidence_links: [
|
|
artifactEvidence.evidence_id,
|
|
memberEvidence.evidence_id,
|
|
boundaryEvidence.evidence_id,
|
|
],
|
|
});
|
|
const result = managedApplicationGraphResultSchema.parse(
|
|
parsed.normalized_result,
|
|
);
|
|
const graph = parseJavaScriptApplicationGraph(result.graph);
|
|
expect(result.summary).toMatchObject({
|
|
assemblies: 1,
|
|
modules: 1,
|
|
types: 1,
|
|
methods: 1,
|
|
fields: 1,
|
|
pinvoke_imports: 1,
|
|
});
|
|
expect(graph.nodes.map(({ kind }) => kind)).toEqual(
|
|
expect.arrayContaining([
|
|
"artifact",
|
|
"managed-assembly",
|
|
"managed-module",
|
|
"managed-type",
|
|
"managed-method",
|
|
"managed-field",
|
|
"managed-pinvoke-import",
|
|
]),
|
|
);
|
|
const allEvidenceIds = [
|
|
artifactEvidence.evidence_id,
|
|
memberEvidence.evidence_id,
|
|
boundaryEvidence.evidence_id,
|
|
].sort();
|
|
const observedEvidenceIds = (kind: string): readonly string[] => {
|
|
const observation = graph.nodes.find((node) => node.kind === kind)
|
|
?.observations[0];
|
|
if (observation === undefined)
|
|
throw new Error(`Expected ${kind} observation`);
|
|
return observation.evidence.evidence_ids;
|
|
};
|
|
expect(observedEvidenceIds("artifact")).toEqual(allEvidenceIds);
|
|
expect(observedEvidenceIds("managed-assembly")).toEqual([
|
|
artifactEvidence.evidence_id,
|
|
]);
|
|
expect(observedEvidenceIds("managed-module")).toEqual([
|
|
artifactEvidence.evidence_id,
|
|
]);
|
|
for (const kind of ["managed-type", "managed-method", "managed-field"])
|
|
expect(observedEvidenceIds(kind)).toEqual([memberEvidence.evidence_id]);
|
|
expect(observedEvidenceIds("managed-pinvoke-import")).toEqual([
|
|
boundaryEvidence.evidence_id,
|
|
]);
|
|
for (const edge of graph.edges.filter(
|
|
({ relation }) => relation === "contains",
|
|
))
|
|
expect(edge.evidence.evidence_ids).toEqual(allEvidenceIds);
|
|
const method = graph.nodes.find(
|
|
({ kind, observations }) =>
|
|
kind === "managed-method" &&
|
|
observations[0]?.label === "Fixture.Program.Main",
|
|
);
|
|
expect(method).toBeDefined();
|
|
const importEdge = graph.edges.find(
|
|
({ source_node_id, relation, target_node_id }) =>
|
|
source_node_id === method?.node_id &&
|
|
relation === "imports" &&
|
|
graph.nodes.find(({ node_id: id }) => id === target_node_id)?.kind ===
|
|
"managed-pinvoke-import",
|
|
);
|
|
expect(importEdge).toBeDefined();
|
|
expect(importEdge?.evidence.evidence_ids).toEqual(
|
|
[memberEvidence.evidence_id, boundaryEvidence.evidence_id].sort(),
|
|
);
|
|
expect(
|
|
graph.nodes.flatMap(({ observations }) =>
|
|
observations.map(({ evidence }) => evidence.authority),
|
|
),
|
|
).toContain("managed-static-analysis");
|
|
|
|
const trace = traceApplicationFeatureEvidence({
|
|
application: parsed,
|
|
native_observations: [],
|
|
seed: {
|
|
kind: "string",
|
|
value: "MessageBoxW",
|
|
match: "exact",
|
|
case_sensitive: true,
|
|
},
|
|
direction: "incoming",
|
|
});
|
|
expect(trace.ok, trace.ok ? undefined : JSON.stringify(trace.error)).toBe(
|
|
true,
|
|
);
|
|
if (!trace.ok) throw new Error("trace failed");
|
|
expect(trace.value.normalized_result).toMatchObject({
|
|
source_evidence_id: parsed.evidence_id,
|
|
summary: { matched_seeds: 1 },
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("managed application graph request", () => {
|
|
it("accepts any nonempty set of inline sources and rejects duplicates", () => {
|
|
const evidence = MANAGED_APPLICATION_GRAPH_EXAMPLE.managed_members;
|
|
expect(
|
|
managedApplicationGraphReferenceInputSchema.safeParse({
|
|
managed_members: evidence,
|
|
}).success,
|
|
).toBe(true);
|
|
expect(
|
|
managedApplicationGraphReferenceInputSchema.safeParse({}).success,
|
|
).toBe(false);
|
|
expect(
|
|
managedApplicationGraphReferenceInputSchema.safeParse({
|
|
managed_members: evidence,
|
|
managed_native_boundaries: evidence,
|
|
}).success,
|
|
).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("managed application graph coverage", () => {
|
|
it("rejects managed Evidence whose artifact digest differs from its subject", () => {
|
|
const bytes = buildManagedPeFixture();
|
|
const binary = managedPeFixtureTarget(bytes, "/fixture/Mismatch.dll");
|
|
const members = inspectManagedMembersBytes(bytes, binary);
|
|
const mismatched = createEvidence(binary, MANAGED_STATIC_PROVIDER, {
|
|
operation: "inspect_managed_members",
|
|
parameters: {},
|
|
result: {
|
|
...members,
|
|
artifact: { ...members.artifact, sha256: "b".repeat(64) },
|
|
identity_scope: {
|
|
...members.identity_scope,
|
|
requires_artifact_sha256: "b".repeat(64),
|
|
},
|
|
},
|
|
});
|
|
const rejected = projectManagedApplicationGraphEvidence({
|
|
managed_members: mismatched,
|
|
});
|
|
expect(rejected.ok).toBe(false);
|
|
if (rejected.ok) throw new Error("mismatched managed Evidence accepted");
|
|
expect(JSON.stringify(rejected.error)).toContain(
|
|
`Managed Evidence inspect_managed_members (${mismatched.evidence_id}) subject SHA-256 ${binary.sha256} does not match normalized artifact SHA-256 ${"b".repeat(64)}`,
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("managed application graph identity facts", () => {
|
|
it.each([
|
|
["managed_members", "memberEvidence"],
|
|
["managed_native_boundaries", "boundaryEvidence"],
|
|
] as const)(
|
|
"binds a module from %s to its supplying Evidence",
|
|
(inputKey, evidenceKey) => {
|
|
const source = createManagedInteropEvidence()[evidenceKey];
|
|
const projected = projectManagedApplicationGraphEvidence({
|
|
[inputKey]: source,
|
|
});
|
|
if (!projected.ok) throw projected.error;
|
|
const result = managedApplicationGraphResultSchema.parse(
|
|
parseEvidence(projected.value).normalized_result,
|
|
);
|
|
const graph = parseJavaScriptApplicationGraph(result.graph);
|
|
expect(result.summary).toMatchObject({ assemblies: 0, modules: 1 });
|
|
expect(
|
|
graph.nodes.find(({ kind }) => kind === "managed-module")
|
|
?.observations[0],
|
|
).toMatchObject({
|
|
evidence: {
|
|
extractor: { operation: source.operation },
|
|
evidence_ids: [source.evidence_id],
|
|
},
|
|
});
|
|
expect(result.evidence_links).toEqual([source.evidence_id]);
|
|
expect(result.limitations).toContain(
|
|
"Managed artifact Evidence was not supplied; assembly identity observations are absent.",
|
|
);
|
|
},
|
|
);
|
|
|
|
it("reports no assembly or module when the inspector observes no identity rows", () => {
|
|
const bytes = buildManagedPeFixture({
|
|
moduleRowCount: 0,
|
|
assemblyRowCount: 0,
|
|
});
|
|
const binary = managedPeFixtureTarget(bytes, "/fixture/NoIdentityRows.exe");
|
|
const inspection = inspectManagedArtifactBytes(bytes, binary);
|
|
expect(inspection).toMatchObject({ module: null, assembly: null });
|
|
const artifactEvidence = createEvidence(binary, MANAGED_STATIC_PROVIDER, {
|
|
operation: "inspect_managed_artifact",
|
|
parameters: {},
|
|
result: inspection,
|
|
rawResult: null,
|
|
limitations: inspection.limitations,
|
|
locations: [{ kind: "artifact-path", path: binary.path }],
|
|
});
|
|
|
|
const projected = projectManagedApplicationGraphEvidence({
|
|
managed_artifact: artifactEvidence,
|
|
});
|
|
if (!projected.ok) throw projected.error;
|
|
const result = managedApplicationGraphResultSchema.parse(
|
|
parseEvidence(projected.value).normalized_result,
|
|
);
|
|
const graph = parseJavaScriptApplicationGraph(result.graph);
|
|
expect(result.summary).toMatchObject({ assemblies: 0, modules: 0 });
|
|
expect(
|
|
graph.nodes.filter(
|
|
({ kind }) => kind === "managed-assembly" || kind === "managed-module",
|
|
),
|
|
).toEqual([]);
|
|
});
|
|
});
|
|
|
|
it("normalizes MVID casing for node identity while preserving observed values", () => {
|
|
const { memberEvidence, boundaryEvidence } = createManagedInteropEvidence();
|
|
const members = managedMemberInspectionSchema.parse(
|
|
parseEvidence(memberEvidence).normalized_result,
|
|
);
|
|
if (members.module === null)
|
|
throw new Error("Expected fixture module identity");
|
|
const uppercaseMvid = members.module.mvid?.toUpperCase();
|
|
if (uppercaseMvid === undefined || uppercaseMvid === null)
|
|
throw new Error("Expected fixture module MVID");
|
|
const uppercaseMembers = createEvidence(undefined, MANAGED_STATIC_PROVIDER, {
|
|
operation: "inspect_managed_members",
|
|
parameters: {},
|
|
result: {
|
|
...members,
|
|
module: {
|
|
...members.module,
|
|
mvid: uppercaseMvid,
|
|
enc_id: null,
|
|
enc_base_id: null,
|
|
},
|
|
identity_scope: {
|
|
...members.identity_scope,
|
|
requires_mvid: uppercaseMvid,
|
|
},
|
|
},
|
|
rawResult: null,
|
|
limitations: members.limitations,
|
|
});
|
|
const baseline = projectManagedApplicationGraphEvidence({
|
|
managed_members: memberEvidence,
|
|
managed_native_boundaries: boundaryEvidence,
|
|
});
|
|
const uppercase = projectManagedApplicationGraphEvidence({
|
|
managed_members: uppercaseMembers,
|
|
managed_native_boundaries: boundaryEvidence,
|
|
});
|
|
if (!baseline.ok) throw baseline.error;
|
|
if (!uppercase.ok) throw uppercase.error;
|
|
const baselineResult = managedApplicationGraphResultSchema.parse(
|
|
parseEvidence(baseline.value).normalized_result,
|
|
);
|
|
const uppercaseResult = managedApplicationGraphResultSchema.parse(
|
|
parseEvidence(uppercase.value).normalized_result,
|
|
);
|
|
const baselineModule = parseJavaScriptApplicationGraph(
|
|
baselineResult.graph,
|
|
).nodes.find(({ kind }) => kind === "managed-module");
|
|
const uppercaseGraph = parseJavaScriptApplicationGraph(uppercaseResult.graph);
|
|
const uppercaseModule = uppercaseGraph.nodes.find(
|
|
({ kind }) => kind === "managed-module",
|
|
);
|
|
expect(uppercaseGraph.edges).toContainEqual(
|
|
expect.objectContaining({
|
|
relation: "imports",
|
|
source_node_id: uppercaseGraph.nodes.find(
|
|
({ kind }) => kind === "managed-method",
|
|
)?.node_id,
|
|
}),
|
|
);
|
|
expect(uppercaseModule?.node_id).toBe(baselineModule?.node_id);
|
|
expect(uppercaseModule?.observations[0]?.properties.mvid).toBe(uppercaseMvid);
|
|
});
|
|
|
|
describe("managed application graph module identity consistency", () => {
|
|
it("rejects contradictory known module MVIDs across same-artifact inputs", () => {
|
|
const { artifactEvidence, memberEvidence, boundaryEvidence } =
|
|
createManagedInteropEvidence();
|
|
const boundaries = managedNativeBoundaryInspectionSchema.parse(
|
|
parseEvidence(boundaryEvidence).normalized_result,
|
|
);
|
|
const conflictingMvid = "ffffffff-ffff-ffff-ffff-ffffffffffff";
|
|
const conflictingBoundaries = createEvidence(
|
|
undefined,
|
|
MANAGED_STATIC_PROVIDER,
|
|
{
|
|
operation: "inspect_managed_native_boundaries",
|
|
parameters: {},
|
|
result: {
|
|
...boundaries,
|
|
module:
|
|
boundaries.module === null
|
|
? null
|
|
: { ...boundaries.module, mvid: conflictingMvid },
|
|
identity_scope: {
|
|
...boundaries.identity_scope,
|
|
requires_mvid: conflictingMvid,
|
|
},
|
|
},
|
|
rawResult: null,
|
|
limitations: boundaries.limitations,
|
|
},
|
|
);
|
|
|
|
const projected = projectManagedApplicationGraphEvidence({
|
|
managed_artifact: artifactEvidence,
|
|
managed_members: memberEvidence,
|
|
managed_native_boundaries: conflictingBoundaries,
|
|
});
|
|
expect(projected.ok).toBe(false);
|
|
if (projected.ok) throw new Error("conflicting MVIDs were accepted");
|
|
expect(JSON.stringify(projected.error)).toContain(
|
|
"conflicting known module MVIDs or token scopes",
|
|
);
|
|
});
|
|
|
|
it("rejects contradictory known module declaration fields", () => {
|
|
const { artifactEvidence, memberEvidence } = createManagedInteropEvidence();
|
|
const members = managedMemberInspectionSchema.parse(
|
|
parseEvidence(memberEvidence).normalized_result,
|
|
);
|
|
if (members.module === null)
|
|
throw new Error("Expected fixture module identity");
|
|
const conflictingMembers = createEvidence(
|
|
undefined,
|
|
MANAGED_STATIC_PROVIDER,
|
|
{
|
|
operation: "inspect_managed_members",
|
|
parameters: {},
|
|
result: {
|
|
...members,
|
|
module: {
|
|
...members.module,
|
|
generation: members.module.generation + 1,
|
|
},
|
|
},
|
|
rawResult: null,
|
|
limitations: members.limitations,
|
|
},
|
|
);
|
|
|
|
const projected = projectManagedApplicationGraphEvidence({
|
|
managed_artifact: artifactEvidence,
|
|
managed_members: conflictingMembers,
|
|
});
|
|
expect(projected.ok).toBe(false);
|
|
if (projected.ok)
|
|
throw new Error("conflicting module declaration was accepted");
|
|
expect(JSON.stringify(projected.error)).toContain(
|
|
"conflicting module generation values",
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("managed application graph token scope", () => {
|
|
it("checks declared token artifact and MVID scopes without a subject digest", () => {
|
|
const { memberEvidence } = createManagedInteropEvidence();
|
|
const members = managedMemberInspectionSchema.parse(
|
|
parseEvidence(memberEvidence).normalized_result,
|
|
);
|
|
const wrongMvidValue = "ffffffff-ffff-ffff-ffff-ffffffffffff";
|
|
const wrongMvidEvidence = createEvidence(
|
|
undefined,
|
|
MANAGED_STATIC_PROVIDER,
|
|
{
|
|
operation: "inspect_managed_members",
|
|
parameters: {},
|
|
result: {
|
|
...members,
|
|
identity_scope: {
|
|
...members.identity_scope,
|
|
requires_mvid: wrongMvidValue,
|
|
},
|
|
},
|
|
rawResult: null,
|
|
limitations: members.limitations,
|
|
},
|
|
);
|
|
const wrongArtifactEvidence = createEvidence(
|
|
undefined,
|
|
MANAGED_STATIC_PROVIDER,
|
|
{
|
|
operation: "inspect_managed_members",
|
|
parameters: {},
|
|
result: {
|
|
...members,
|
|
identity_scope: {
|
|
...members.identity_scope,
|
|
requires_artifact_sha256: "b".repeat(64),
|
|
},
|
|
},
|
|
rawResult: null,
|
|
limitations: members.limitations,
|
|
},
|
|
);
|
|
|
|
const wrongMvidResult = projectManagedApplicationGraphEvidence({
|
|
managed_members: wrongMvidEvidence,
|
|
});
|
|
expect(wrongMvidResult.ok).toBe(false);
|
|
if (wrongMvidResult.ok)
|
|
throw new Error("mismatched token MVID was accepted");
|
|
expect(JSON.stringify(wrongMvidResult.error)).toContain("token scope MVID");
|
|
|
|
const wrongArtifact = projectManagedApplicationGraphEvidence({
|
|
managed_members: wrongArtifactEvidence,
|
|
});
|
|
expect(wrongArtifact.ok).toBe(false);
|
|
if (wrongArtifact.ok)
|
|
throw new Error("mismatched token artifact digest was accepted");
|
|
expect(JSON.stringify(wrongArtifact.error)).toContain(
|
|
"token scope SHA-256",
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("unknown managed application graph token scope", () => {
|
|
it("keeps absent MVID scope unknown and marks cross-source token joins partial", () => {
|
|
const { memberEvidence, boundaryEvidence } = createManagedInteropEvidence();
|
|
const members = managedMemberInspectionSchema.parse(
|
|
parseEvidence(memberEvidence).normalized_result,
|
|
);
|
|
const boundaries = managedNativeBoundaryInspectionSchema.parse(
|
|
parseEvidence(boundaryEvidence).normalized_result,
|
|
);
|
|
const unknownMembers = createEvidence(undefined, MANAGED_STATIC_PROVIDER, {
|
|
operation: "inspect_managed_members",
|
|
parameters: {},
|
|
result: {
|
|
...members,
|
|
module:
|
|
members.module === null
|
|
? null
|
|
: {
|
|
...members.module,
|
|
mvid: null,
|
|
enc_id: null,
|
|
enc_base_id: null,
|
|
},
|
|
identity_scope: { ...members.identity_scope, requires_mvid: null },
|
|
},
|
|
rawResult: null,
|
|
limitations: members.limitations,
|
|
});
|
|
|
|
const projected = projectManagedApplicationGraphEvidence({
|
|
managed_members: unknownMembers,
|
|
managed_native_boundaries: boundaryEvidence,
|
|
});
|
|
if (!projected.ok) throw projected.error;
|
|
const result = managedApplicationGraphResultSchema.parse(
|
|
parseEvidence(projected.value).normalized_result,
|
|
);
|
|
const graph = parseJavaScriptApplicationGraph(result.graph);
|
|
expect(result.summary.modules).toBe(1);
|
|
expect(result.coverage.status).toBe("partial");
|
|
expect(result.limitations).toContain(
|
|
"Managed boundary tokens were not linked to member nodes because matching module MVID scope was not established.",
|
|
);
|
|
const moduleObservation = graph.nodes.find(
|
|
({ kind }) => kind === "managed-module",
|
|
)?.observations[0];
|
|
expect(moduleObservation?.properties.mvid).toBe(boundaries.module?.mvid);
|
|
expect(moduleObservation?.evidence.extractor.operation).toBe(
|
|
"inspect_managed_native_boundaries",
|
|
);
|
|
const method = graph.nodes.find(
|
|
({ kind, observations }) =>
|
|
kind === "managed-method" &&
|
|
observations[0]?.label === "Fixture.Program.Main",
|
|
);
|
|
expect(method).toBeDefined();
|
|
const importEdge = graph.edges.find(
|
|
({ relation, target_node_id }) =>
|
|
relation === "imports" &&
|
|
graph.nodes.find(({ node_id }) => node_id === target_node_id)?.kind ===
|
|
"managed-pinvoke-import",
|
|
);
|
|
expect(importEdge).toBeDefined();
|
|
expect(
|
|
graph.nodes.find(({ node_id }) => node_id === importEdge?.source_node_id)
|
|
?.kind,
|
|
).toBe("artifact");
|
|
});
|
|
});
|
|
|
|
describe("managed application graph coverage", () => {
|
|
it("preserves partial parser coverage in graph and per-fact coverage", () => {
|
|
const bytes = buildManagedPeFixture();
|
|
const binary = managedPeFixtureTarget(bytes, "/fixture/ManagedInterop.exe");
|
|
const members = inspectManagedMembersBytes(bytes, binary);
|
|
const parserPartialMembers = {
|
|
...members,
|
|
coverage: {
|
|
state: "partial" as const,
|
|
issues: [
|
|
{
|
|
code: "invalid-blob" as const,
|
|
scope: "metadata.#Blob",
|
|
offset: 0x0a00,
|
|
detail: "Blob content leaves #Blob",
|
|
},
|
|
],
|
|
},
|
|
};
|
|
const parserPartialEvidence = createEvidence(
|
|
binary,
|
|
MANAGED_STATIC_PROVIDER,
|
|
{
|
|
operation: "inspect_managed_members",
|
|
parameters: {},
|
|
result: parserPartialMembers,
|
|
rawResult: null,
|
|
limitations: parserPartialMembers.limitations,
|
|
},
|
|
);
|
|
const parserPartialProjection = projectManagedApplicationGraphEvidence({
|
|
managed_members: parserPartialEvidence,
|
|
});
|
|
|
|
if (!parserPartialProjection.ok)
|
|
throw new Error("partial projection failed");
|
|
const parserPartialResult = managedApplicationGraphResultSchema.parse(
|
|
parseEvidence(parserPartialProjection.value).normalized_result,
|
|
);
|
|
expect(parserPartialResult.coverage).toMatchObject({
|
|
status: "partial",
|
|
});
|
|
expect(parserPartialResult.graph.coverage).toEqual({
|
|
status: "partial",
|
|
truncated: false,
|
|
omitted_count: null,
|
|
limits: [],
|
|
});
|
|
});
|
|
});
|