rea-agents 2.0.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +103 -38
- package/bridge/ghidra/ReaGhidraBridge.java +96 -11
- package/dist/application/AndroidApplicationService.js +17 -0
- package/dist/application/AppleApplicationService.js +17 -0
- package/dist/application/ArtifactExtraction.js +1 -1
- package/dist/application/ArtifactInventory/classify.js +42 -0
- package/dist/application/ArtifactInventory/hash.js +43 -0
- package/dist/application/ArtifactInventory/reader.js +41 -0
- package/dist/application/ArtifactInventory/scanCanonical.js +155 -0
- package/dist/application/ArtifactInventory/scanReader.js +124 -0
- package/dist/application/ArtifactInventory/types.js +10 -0
- package/dist/application/ArtifactInventory.js +9 -351
- package/dist/application/AuthorizedArtifactInventory.js +2 -2
- package/dist/application/BinarySession.js +47 -270
- package/dist/application/BinarySessionExecution.js +28 -0
- package/dist/application/BinarySessionOpen.js +39 -0
- package/dist/application/BinarySessionRecords.js +149 -0
- package/dist/application/BinarySessionStatus.js +75 -0
- package/dist/application/CapabilityInventory.js +24 -2
- package/dist/application/ClientRegistrationStatus.js +11 -4
- package/dist/application/CrossVersionInventory.js +8 -2
- package/dist/application/CrossVersionInvestigation.js +1 -23
- package/dist/application/CrossVersionInvestigationCollections.js +23 -0
- package/dist/application/DirectAnalysis.js +47 -44
- package/dist/application/Doctor.js +156 -238
- package/dist/application/DoctorDiagnostics.js +180 -0
- package/dist/application/ElectronBoundaryAnalysis.js +23 -7
- package/dist/application/ElectronBoundaryGraphWindows.js +32 -8
- package/dist/application/EnhancedToolPagination.js +22 -0
- package/dist/application/EnhancedToolTypes.js +4 -0
- package/dist/application/EnhancedTools.js +20 -37
- package/dist/application/InstrumentedJavaScriptReplayHost.js +36 -0
- package/dist/application/InventoryProjectionEvidence.js +41 -0
- package/dist/application/InvestigationProviders.js +12 -0
- package/dist/application/InvestigationWorkspaceStore.js +24 -10
- package/dist/application/JavaScriptArtifactAnalysis.js +45 -6
- package/dist/application/JavaScriptArtifactFiles.js +6 -2
- package/dist/application/JavaScriptArtifactGraphBuilder.js +23 -1
- package/dist/application/JavaScriptArtifactGraphBundlers.js +225 -0
- package/dist/application/JavaScriptArtifactGraphContext.js +37 -36
- package/dist/application/JavaScriptArtifactGraphDocuments.js +27 -4
- package/dist/application/JavaScriptArtifactGraphFindings.js +54 -8
- package/dist/application/JavaScriptArtifactGraphStructure.js +29 -101
- package/dist/application/JavaScriptArtifactPathResolution.js +269 -0
- package/dist/application/JavaScriptArtifactReconstruction.js +1 -1
- package/dist/application/JavaScriptJsonModules.js +39 -0
- package/dist/application/JavaScriptModuleRelationships.js +262 -0
- package/dist/application/JavaScriptReplayPermission.js +16 -0
- package/dist/application/JavaScriptReplayService.js +182 -156
- package/dist/application/LinuxHopper.js +10 -0
- package/dist/application/MacHopper.js +22 -11
- package/dist/application/NodeRuntimeCharacterizationService.js +196 -0
- package/dist/application/PermissionAuthority.js +106 -63
- package/dist/application/ProcessCaptureCapability.js +1 -1
- package/dist/application/ProcessCapturePermission.js +13 -0
- package/dist/application/ProcessCli.js +2 -12
- package/dist/application/ProcessHarness.js +1 -1
- package/dist/application/ProcessPairedExperiment.js +72 -0
- package/dist/application/ProjectPermissionStore.js +48 -9
- package/dist/application/RealHopperAssertions.js +76 -0
- package/dist/application/ReconstructionCoverageService.js +69 -0
- package/dist/application/ReconstructionCoverageWorkspaceStore.js +31 -0
- package/dist/application/RuntimeExecutableDiagnostics.js +172 -0
- package/dist/application/Setup.js +148 -260
- package/dist/application/SetupClientConfiguration.js +224 -0
- package/dist/application/SetupClients.js +24 -2
- package/dist/application/SetupPlan.js +124 -12
- package/dist/application/SetupSkill.js +54 -36
- package/dist/application/SupportedClients.js +1 -0
- package/dist/application/Uninstall.js +12 -3
- package/dist/application/Upgrade.js +16 -1
- package/dist/application/WindowsCapabilities.js +86 -0
- package/dist/artifacts/AsarArtifactReader.js +11 -0
- package/dist/browser/BrowserProcessStartup.js +88 -0
- package/dist/browser/CdpCaptureDocuments.js +12 -8
- package/dist/browser/CdpCaptureEventBodyShapes.js +75 -0
- package/dist/browser/CdpCaptureEventHandlers.js +336 -0
- package/dist/browser/CdpCaptureEventHelpers.js +71 -0
- package/dist/browser/CdpCaptureEventState.js +1 -0
- package/dist/browser/CdpCaptureEventTypes.js +1 -0
- package/dist/browser/CdpCaptureEvents.js +29 -496
- package/dist/browser/CdpObservationSession.js +51 -8
- package/dist/browser/CdpPageCapture.js +12 -133
- package/dist/browser/CdpPageCaptureScripts.js +97 -0
- package/dist/browser/CdpPageCaptureWorkers.js +46 -0
- package/dist/browser/CdpWebMcpDiscovery.js +38 -14
- package/dist/browser/PngVisualDiff.js +9 -2
- package/dist/catalogIdentity.js +4 -0
- package/dist/cli/artifactCommands.js +82 -0
- package/dist/cli/coreAnalysisCommands.js +232 -0
- package/dist/cli/managedCommands.js +397 -0
- package/dist/cli/managedProjectGraphCommand.js +24 -0
- package/dist/cli/options.js +9 -0
- package/dist/cli/setupCommands.js +113 -0
- package/dist/cli/types.js +1 -0
- package/dist/cli/utilityCommands.js +122 -0
- package/dist/cli.js +10 -768
- package/dist/cliApplicationCommands.js +118 -4
- package/dist/cliBrowserAdvancedCommands.js +73 -16
- package/dist/cliBrowserCommands.js +39 -115
- package/dist/cliCommandNames.js +4 -0
- package/dist/cliElectronCommands.js +33 -62
- package/dist/cliEvidenceCommands.js +13 -2
- package/dist/cliInvestigationCommands.js +53 -10
- package/dist/cliObservationOptions.js +137 -0
- package/dist/cliPolicyCommands.js +80 -46
- package/dist/cliSetup.js +306 -0
- package/dist/config/environment.js +107 -0
- package/dist/config/parseConfig.js +228 -0
- package/dist/config/parsers.js +68 -0
- package/dist/config/permissions.js +30 -0
- package/dist/config/types.js +1 -0
- package/dist/config.js +1 -375
- package/dist/contracts/applicationToolContracts.js +134 -0
- package/dist/contracts/electronToolContracts.js +51 -3
- package/dist/contracts/managedToolContracts.js +8 -3
- package/dist/contracts/managedWorkflowToolContracts.js +3 -3
- package/dist/contracts/providerSelection.js +2 -0
- package/dist/contracts/sessionStatusContract.js +26 -0
- package/dist/contracts/toolContractTypes.js +12 -1
- package/dist/contracts/toolContracts.js +5 -12
- package/dist/contracts/toolEffects.js +14 -0
- package/dist/contracts/toolOutputSchemaGroups.js +274 -0
- package/dist/contracts/toolOutputSchemaPrimitives.js +328 -0
- package/dist/contracts/toolOutputSchemas.js +2 -550
- package/dist/domain/analysisErrorPresentation.js +234 -0
- package/dist/domain/analysisErrorProjection.js +284 -0
- package/dist/domain/androidApplication.js +206 -0
- package/dist/domain/appleApplication.js +221 -0
- package/dist/domain/artifactComparison.js +34 -15
- package/dist/domain/binaryTarget.js +87 -37
- package/dist/domain/boundedCartesianProjection.js +15 -0
- package/dist/domain/browserObservation.js +1 -285
- package/dist/domain/browserObservationSchemas.js +286 -0
- package/dist/domain/electronStaticAnalysisBrowser.js +14 -2
- package/dist/domain/errors.js +4 -486
- package/dist/domain/functionComparison.js +4 -165
- package/dist/domain/functionComparisonDimensions.js +164 -0
- package/dist/domain/javascriptApplicationVersionItems.js +18 -6
- package/dist/domain/javascriptApplicationVersionKeys.js +8 -8
- package/dist/domain/javascriptExportInstrumentation.js +97 -0
- package/dist/domain/javascriptFeatureTraversal.js +19 -7
- package/dist/domain/javascriptRuntimeStaticCandidates.js +3 -1
- package/dist/domain/javascriptSemanticAnalysis.js +386 -0
- package/dist/domain/javascriptSemanticIr.js +30 -0
- package/dist/domain/javascriptSemanticProjection.js +366 -0
- package/dist/domain/javascriptSemanticState.js +40 -0
- package/dist/domain/javascriptSemanticTraversal.js +22 -0
- package/dist/domain/javascriptSemanticValues.js +352 -0
- package/dist/domain/javascriptStaticAnalysis.js +5 -221
- package/dist/domain/javascriptStaticAnalysisBundler.js +209 -0
- package/dist/domain/javascriptStaticAnalysisCalls.js +180 -0
- package/dist/domain/javascriptStaticAnalysisHelpers.js +71 -2
- package/dist/domain/knownPageCoverage.js +21 -0
- package/dist/domain/managedApplicationGraph.js +14 -364
- package/dist/domain/managedApplicationGraphCoverage.js +170 -0
- package/dist/domain/managedApplicationGraphNodeCoverage.js +6 -0
- package/dist/domain/managedApplicationGraphNodes.js +336 -0
- package/dist/domain/managedArtifact.js +16 -8
- package/dist/domain/managedMemberComparison.js +37 -391
- package/dist/domain/managedMemberComparisonCoverage.js +72 -0
- package/dist/domain/managedMemberComparisonMatch.js +356 -0
- package/dist/domain/managedNativeVerification.js +27 -389
- package/dist/domain/managedNativeVerificationMatch.js +272 -0
- package/dist/domain/managedNativeVerificationSchemas.js +141 -0
- package/dist/domain/managedReconstruction.js +82 -69
- package/dist/domain/managedRuntimeCorrelation.js +12 -3
- package/dist/domain/nodeRuntimeCharacterization.js +66 -0
- package/dist/domain/permissionPolicy.js +2 -0
- package/dist/domain/processComparison.js +19 -0
- package/dist/domain/processPairedExperiment.js +128 -0
- package/dist/domain/reconstructionCoverage.js +387 -0
- package/dist/domain/reconstructionCoverageEvaluation.js +212 -0
- package/dist/domain/reconstructionVerificationSchemas.js +8 -0
- package/dist/domain/replayMachine.js +316 -0
- package/dist/domain/replayMachineRuntime.js +215 -0
- package/dist/domain/runtimeCharacterization.js +85 -0
- package/dist/domain/runtimeIdentification.js +210 -0
- package/dist/domain/webBundleAnalyzer.js +3 -409
- package/dist/domain/webBundleAnalyzerAst.js +77 -0
- package/dist/domain/webBundleAnalyzerInspection.js +307 -0
- package/dist/domain/webBundleAnalyzerResult.js +120 -0
- package/dist/dotnet/ManagedArtifactInspector.js +50 -29
- package/dist/dotnet/ManagedMemberInspector.js +51 -785
- package/dist/dotnet/ManagedMemberInspectorCore.js +297 -0
- package/dist/dotnet/ManagedMemberInstructionDecoder.js +427 -0
- package/dist/dotnet/ManagedMemberRows.js +120 -0
- package/dist/dotnet/ManagedMetadataInventory.js +42 -306
- package/dist/dotnet/ManagedMetadataInventoryRows.js +292 -0
- package/dist/dotnet/ManagedMetadataLayout.js +48 -111
- package/dist/dotnet/ManagedMetadataRowSizes.js +54 -0
- package/dist/dotnet/ManagedMethodBodyReader.js +143 -0
- package/dist/dotnet/ManagedNativeBoundaryHelpers.js +311 -0
- package/dist/dotnet/ManagedNativeBoundaryInspector.js +102 -350
- package/dist/dotnet/ManagedPeReader.js +59 -28
- package/dist/evaluation/CodexAgentEval.js +132 -0
- package/dist/generatedPackageMetadata.js +2 -2
- package/dist/ghidra/GhidraClient.js +76 -91
- package/dist/ghidra/GhidraClientStartup.js +29 -0
- package/dist/ghidra/GhidraClientWire.js +34 -0
- package/dist/ghidra/GhidraDefaults.js +1 -1
- package/dist/ghidra/GhidraDiagnostics.js +6 -1
- package/dist/ghidra/GhidraInstallation.js +20 -15
- package/dist/ghidra/GhidraLauncher.js +93 -29
- package/dist/ghidra/GhidraProvider.js +61 -161
- package/dist/ghidra/GhidraProviderCapabilities.js +173 -0
- package/dist/ghidra/GhidraSessionValues.js +2 -0
- package/dist/ghidra/GhidraSocketConnection.js +44 -7
- package/dist/ghidra/GhidraTargetSnapshot.js +30 -0
- package/dist/ghidra/GhidraTransport.js +71 -0
- package/dist/identity.js +4 -2
- package/dist/main/messages.js +5 -0
- package/dist/main/reload.js +49 -0
- package/dist/main/shutdown.js +25 -0
- package/dist/main/startup.js +14 -0
- package/dist/main/state.js +26 -0
- package/dist/main/transport.js +61 -0
- package/dist/main/types.js +1 -0
- package/dist/main.js +35 -146
- package/dist/process/PrivateRuntimeRoot.js +3 -2
- package/dist/process/ProcessOwnership.js +35 -0
- package/dist/process/ProviderProcess.js +2 -0
- package/dist/replay/JavaScriptReplayWorker.js +64 -50
- package/dist/replay/LinuxJavaScriptReplayRunner.js +173 -390
- package/dist/replay/LinuxJavaScriptReplaySandbox.js +140 -0
- package/dist/replay/ReplayOutcome.js +95 -0
- package/dist/replay/ReplayProcessLifecycle.js +71 -0
- package/dist/server/ProcessCaptureElicitation.js +157 -0
- package/dist/server/createServer.js +124 -56
- package/dist/server/javascriptApplicationResult.js +85 -0
- package/dist/server/registerApplicationTools/characterization.js +57 -0
- package/dist/server/registerApplicationTools/compareVersions.js +34 -0
- package/dist/server/registerApplicationTools/controlledReplay.js +38 -0
- package/dist/server/registerApplicationTools/coverage.js +84 -0
- package/dist/server/registerApplicationTools/helpers.js +42 -0
- package/dist/server/registerApplicationTools/traceFeature.js +26 -0
- package/dist/server/registerApplicationTools/types.js +1 -0
- package/dist/server/registerApplicationTools.js +10 -112
- package/dist/server/registerBrowserTools.js +59 -83
- package/dist/server/registerElectronTools.js +48 -49
- package/dist/server/registerEnhancedTools.js +34 -42
- package/dist/server/registerEvidenceResources.js +56 -0
- package/dist/server/registerInvestigationTools/helpers.js +74 -0
- package/dist/server/registerInvestigationTools/types.js +1 -0
- package/dist/server/registerInvestigationTools.js +83 -116
- package/dist/server/registerJavaScriptApplicationGraphResource.js +69 -0
- package/dist/server/registerManagedTools.js +18 -1
- package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +65 -0
- package/dist/server/registerManagedWorkflowTools/contract.js +8 -0
- package/dist/server/registerManagedWorkflowTools/evidence.js +43 -0
- package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +39 -0
- package/dist/server/registerManagedWorkflowTools/planManagedRuntimeCorrelation.js +39 -0
- package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +52 -0
- package/dist/server/registerManagedWorkflowTools/types.js +1 -0
- package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +75 -0
- package/dist/server/registerManagedWorkflowTools.js +10 -274
- package/dist/server/registerOfficialTools.js +73 -59
- package/dist/server/registerSessionRecordTools.js +137 -0
- package/dist/server/registerSessionStatusTool.js +97 -26
- package/dist/server/registerSessionTools.js +60 -164
- package/dist/server/sessionAvailabilityPolicy.js +10 -0
- package/dist/server/toolRegistrationOptions.js +101 -3
- package/dist/server/toolResult.js +15 -4
- package/package.json +11 -11
- package/skills/reverse-engineer-anything/SKILL.md +76 -0
- package/skills/reverse-engineer-anything/references/controlled-replay.md +12 -0
- package/skills/reverse-engineer-anything/references/evidence-workflows.md +33 -0
- package/skills/reverse-engineer-anything/references/javascript-applications.md +25 -0
- package/skills/reverse-engineer-anything/references/native-and-artifacts.md +36 -0
- package/skills/reverse-engineer-anything/references/runtime-observation.md +24 -0
- package/scripts/prepare-node-pty.mjs +0 -35
- package/scripts/rebuild-native.mjs +0 -22
- package/skills/rea-analysis/SKILL.md +0 -222
|
@@ -1,17 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { commentProjection, combineCoverage, functionMatch, identityProjection, isAutoName, normalizeCfg, project, referenceKindProjection, referenceProjection, sorted, stringAndNameProjection, } from "./functionComparisonNormalization.js";
|
|
1
|
+
import { parseFunctionEvidence } from "./functionDossierEvidence.js";
|
|
2
|
+
import { functionMatch } from "./functionComparisonNormalization.js";
|
|
4
3
|
import { functionComparisonResultSchema, } from "./functionComparisonSchemas.js";
|
|
5
|
-
import {
|
|
4
|
+
import { overallStatus, summarize, canonicalJson, } from "./functionComparisonResults.js";
|
|
5
|
+
import { compareDimensions } from "./functionComparisonDimensions.js";
|
|
6
6
|
export { functionComparisonInputSchema, functionComparisonResultSchema, } from "./functionComparisonSchemas.js";
|
|
7
|
-
const unresolvedDimension = (...[dimension, status, links, leftCount, rightCount, limitations]) => buildUnresolvedDimension({
|
|
8
|
-
dimension,
|
|
9
|
-
status,
|
|
10
|
-
links,
|
|
11
|
-
leftCount,
|
|
12
|
-
rightCount,
|
|
13
|
-
limitations,
|
|
14
|
-
});
|
|
15
7
|
/** Compare two explicit function Evidence page sets without fuzzy matching. */
|
|
16
8
|
export const compareFunctions = (leftInput, rightInput, offset, limit) => {
|
|
17
9
|
const left = parseFunctionEvidence(leftInput);
|
|
@@ -52,156 +44,3 @@ export const compareFunctions = (leftInput, rightInput, offset, limit) => {
|
|
|
52
44
|
].sort((a, b) => a.localeCompare(b)),
|
|
53
45
|
});
|
|
54
46
|
};
|
|
55
|
-
const compareDimensions = (left, right, links, providersDiffer) => [
|
|
56
|
-
compareIdentity(left, right, links, providersDiffer),
|
|
57
|
-
compareText("pseudocode", left.pseudocode.text, right.pseudocode.text, left.pseudocode.complete, right.pseudocode.complete, links, providersDiffer),
|
|
58
|
-
compareText("assembly", left.collections.assembly.items.join("\n"), right.collections.assembly.items.join("\n"), left.collections.assembly.complete, right.collections.assembly.complete, links, providersDiffer, left.collections.assembly.truncated || right.collections.assembly.truncated, "Assembly is opaque provider text; relocation normalization is unavailable."),
|
|
59
|
-
compareComments(left, right, links, providersDiffer),
|
|
60
|
-
compareCalls(left, right, links, providersDiffer),
|
|
61
|
-
compareReferences(left, right, links, providersDiffer),
|
|
62
|
-
compareStringsAndNames(left, right, links, providersDiffer),
|
|
63
|
-
compareCfg(left, right, links, providersDiffer),
|
|
64
|
-
];
|
|
65
|
-
const compareText = (...[dimension, left, right, leftComplete, rightComplete, links, providersDiffer, explicitTruncation, limitation,]) => {
|
|
66
|
-
const truncated = explicitTruncation ?? (!leftComplete || !rightComplete);
|
|
67
|
-
if (!leftComplete || !rightComplete || providersDiffer)
|
|
68
|
-
return unresolvedDimension(dimension, truncated ? "truncated" : "unknown", links, left.length, right.length, [
|
|
69
|
-
...(limitation === undefined ? [] : [limitation]),
|
|
70
|
-
...(providersDiffer
|
|
71
|
-
? ["Exact text comparison requires one provider identity."]
|
|
72
|
-
: []),
|
|
73
|
-
]);
|
|
74
|
-
const changes = diffLines(left, right, {
|
|
75
|
-
timeout: 100,
|
|
76
|
-
maxEditLength: 10_000,
|
|
77
|
-
});
|
|
78
|
-
if (changes === undefined)
|
|
79
|
-
return unresolvedDimension(dimension, "unknown", links, left.length, right.length, ["Bounded line diff exceeded its time or edit-distance limit."]);
|
|
80
|
-
const delta = changes.reduce((summary, change) => ({
|
|
81
|
-
added_lines: summary.added_lines + (change.added ? (change.count ?? 0) : 0),
|
|
82
|
-
removed_lines: summary.removed_lines + (change.removed ? (change.count ?? 0) : 0),
|
|
83
|
-
hunks: summary.hunks + (change.added || change.removed ? 1 : 0),
|
|
84
|
-
}), { added_lines: 0, removed_lines: 0, hunks: 0 });
|
|
85
|
-
return dimensionResult({
|
|
86
|
-
dimension,
|
|
87
|
-
status: delta.hunks === 0 ? "unchanged" : "changed",
|
|
88
|
-
left,
|
|
89
|
-
right,
|
|
90
|
-
links,
|
|
91
|
-
providersDiffer,
|
|
92
|
-
leftCount: [...left].length,
|
|
93
|
-
rightCount: [...right].length,
|
|
94
|
-
textDelta: delta,
|
|
95
|
-
limitations: limitation === undefined ? [] : [limitation],
|
|
96
|
-
});
|
|
97
|
-
};
|
|
98
|
-
const compareCollections = (...[dimension, left, right, leftCoverage, rightCoverage, links, providersDiffer,]) => {
|
|
99
|
-
if (!leftCoverage.complete || !rightCoverage.complete)
|
|
100
|
-
return unresolvedDimension(dimension, leftCoverage.truncated || rightCoverage.truncated
|
|
101
|
-
? "truncated"
|
|
102
|
-
: "unknown", links, left.length, right.length, []);
|
|
103
|
-
return compareValues(dimension, sorted(left), sorted(right), links, true, true, providersDiffer);
|
|
104
|
-
};
|
|
105
|
-
const compareComments = (left, right, links, providersDiffer) => {
|
|
106
|
-
const leftValues = commentProjection(left);
|
|
107
|
-
const rightValues = commentProjection(right);
|
|
108
|
-
if (leftValues === null || rightValues === null)
|
|
109
|
-
return unresolvedDimension("comments", "unknown", links, left.collections.comments.items.length, right.collections.comments.items.length, ["Comment locations could not be normalized relative to the function."]);
|
|
110
|
-
return compareCollections("comments", leftValues, rightValues, left.collections.comments, right.collections.comments, links, providersDiffer);
|
|
111
|
-
};
|
|
112
|
-
const compareStringsAndNames = (left, right, links, providersDiffer) => {
|
|
113
|
-
const leftValues = stringAndNameProjection(left);
|
|
114
|
-
const rightValues = stringAndNameProjection(right);
|
|
115
|
-
if (leftValues === null || rightValues === null)
|
|
116
|
-
return unresolvedDimension("strings_names", "unknown", links, null, null, [
|
|
117
|
-
"Reference source locations could not be normalized to function offsets.",
|
|
118
|
-
]);
|
|
119
|
-
return compareCollections("strings_names", leftValues, rightValues, combineCoverage(left.collections.referenced_strings, left.collections.referenced_names), combineCoverage(right.collections.referenced_strings, right.collections.referenced_names), links, providersDiffer);
|
|
120
|
-
};
|
|
121
|
-
const compareReferences = (left, right, links, providersDiffer) => {
|
|
122
|
-
const leftCoverage = combineCoverage(left.collections.incoming_references, left.collections.outgoing_references);
|
|
123
|
-
const rightCoverage = combineCoverage(right.collections.incoming_references, right.collections.outgoing_references);
|
|
124
|
-
if (!leftCoverage.complete || !rightCoverage.complete)
|
|
125
|
-
return unresolvedDimension("references", leftCoverage.truncated || rightCoverage.truncated
|
|
126
|
-
? "truncated"
|
|
127
|
-
: "unknown", links, leftCoverage.items.length, rightCoverage.items.length, []);
|
|
128
|
-
const leftProjection = referenceProjection(left);
|
|
129
|
-
const rightProjection = referenceProjection(right);
|
|
130
|
-
if (leftProjection.length === 0 && rightProjection.length === 0)
|
|
131
|
-
return compareValues("references", leftProjection, rightProjection, links, true, true, providersDiffer);
|
|
132
|
-
if (canonicalJson(leftProjection) !== canonicalJson(rightProjection))
|
|
133
|
-
return dimensionResult({
|
|
134
|
-
dimension: "references",
|
|
135
|
-
status: "changed",
|
|
136
|
-
left: leftProjection,
|
|
137
|
-
right: rightProjection,
|
|
138
|
-
links,
|
|
139
|
-
providersDiffer,
|
|
140
|
-
leftCount: leftProjection.length,
|
|
141
|
-
rightCount: rightProjection.length,
|
|
142
|
-
textDelta: null,
|
|
143
|
-
limitations: [
|
|
144
|
-
"Reference endpoints differ independently of provider reference-kind metadata.",
|
|
145
|
-
],
|
|
146
|
-
});
|
|
147
|
-
const leftKinds = referenceKindProjection(left);
|
|
148
|
-
const rightKinds = referenceKindProjection(right);
|
|
149
|
-
if (leftKinds !== null && rightKinds !== null)
|
|
150
|
-
return compareValues("references", leftKinds, rightKinds, links, true, true, providersDiffer);
|
|
151
|
-
return unresolvedDimension("references", "unknown", links, leftProjection.length, rightProjection.length, [
|
|
152
|
-
"At least one provider did not expose reference kinds, so equal endpoints do not prove equal edge semantics.",
|
|
153
|
-
]);
|
|
154
|
-
};
|
|
155
|
-
const compareIdentity = (left, right, links, providersDiffer) => {
|
|
156
|
-
if (isAutoName(left.procedure.name) || isAutoName(right.procedure.name))
|
|
157
|
-
return unresolvedDimension("identity", "unknown", links, null, null, [
|
|
158
|
-
"Address-derived function names are not stable cross-version identity.",
|
|
159
|
-
]);
|
|
160
|
-
return compareValues("identity", identityProjection(left), identityProjection(right), links, true, true, providersDiffer);
|
|
161
|
-
};
|
|
162
|
-
const compareCalls = (left, right, links, providersDiffer) => {
|
|
163
|
-
const leftValues = callProjection(left);
|
|
164
|
-
const rightValues = callProjection(right);
|
|
165
|
-
if ([...leftValues, ...rightValues].some(({ name }) => isAutoName(name)))
|
|
166
|
-
return unresolvedDimension("calls", "unknown", links, leftValues.length, rightValues.length, ["Address-derived callee or caller names cannot be matched safely."]);
|
|
167
|
-
return compareCollections("calls", leftValues, rightValues, combineCoverage(left.collections.callers, left.collections.callees), combineCoverage(right.collections.callers, right.collections.callees), links, providersDiffer);
|
|
168
|
-
};
|
|
169
|
-
const callProjection = (snapshot) => [
|
|
170
|
-
...project(snapshot.collections.callers, ({ name }) => ({
|
|
171
|
-
direction: "in",
|
|
172
|
-
name,
|
|
173
|
-
})),
|
|
174
|
-
...project(snapshot.collections.callees, ({ name }) => ({
|
|
175
|
-
direction: "out",
|
|
176
|
-
name,
|
|
177
|
-
})),
|
|
178
|
-
];
|
|
179
|
-
const compareCfg = (left, right, links, providersDiffer) => {
|
|
180
|
-
const leftBlocks = left.collections.basic_blocks;
|
|
181
|
-
const rightBlocks = right.collections.basic_blocks;
|
|
182
|
-
if (!leftBlocks.complete || !rightBlocks.complete)
|
|
183
|
-
return unresolvedDimension("cfg", leftBlocks.truncated || rightBlocks.truncated ? "truncated" : "unknown", links, leftBlocks.items.length, rightBlocks.items.length, []);
|
|
184
|
-
const leftGraph = normalizeCfg(leftBlocks.items);
|
|
185
|
-
const rightGraph = normalizeCfg(rightBlocks.items);
|
|
186
|
-
if (leftGraph === null || rightGraph === null)
|
|
187
|
-
return unresolvedDimension("cfg", "unknown", links, leftBlocks.items.length, rightBlocks.items.length, ["CFG addresses could not be normalized to local block indices."]);
|
|
188
|
-
return compareValues("cfg", leftGraph, rightGraph, links, true, true, providersDiffer);
|
|
189
|
-
};
|
|
190
|
-
const compareValues = (...[dimension, left, right, links, leftComplete, rightComplete, providersDiffer,]) => {
|
|
191
|
-
if (!leftComplete || !rightComplete)
|
|
192
|
-
return unresolvedDimension(dimension, "unknown", links, null, null, []);
|
|
193
|
-
const leftJson = canonicalJson(left);
|
|
194
|
-
const rightJson = canonicalJson(right);
|
|
195
|
-
return dimensionResult({
|
|
196
|
-
dimension,
|
|
197
|
-
status: leftJson === rightJson ? "unchanged" : "changed",
|
|
198
|
-
left,
|
|
199
|
-
right,
|
|
200
|
-
links,
|
|
201
|
-
providersDiffer,
|
|
202
|
-
leftCount: Array.isArray(left) ? left.length : null,
|
|
203
|
-
rightCount: Array.isArray(right) ? right.length : null,
|
|
204
|
-
textDelta: null,
|
|
205
|
-
limitations: [],
|
|
206
|
-
});
|
|
207
|
-
};
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { diffLines } from "diff";
|
|
2
|
+
import { commentProjection, combineCoverage, identityProjection, isAutoName, normalizeCfg, project, referenceKindProjection, referenceProjection, sorted, stringAndNameProjection, } from "./functionComparisonNormalization.js";
|
|
3
|
+
import { canonicalJson, dimensionResult, unresolvedDimension as buildUnresolvedDimension, } from "./functionComparisonResults.js";
|
|
4
|
+
const unresolvedDimension = (...[dimension, status, links, leftCount, rightCount, limitations]) => buildUnresolvedDimension({
|
|
5
|
+
dimension,
|
|
6
|
+
status,
|
|
7
|
+
links,
|
|
8
|
+
leftCount,
|
|
9
|
+
rightCount,
|
|
10
|
+
limitations,
|
|
11
|
+
});
|
|
12
|
+
export const compareDimensions = (left, right, links, providersDiffer) => [
|
|
13
|
+
compareIdentity(left, right, links, providersDiffer),
|
|
14
|
+
compareText("pseudocode", left.pseudocode.text, right.pseudocode.text, left.pseudocode.complete, right.pseudocode.complete, links, providersDiffer),
|
|
15
|
+
compareText("assembly", left.collections.assembly.items.join("\n"), right.collections.assembly.items.join("\n"), left.collections.assembly.complete, right.collections.assembly.complete, links, providersDiffer, left.collections.assembly.truncated || right.collections.assembly.truncated, "Assembly is opaque provider text; relocation normalization is unavailable."),
|
|
16
|
+
compareComments(left, right, links, providersDiffer),
|
|
17
|
+
compareCalls(left, right, links, providersDiffer),
|
|
18
|
+
compareReferences(left, right, links, providersDiffer),
|
|
19
|
+
compareStringsAndNames(left, right, links, providersDiffer),
|
|
20
|
+
compareCfg(left, right, links, providersDiffer),
|
|
21
|
+
];
|
|
22
|
+
const compareText = (...[dimension, left, right, leftComplete, rightComplete, links, providersDiffer, explicitTruncation, limitation,]) => {
|
|
23
|
+
const truncated = explicitTruncation ?? (!leftComplete || !rightComplete);
|
|
24
|
+
if (!leftComplete || !rightComplete || providersDiffer)
|
|
25
|
+
return unresolvedDimension(dimension, truncated ? "truncated" : "unknown", links, left.length, right.length, [
|
|
26
|
+
...(limitation === undefined ? [] : [limitation]),
|
|
27
|
+
...(providersDiffer
|
|
28
|
+
? ["Exact text comparison requires one provider identity."]
|
|
29
|
+
: []),
|
|
30
|
+
]);
|
|
31
|
+
const changes = diffLines(left, right, {
|
|
32
|
+
timeout: 100,
|
|
33
|
+
maxEditLength: 10_000,
|
|
34
|
+
});
|
|
35
|
+
if (changes === undefined)
|
|
36
|
+
return unresolvedDimension(dimension, "unknown", links, left.length, right.length, ["Bounded line diff exceeded its time or edit-distance limit."]);
|
|
37
|
+
const delta = changes.reduce((summary, change) => ({
|
|
38
|
+
added_lines: summary.added_lines + (change.added ? (change.count ?? 0) : 0),
|
|
39
|
+
removed_lines: summary.removed_lines + (change.removed ? (change.count ?? 0) : 0),
|
|
40
|
+
hunks: summary.hunks + (change.added || change.removed ? 1 : 0),
|
|
41
|
+
}), { added_lines: 0, removed_lines: 0, hunks: 0 });
|
|
42
|
+
return dimensionResult({
|
|
43
|
+
dimension,
|
|
44
|
+
status: delta.hunks === 0 ? "unchanged" : "changed",
|
|
45
|
+
left,
|
|
46
|
+
right,
|
|
47
|
+
links,
|
|
48
|
+
providersDiffer,
|
|
49
|
+
leftCount: [...left].length,
|
|
50
|
+
rightCount: [...right].length,
|
|
51
|
+
textDelta: delta,
|
|
52
|
+
limitations: limitation === undefined ? [] : [limitation],
|
|
53
|
+
});
|
|
54
|
+
};
|
|
55
|
+
const compareCollections = (...[dimension, left, right, leftCoverage, rightCoverage, links, providersDiffer,]) => {
|
|
56
|
+
if (!leftCoverage.complete || !rightCoverage.complete)
|
|
57
|
+
return unresolvedDimension(dimension, leftCoverage.truncated || rightCoverage.truncated
|
|
58
|
+
? "truncated"
|
|
59
|
+
: "unknown", links, left.length, right.length, []);
|
|
60
|
+
return compareValues(dimension, sorted(left), sorted(right), links, true, true, providersDiffer);
|
|
61
|
+
};
|
|
62
|
+
const compareComments = (left, right, links, providersDiffer) => {
|
|
63
|
+
const leftValues = commentProjection(left);
|
|
64
|
+
const rightValues = commentProjection(right);
|
|
65
|
+
if (leftValues === null || rightValues === null)
|
|
66
|
+
return unresolvedDimension("comments", "unknown", links, left.collections.comments.items.length, right.collections.comments.items.length, ["Comment locations could not be normalized relative to the function."]);
|
|
67
|
+
return compareCollections("comments", leftValues, rightValues, left.collections.comments, right.collections.comments, links, providersDiffer);
|
|
68
|
+
};
|
|
69
|
+
const compareStringsAndNames = (left, right, links, providersDiffer) => {
|
|
70
|
+
const leftValues = stringAndNameProjection(left);
|
|
71
|
+
const rightValues = stringAndNameProjection(right);
|
|
72
|
+
if (leftValues === null || rightValues === null)
|
|
73
|
+
return unresolvedDimension("strings_names", "unknown", links, null, null, [
|
|
74
|
+
"Reference source locations could not be normalized to function offsets.",
|
|
75
|
+
]);
|
|
76
|
+
return compareCollections("strings_names", leftValues, rightValues, combineCoverage(left.collections.referenced_strings, left.collections.referenced_names), combineCoverage(right.collections.referenced_strings, right.collections.referenced_names), links, providersDiffer);
|
|
77
|
+
};
|
|
78
|
+
const compareReferences = (left, right, links, providersDiffer) => {
|
|
79
|
+
const leftCoverage = combineCoverage(left.collections.incoming_references, left.collections.outgoing_references);
|
|
80
|
+
const rightCoverage = combineCoverage(right.collections.incoming_references, right.collections.outgoing_references);
|
|
81
|
+
if (!leftCoverage.complete || !rightCoverage.complete)
|
|
82
|
+
return unresolvedDimension("references", leftCoverage.truncated || rightCoverage.truncated
|
|
83
|
+
? "truncated"
|
|
84
|
+
: "unknown", links, leftCoverage.items.length, rightCoverage.items.length, []);
|
|
85
|
+
const leftProjection = referenceProjection(left);
|
|
86
|
+
const rightProjection = referenceProjection(right);
|
|
87
|
+
if (leftProjection.length === 0 && rightProjection.length === 0)
|
|
88
|
+
return compareValues("references", leftProjection, rightProjection, links, true, true, providersDiffer);
|
|
89
|
+
if (canonicalJson(leftProjection) !== canonicalJson(rightProjection))
|
|
90
|
+
return dimensionResult({
|
|
91
|
+
dimension: "references",
|
|
92
|
+
status: "changed",
|
|
93
|
+
left: leftProjection,
|
|
94
|
+
right: rightProjection,
|
|
95
|
+
links,
|
|
96
|
+
providersDiffer,
|
|
97
|
+
leftCount: leftProjection.length,
|
|
98
|
+
rightCount: rightProjection.length,
|
|
99
|
+
textDelta: null,
|
|
100
|
+
limitations: [
|
|
101
|
+
"Reference endpoints differ independently of provider reference-kind metadata.",
|
|
102
|
+
],
|
|
103
|
+
});
|
|
104
|
+
const leftKinds = referenceKindProjection(left);
|
|
105
|
+
const rightKinds = referenceKindProjection(right);
|
|
106
|
+
if (leftKinds !== null && rightKinds !== null)
|
|
107
|
+
return compareValues("references", leftKinds, rightKinds, links, true, true, providersDiffer);
|
|
108
|
+
return unresolvedDimension("references", "unknown", links, leftProjection.length, rightProjection.length, [
|
|
109
|
+
"At least one provider did not expose reference kinds, so equal endpoints do not prove equal edge semantics.",
|
|
110
|
+
]);
|
|
111
|
+
};
|
|
112
|
+
const compareIdentity = (left, right, links, providersDiffer) => {
|
|
113
|
+
if (isAutoName(left.procedure.name) || isAutoName(right.procedure.name))
|
|
114
|
+
return unresolvedDimension("identity", "unknown", links, null, null, [
|
|
115
|
+
"Address-derived function names are not stable cross-version identity.",
|
|
116
|
+
]);
|
|
117
|
+
return compareValues("identity", identityProjection(left), identityProjection(right), links, true, true, providersDiffer);
|
|
118
|
+
};
|
|
119
|
+
const compareCalls = (left, right, links, providersDiffer) => {
|
|
120
|
+
const leftValues = callProjection(left);
|
|
121
|
+
const rightValues = callProjection(right);
|
|
122
|
+
if ([...leftValues, ...rightValues].some(({ name }) => isAutoName(name)))
|
|
123
|
+
return unresolvedDimension("calls", "unknown", links, leftValues.length, rightValues.length, ["Address-derived callee or caller names cannot be matched safely."]);
|
|
124
|
+
return compareCollections("calls", leftValues, rightValues, combineCoverage(left.collections.callers, left.collections.callees), combineCoverage(right.collections.callers, right.collections.callees), links, providersDiffer);
|
|
125
|
+
};
|
|
126
|
+
const callProjection = (snapshot) => [
|
|
127
|
+
...project(snapshot.collections.callers, ({ name }) => ({
|
|
128
|
+
direction: "in",
|
|
129
|
+
name,
|
|
130
|
+
})),
|
|
131
|
+
...project(snapshot.collections.callees, ({ name }) => ({
|
|
132
|
+
direction: "out",
|
|
133
|
+
name,
|
|
134
|
+
})),
|
|
135
|
+
];
|
|
136
|
+
const compareCfg = (left, right, links, providersDiffer) => {
|
|
137
|
+
const leftBlocks = left.collections.basic_blocks;
|
|
138
|
+
const rightBlocks = right.collections.basic_blocks;
|
|
139
|
+
if (!leftBlocks.complete || !rightBlocks.complete)
|
|
140
|
+
return unresolvedDimension("cfg", leftBlocks.truncated || rightBlocks.truncated ? "truncated" : "unknown", links, leftBlocks.items.length, rightBlocks.items.length, []);
|
|
141
|
+
const leftGraph = normalizeCfg(leftBlocks.items);
|
|
142
|
+
const rightGraph = normalizeCfg(rightBlocks.items);
|
|
143
|
+
if (leftGraph === null || rightGraph === null)
|
|
144
|
+
return unresolvedDimension("cfg", "unknown", links, leftBlocks.items.length, rightBlocks.items.length, ["CFG addresses could not be normalized to local block indices."]);
|
|
145
|
+
return compareValues("cfg", leftGraph, rightGraph, links, true, true, providersDiffer);
|
|
146
|
+
};
|
|
147
|
+
const compareValues = (...[dimension, left, right, links, leftComplete, rightComplete, providersDiffer,]) => {
|
|
148
|
+
if (!leftComplete || !rightComplete)
|
|
149
|
+
return unresolvedDimension(dimension, "unknown", links, null, null, []);
|
|
150
|
+
const leftJson = canonicalJson(left);
|
|
151
|
+
const rightJson = canonicalJson(right);
|
|
152
|
+
return dimensionResult({
|
|
153
|
+
dimension,
|
|
154
|
+
status: leftJson === rightJson ? "unchanged" : "changed",
|
|
155
|
+
left,
|
|
156
|
+
right,
|
|
157
|
+
links,
|
|
158
|
+
providersDiffer,
|
|
159
|
+
leftCount: Array.isArray(left) ? left.length : null,
|
|
160
|
+
rightCount: Array.isArray(right) ? right.length : null,
|
|
161
|
+
textDelta: null,
|
|
162
|
+
limitations: [],
|
|
163
|
+
});
|
|
164
|
+
};
|
|
@@ -145,20 +145,32 @@ const relationshipSignature = (node, side, context) => {
|
|
|
145
145
|
const signatures = graph.edges.flatMap((edge) => {
|
|
146
146
|
if (edge.source_node_id === node.node_id)
|
|
147
147
|
return [
|
|
148
|
-
edgeSignature(
|
|
148
|
+
edgeSignature({
|
|
149
|
+
direction: "out",
|
|
150
|
+
relation: edge.relation,
|
|
151
|
+
neighborId: edge.target_node_id,
|
|
152
|
+
paired,
|
|
153
|
+
nodeById,
|
|
154
|
+
}),
|
|
149
155
|
];
|
|
150
156
|
if (edge.target_node_id === node.node_id)
|
|
151
157
|
return [
|
|
152
|
-
edgeSignature(
|
|
158
|
+
edgeSignature({
|
|
159
|
+
direction: "in",
|
|
160
|
+
relation: edge.relation,
|
|
161
|
+
neighborId: edge.source_node_id,
|
|
162
|
+
paired,
|
|
163
|
+
nodeById,
|
|
164
|
+
}),
|
|
153
165
|
];
|
|
154
166
|
return [];
|
|
155
167
|
});
|
|
156
168
|
return canonical(signatures.sort(compareCodePoints));
|
|
157
169
|
};
|
|
158
|
-
const edgeSignature = (
|
|
159
|
-
const mapped = paired.get(neighborId);
|
|
160
|
-
const neighbor = nodeById.get(neighborId);
|
|
161
|
-
return `${direction}\0${relation}\0${mapped ?? `unmatched:${neighbor?.kind ?? "unknown"}`}`;
|
|
170
|
+
const edgeSignature = (context) => {
|
|
171
|
+
const mapped = context.paired.get(context.neighborId);
|
|
172
|
+
const neighbor = context.nodeById.get(context.neighborId);
|
|
173
|
+
return `${context.direction}\0${context.relation}\0${mapped ?? `unmatched:${neighbor?.kind ?? "unknown"}`}`;
|
|
162
174
|
};
|
|
163
175
|
const itemEvidenceLinks = (left, right, context) => [
|
|
164
176
|
...new Set([
|
|
@@ -23,7 +23,7 @@ export const matchJavaScriptApplicationVersions = (leftNodes, rightNodes) => {
|
|
|
23
23
|
const rightCandidates = new Map();
|
|
24
24
|
const pairs = [];
|
|
25
25
|
for (const tier of matchTiers())
|
|
26
|
-
applyTier(left, right, pairs, leftCandidates, rightCandidates, tier);
|
|
26
|
+
applyTier({ left, right, pairs, leftCandidates, rightCandidates, tier });
|
|
27
27
|
const remainingLeft = sortedNodes(left.values());
|
|
28
28
|
const remainingRight = sortedNodes(right.values());
|
|
29
29
|
const leftIds = new Set(remainingLeft.map(({ node_id: id }) => id));
|
|
@@ -36,24 +36,24 @@ export const matchJavaScriptApplicationVersions = (leftNodes, rightNodes) => {
|
|
|
36
36
|
candidatesForRight: filteredCandidates(rightCandidates, leftIds),
|
|
37
37
|
};
|
|
38
38
|
};
|
|
39
|
-
const applyTier = (
|
|
40
|
-
const leftByKey = nodesByKey(left.values(), tier.key);
|
|
41
|
-
const rightByKey = nodesByKey(right.values(), tier.key);
|
|
39
|
+
const applyTier = (context) => {
|
|
40
|
+
const leftByKey = nodesByKey(context.left.values(), context.tier.key);
|
|
41
|
+
const rightByKey = nodesByKey(context.right.values(), context.tier.key);
|
|
42
42
|
for (const key of [...leftByKey.keys()].sort(compareCodePoints)) {
|
|
43
43
|
const leftGroup = leftByKey.get(key) ?? [];
|
|
44
44
|
const rightGroup = rightByKey.get(key) ?? [];
|
|
45
45
|
if (rightGroup.length === 0)
|
|
46
46
|
continue;
|
|
47
|
-
recordCandidates(leftGroup, rightGroup, leftCandidates, rightCandidates);
|
|
47
|
+
recordCandidates(leftGroup, rightGroup, context.leftCandidates, context.rightCandidates);
|
|
48
48
|
if (leftGroup.length !== 1 || rightGroup.length !== 1)
|
|
49
49
|
continue;
|
|
50
50
|
const leftNode = leftGroup[0];
|
|
51
51
|
const rightNode = rightGroup[0];
|
|
52
52
|
if (leftNode === undefined || rightNode === undefined)
|
|
53
53
|
continue;
|
|
54
|
-
pairs.push({ left: leftNode, right: rightNode, ...tier });
|
|
55
|
-
left.delete(leftNode.node_id);
|
|
56
|
-
right.delete(rightNode.node_id);
|
|
54
|
+
context.pairs.push({ left: leftNode, right: rightNode, ...context.tier });
|
|
55
|
+
context.left.delete(leftNode.node_id);
|
|
56
|
+
context.right.delete(rightNode.node_id);
|
|
57
57
|
}
|
|
58
58
|
};
|
|
59
59
|
const nodesByKey = (nodes, keyFor) => {
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
const digestSchema = z.string().regex(/^[a-f0-9]{64}$/u);
|
|
4
|
+
export const javascriptExportInstrumentationInputSchema = z.strictObject({
|
|
5
|
+
artifact_path: z.string().min(1).max(4_096),
|
|
6
|
+
artifact_sha256: digestSchema,
|
|
7
|
+
selection: z.strictObject({
|
|
8
|
+
byte_start: z.number().int().min(0),
|
|
9
|
+
byte_end: z.number().int().min(1),
|
|
10
|
+
selected_sha256: digestSchema,
|
|
11
|
+
export_name: z.string().regex(/^[A-Za-z_$][A-Za-z0-9_$]{0,199}$/u),
|
|
12
|
+
}),
|
|
13
|
+
});
|
|
14
|
+
export const javascriptExportTransformationManifestSchema = z.strictObject({
|
|
15
|
+
schema_version: z.literal(1),
|
|
16
|
+
kind: z.literal("commonjs-factory-export-v1"),
|
|
17
|
+
artifact_path: z.string().min(1).max(4_096),
|
|
18
|
+
original_sha256: digestSchema,
|
|
19
|
+
original_byte_length: z.number().int().min(0),
|
|
20
|
+
instrumented_sha256: digestSchema,
|
|
21
|
+
instrumented_byte_length: z.number().int().min(0),
|
|
22
|
+
selected_range: z.strictObject({
|
|
23
|
+
byte_start: z.number().int().min(0),
|
|
24
|
+
byte_end: z.number().int().min(1),
|
|
25
|
+
selected_sha256: digestSchema,
|
|
26
|
+
}),
|
|
27
|
+
inserted_ranges: z
|
|
28
|
+
.array(z.strictObject({
|
|
29
|
+
byte_start: z.number().int().min(0),
|
|
30
|
+
byte_end: z.number().int().min(1),
|
|
31
|
+
inserted_sha256: digestSchema,
|
|
32
|
+
purpose: z.enum(["factory-prefix", "export-binding", "factory-suffix"]),
|
|
33
|
+
}))
|
|
34
|
+
.length(3),
|
|
35
|
+
output_format: z.literal("commonjs-factory"),
|
|
36
|
+
source_map: z.literal(null),
|
|
37
|
+
});
|
|
38
|
+
/** Instrument one exact UTF-8 expression range without mutating source bytes. */
|
|
39
|
+
export const instrumentJavaScriptExport = (source, rawInput) => {
|
|
40
|
+
const input = javascriptExportInstrumentationInputSchema.parse(rawInput);
|
|
41
|
+
if (sha256(source) !== input.artifact_sha256)
|
|
42
|
+
throw new TypeError("JavaScript instrumentation artifact digest mismatch");
|
|
43
|
+
const { byte_start: start, byte_end: end } = input.selection;
|
|
44
|
+
if (end <= start || end > source.byteLength)
|
|
45
|
+
throw new TypeError("JavaScript instrumentation selection is out of bounds");
|
|
46
|
+
const selected = source.slice(start, end);
|
|
47
|
+
if (sha256(selected) !== input.selection.selected_sha256)
|
|
48
|
+
throw new TypeError("JavaScript instrumentation selection digest mismatch");
|
|
49
|
+
decodeUtf8(source);
|
|
50
|
+
decodeUtf8(selected);
|
|
51
|
+
const prefix = encode("function(module, exports, require) {\n");
|
|
52
|
+
const binding = encode(`\nmodule.exports[${JSON.stringify(input.selection.export_name)}] = (${decodeUtf8(selected)});\n`);
|
|
53
|
+
const suffix = encode("}\n");
|
|
54
|
+
const bytes = concatenate([prefix, source, binding, suffix]);
|
|
55
|
+
const bindingStart = prefix.byteLength + source.byteLength;
|
|
56
|
+
const suffixStart = bindingStart + binding.byteLength;
|
|
57
|
+
const manifest = javascriptExportTransformationManifestSchema.parse({
|
|
58
|
+
schema_version: 1,
|
|
59
|
+
kind: "commonjs-factory-export-v1",
|
|
60
|
+
artifact_path: input.artifact_path,
|
|
61
|
+
original_sha256: input.artifact_sha256,
|
|
62
|
+
original_byte_length: source.byteLength,
|
|
63
|
+
instrumented_sha256: sha256(bytes),
|
|
64
|
+
instrumented_byte_length: bytes.byteLength,
|
|
65
|
+
selected_range: {
|
|
66
|
+
byte_start: start,
|
|
67
|
+
byte_end: end,
|
|
68
|
+
selected_sha256: input.selection.selected_sha256,
|
|
69
|
+
},
|
|
70
|
+
inserted_ranges: [
|
|
71
|
+
range(0, prefix, "factory-prefix"),
|
|
72
|
+
range(bindingStart, binding, "export-binding"),
|
|
73
|
+
range(suffixStart, suffix, "factory-suffix"),
|
|
74
|
+
],
|
|
75
|
+
output_format: "commonjs-factory",
|
|
76
|
+
source_map: null,
|
|
77
|
+
});
|
|
78
|
+
return { bytes, manifest };
|
|
79
|
+
};
|
|
80
|
+
const range = (start, bytes, purpose) => ({
|
|
81
|
+
byte_start: start,
|
|
82
|
+
byte_end: start + bytes.byteLength,
|
|
83
|
+
inserted_sha256: sha256(bytes),
|
|
84
|
+
purpose,
|
|
85
|
+
});
|
|
86
|
+
const encode = (value) => new TextEncoder().encode(value);
|
|
87
|
+
const decodeUtf8 = (value) => new TextDecoder("utf-8", { fatal: true }).decode(value);
|
|
88
|
+
const concatenate = (values) => {
|
|
89
|
+
const output = new Uint8Array(values.reduce((total, value) => total + value.byteLength, 0));
|
|
90
|
+
let offset = 0;
|
|
91
|
+
for (const value of values) {
|
|
92
|
+
output.set(value, offset);
|
|
93
|
+
offset += value.byteLength;
|
|
94
|
+
}
|
|
95
|
+
return output;
|
|
96
|
+
};
|
|
97
|
+
const sha256 = (value) => createHash("sha256").update(value).digest("hex");
|
|
@@ -18,11 +18,23 @@ export const traverseApplicationFeature = (graph, seedNodeIds, direction, limits
|
|
|
18
18
|
const depth = depths.get(current) ?? 0;
|
|
19
19
|
for (const entry of adjacency.get(current) ?? []) {
|
|
20
20
|
if (depth >= limits.max_depth) {
|
|
21
|
-
recordOmission(
|
|
21
|
+
recordOmission({
|
|
22
|
+
entry,
|
|
23
|
+
current,
|
|
24
|
+
omittedNodes,
|
|
25
|
+
omittedEdges,
|
|
26
|
+
frontier,
|
|
27
|
+
});
|
|
22
28
|
continue;
|
|
23
29
|
}
|
|
24
30
|
if (!visited.has(entry.nextNodeId) && visited.size >= limits.max_nodes) {
|
|
25
|
-
recordOmission(
|
|
31
|
+
recordOmission({
|
|
32
|
+
entry,
|
|
33
|
+
current,
|
|
34
|
+
omittedNodes,
|
|
35
|
+
omittedEdges,
|
|
36
|
+
frontier,
|
|
37
|
+
});
|
|
26
38
|
continue;
|
|
27
39
|
}
|
|
28
40
|
if (!retainedEdges.has(entry.edge.edge_id) &&
|
|
@@ -80,9 +92,9 @@ const buildAdjacency = (edges, direction) => {
|
|
|
80
92
|
const addAdjacency = (adjacency, nodeId, entry) => {
|
|
81
93
|
adjacency.set(nodeId, [...(adjacency.get(nodeId) ?? []), entry]);
|
|
82
94
|
};
|
|
83
|
-
const recordOmission = (
|
|
84
|
-
omittedNodes.add(entry.nextNodeId);
|
|
85
|
-
omittedEdges.add(entry.edge.edge_id);
|
|
86
|
-
frontier.add(current);
|
|
87
|
-
frontier.add(entry.nextNodeId);
|
|
95
|
+
const recordOmission = (context) => {
|
|
96
|
+
context.omittedNodes.add(context.entry.nextNodeId);
|
|
97
|
+
context.omittedEdges.add(context.entry.edge.edge_id);
|
|
98
|
+
context.frontier.add(context.current);
|
|
99
|
+
context.frontier.add(context.entry.nextNodeId);
|
|
88
100
|
};
|
|
@@ -61,7 +61,8 @@ const candidatesForLayer = (layer) => {
|
|
|
61
61
|
const candidateCategory = (node) => {
|
|
62
62
|
if (node.kind === "electron-renderer")
|
|
63
63
|
return "renderer";
|
|
64
|
-
if (node.kind === "javascript-asset" ||
|
|
64
|
+
if (node.kind === "javascript-asset" ||
|
|
65
|
+
(node.kind === "javascript-module" && !isStaticSourceModule(node)))
|
|
65
66
|
return "javascript";
|
|
66
67
|
if (node.kind === "worker")
|
|
67
68
|
return "worker";
|
|
@@ -69,6 +70,7 @@ const candidateCategory = (node) => {
|
|
|
69
70
|
return "service-worker";
|
|
70
71
|
return null;
|
|
71
72
|
};
|
|
73
|
+
const isStaticSourceModule = (node) => node.observations.some(({ properties }) => properties.semantic_role === "source-module");
|
|
72
74
|
const indexStaticPaths = (graph) => {
|
|
73
75
|
const nodes = new Map(graph.nodes.map((candidate) => [candidate.node_id, candidate]));
|
|
74
76
|
const relatedBySource = new Map();
|