rea-agents 1.7.0 → 2.0.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 +38 -31
- package/dist/application/CapabilityInventory.js +18 -0
- package/dist/application/CrossVersionInvestigation.js +10 -6
- package/dist/application/Doctor.js +56 -6
- package/dist/application/ElectronBoundaryAnalysis.js +96 -0
- package/dist/application/ElectronBoundaryGraph.js +9 -0
- package/dist/application/ElectronBoundaryGraphContext.js +62 -0
- package/dist/application/ElectronBoundaryGraphIpc.js +242 -0
- package/dist/application/ElectronBoundaryGraphNative.js +86 -0
- package/dist/application/ElectronBoundaryGraphWindows.js +199 -0
- package/dist/application/EnhancedTools.js +38 -13
- package/dist/application/InvestigationProviders.js +30 -0
- package/dist/application/JavaScriptApplicationEvidence.js +26 -0
- package/dist/application/JavaScriptApplicationEvidenceGraph.js +89 -0
- package/dist/application/JavaScriptApplicationService.js +74 -0
- package/dist/application/JavaScriptApplicationWorkflowEvidence.js +29 -0
- package/dist/application/JavaScriptApplicationWorkflowService.js +90 -0
- package/dist/application/JavaScriptArtifactAnalysis.js +7 -1
- package/dist/application/JavaScriptArtifactGraphBuilder.js +59 -16
- package/dist/application/JavaScriptArtifactGraphEvidence.js +24 -14
- package/dist/application/JavaScriptArtifactReconstruction.js +3 -0
- package/dist/application/JavaScriptArtifactReconstructionInput.js +2 -83
- package/dist/application/JavaScriptReplayPlanning.js +201 -0
- package/dist/application/JavaScriptReplayService.js +266 -0
- package/dist/application/JavaScriptRuntimeReconciliationEvidence.js +25 -0
- package/dist/application/JavaScriptRuntimeReconciliationService.js +27 -0
- package/dist/application/ManagedApplicationGraphService.js +55 -0
- package/dist/application/ManagedMemberComparisonService.js +122 -0
- package/dist/application/ManagedNativeVerificationService.js +39 -0
- package/dist/application/ManagedReconstructionService.js +58 -0
- package/dist/application/ManagedRuntimeCorrelationService.js +103 -0
- package/dist/application/PermissionAuthority.js +1 -1
- package/dist/application/ProcessSampling.js +15 -11
- package/dist/application/ProjectPermissionStore.js +1 -0
- package/dist/application/runtime.js +2 -0
- package/dist/browser/CdpCaptureEvents.js +49 -0
- package/dist/browser/CdpElectronInspection.js +106 -162
- package/dist/browser/CdpElectronProvider.js +5 -1
- package/dist/browser/CdpElectronScriptEvents.js +69 -0
- package/dist/browser/CdpElectronScripts.js +94 -0
- package/dist/browser/CdpElectronWorkers.js +56 -0
- package/dist/browser/CdpPageCapture.js +8 -4
- package/dist/catalogIdentity.js +4 -1
- package/dist/cli.js +388 -0
- package/dist/cliApplicationCommands.js +62 -0
- package/dist/cliCommandNames.js +13 -0
- package/dist/cliElectronCommands.js +103 -1
- package/dist/cliJsonInput.js +54 -0
- package/dist/config.js +83 -0
- package/dist/contracts/applicationToolContracts.js +91 -0
- package/dist/contracts/artifactToolContracts.js +5 -9
- package/dist/contracts/browserToolContracts.js +14 -62
- package/dist/contracts/electronToolContracts.js +45 -19
- package/dist/contracts/errorSchemas.js +1 -0
- package/dist/contracts/investigationExamples.js +0 -6
- package/dist/contracts/javascriptApplicationWorkflowExamples.js +46 -0
- package/dist/contracts/javascriptRuntimeReconciliationExample.js +208 -0
- package/dist/contracts/managedToolContracts.js +153 -0
- package/dist/contracts/managedWorkflowExamples.js +346 -0
- package/dist/contracts/managedWorkflowToolContracts.js +203 -0
- package/dist/contracts/nativeToolContracts.js +2 -6
- package/dist/contracts/promptContracts.js +18 -2
- package/dist/contracts/toolContractExamples.js +10 -25
- package/dist/contracts/toolContracts.js +47 -45
- package/dist/contracts/toolEffects.js +160 -0
- package/dist/contracts/toolOutputSchemas.js +46 -31
- package/dist/doctorRuntime.js +42 -1
- package/dist/domain/artifactComparison.js +3 -4
- package/dist/domain/browserObservation.js +3 -0
- package/dist/domain/bundleComparison.js +4 -4
- package/dist/domain/electronObservation.js +13 -0
- package/dist/domain/electronStaticAnalysis.js +9 -0
- package/dist/domain/electronStaticAnalysisBrowser.js +194 -0
- package/dist/domain/electronStaticAnalysisIpc.js +171 -0
- package/dist/domain/electronStaticAnalysisNative.js +164 -0
- package/dist/domain/electronStaticAnalysisTypes.js +1 -0
- package/dist/domain/electronStaticAnalysisValues.js +103 -0
- package/dist/domain/errors.js +67 -1
- package/dist/domain/functionComparisonSchemas.js +3 -8
- package/dist/domain/inputIssueProjection.js +52 -0
- package/dist/domain/javascriptApplicationAnalysis.js +155 -0
- package/dist/domain/javascriptApplicationChangeGraph.js +231 -0
- package/dist/domain/javascriptApplicationEvidenceSchemas.js +18 -0
- package/dist/domain/javascriptApplicationGraph.js +2 -1
- package/dist/domain/javascriptApplicationGraphSchemas.js +7 -0
- package/dist/domain/javascriptApplicationVersionComparison.js +116 -0
- package/dist/domain/javascriptApplicationVersionComparisonSchemas.js +139 -0
- package/dist/domain/javascriptApplicationVersionItems.js +221 -0
- package/dist/domain/javascriptApplicationVersionKeys.js +170 -0
- package/dist/domain/javascriptFeatureSeed.js +140 -0
- package/dist/domain/javascriptFeatureTrace.js +232 -0
- package/dist/domain/javascriptFeatureTraceSchemas.js +136 -0
- package/dist/domain/javascriptFeatureTraversal.js +88 -0
- package/dist/domain/javascriptNativeHandoff.js +85 -0
- package/dist/domain/javascriptReplay.js +361 -0
- package/dist/domain/javascriptRuntimeLoadState.js +106 -0
- package/dist/domain/javascriptRuntimeReconciliation.js +42 -0
- package/dist/domain/javascriptRuntimeReconciliationGraph.js +169 -0
- package/dist/domain/javascriptRuntimeReconciliationMatching.js +247 -0
- package/dist/domain/javascriptRuntimeReconciliationParsing.js +160 -0
- package/dist/domain/javascriptRuntimeReconciliationResult.js +119 -0
- package/dist/domain/javascriptRuntimeReconciliationRuntime.js +316 -0
- package/dist/domain/javascriptRuntimeReconciliationSchemas.js +245 -0
- package/dist/domain/javascriptRuntimeStaticCandidates.js +191 -0
- package/dist/domain/javascriptStaticAnalysis.js +31 -43
- package/dist/domain/javascriptStaticAnalysisFindings.js +39 -0
- package/dist/domain/javascriptStaticAnalysisHelpers.js +10 -0
- package/dist/domain/javascriptStaticAnalysisState.js +6 -0
- package/dist/domain/managedApplicationGraph.js +556 -0
- package/dist/domain/managedArtifact.js +444 -0
- package/dist/domain/managedMemberComparison.js +565 -0
- package/dist/domain/managedNativeVerification.js +408 -0
- package/dist/domain/managedReconstruction.js +183 -0
- package/dist/domain/managedRuntimeCorrelation.js +175 -0
- package/dist/domain/reconstructionVerificationSchemas.js +1 -3
- package/dist/dotnet/ManagedArtifactInspector.js +318 -0
- package/dist/dotnet/ManagedMemberInspector.js +887 -0
- package/dist/dotnet/ManagedMetadataHeaps.js +131 -0
- package/dist/dotnet/ManagedMetadataInventory.js +368 -0
- package/dist/dotnet/ManagedMetadataLayout.js +322 -0
- package/dist/dotnet/ManagedNativeBoundaryInspector.js +391 -0
- package/dist/dotnet/ManagedPeReader.js +157 -0
- package/dist/dotnet/ManagedReaderFailure.js +10 -0
- package/dist/dotnet/ManagedStaticProvider.js +203 -0
- package/dist/generatedPackageMetadata.js +2 -2
- package/dist/ghidra/GhidraProvider.js +6 -0
- package/dist/main.js +14 -0
- package/dist/replay/JavaScriptReplayWorker.js +286 -0
- package/dist/replay/LinuxJavaScriptReplayRunner.js +434 -0
- package/dist/replay/LinuxRuntimeClosure.js +46 -0
- package/dist/replay/LinuxSeccompPolicy.js +40 -0
- package/dist/replay/ReplayWorkerProtocol.js +55 -0
- package/dist/replay/SystemJavaScriptReplayHost.js +182 -0
- package/dist/server/createServer.js +52 -0
- package/dist/server/registerApplicationTools.js +115 -0
- package/dist/server/registerArtifactComparisonTool.js +16 -9
- package/dist/server/registerBrowserTools.js +33 -8
- package/dist/server/registerBundleComparisonTool.js +17 -20
- package/dist/server/registerElectronTools.js +45 -3
- package/dist/server/registerEnhancedTools.js +58 -13
- package/dist/server/registerEvidenceTools.js +5 -1
- package/dist/server/registerFunctionComparisonTool.js +14 -7
- package/dist/server/registerInvestigationTools.js +21 -17
- package/dist/server/registerManagedTools.js +6 -0
- package/dist/server/registerManagedWorkflowTools.js +277 -0
- package/dist/server/registerOfficialTools.js +8 -8
- package/dist/server/registerProcessComparisonTool.js +25 -47
- package/dist/server/registerSessionStatusTool.js +7 -7
- package/dist/server/registerSessionTools.js +51 -86
- package/dist/server/sessionEvidence.js +14 -19
- package/dist/server/toolInputValidation.js +77 -0
- package/dist/server/toolRegistrationOptions.js +79 -2
- package/dist/server/toolResult.js +25 -17
- package/package.json +12 -4
- package/scripts/rea.mjs +1 -1
- package/skills/rea-analysis/SKILL.md +59 -3
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { readFile, stat } from "node:fs/promises";
|
|
3
|
+
import { createAnalysisExecution, } from "../application/AnalysisProvider.js";
|
|
4
|
+
import { MANAGED_STATIC_PROVIDER } from "../application/InvestigationProviders.js";
|
|
5
|
+
import { MANAGED_TOOL_CONTRACTS, managedArtifactInputSchema, managedMemberInputSchema, managedNativeBoundaryInputSchema, } from "../contracts/managedToolContracts.js";
|
|
6
|
+
import { AnalysisCancelledError, AnalysisCapabilityUnavailableError, EvidenceIntegrityError, ProviderAdapterError, } from "../domain/errors.js";
|
|
7
|
+
import { err, ok } from "../domain/result.js";
|
|
8
|
+
import { inspectManagedArtifactBytes } from "./ManagedArtifactInspector.js";
|
|
9
|
+
import { inspectManagedMembersBytes } from "./ManagedMemberInspector.js";
|
|
10
|
+
import { inspectManagedNativeBoundariesBytes } from "./ManagedNativeBoundaryInspector.js";
|
|
11
|
+
const IDENTITY = Object.freeze(MANAGED_STATIC_PROVIDER);
|
|
12
|
+
/** Execution-free managed PE/CLI auxiliary provider. */
|
|
13
|
+
export class ManagedStaticProvider {
|
|
14
|
+
#capabilities = Object.freeze(MANAGED_TOOL_CONTRACTS.map((contract) => Object.freeze({
|
|
15
|
+
provider: IDENTITY,
|
|
16
|
+
operation: contract.name,
|
|
17
|
+
inputContractVersion: 1,
|
|
18
|
+
outputContractVersion: 1,
|
|
19
|
+
available: true,
|
|
20
|
+
reason: null,
|
|
21
|
+
pagination: "offset",
|
|
22
|
+
exhaustive: false,
|
|
23
|
+
effects: Object.freeze({
|
|
24
|
+
mutatesArtifact: false,
|
|
25
|
+
launchesProcess: false,
|
|
26
|
+
mayShowUi: false,
|
|
27
|
+
mayAccessNetwork: false,
|
|
28
|
+
mayWriteFilesystem: false,
|
|
29
|
+
changesPermissions: false,
|
|
30
|
+
requiresRoot: false,
|
|
31
|
+
}),
|
|
32
|
+
limits: Object.freeze({
|
|
33
|
+
maxResults: 500,
|
|
34
|
+
maxPayloadBytes: 4 * 1024 * 1024,
|
|
35
|
+
timeoutMs: null,
|
|
36
|
+
}),
|
|
37
|
+
limitations: limitationsFor(contract.name),
|
|
38
|
+
})));
|
|
39
|
+
identity() {
|
|
40
|
+
return IDENTITY;
|
|
41
|
+
}
|
|
42
|
+
capabilities() {
|
|
43
|
+
return this.#capabilities;
|
|
44
|
+
}
|
|
45
|
+
createClient(target) {
|
|
46
|
+
return new ManagedStaticClient(target);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
class ManagedStaticClient {
|
|
50
|
+
target;
|
|
51
|
+
constructor(target) {
|
|
52
|
+
this.target = target;
|
|
53
|
+
}
|
|
54
|
+
async execute(operation, parameters, options) {
|
|
55
|
+
if (operation === "health")
|
|
56
|
+
return ok(createAnalysisExecution(null, IDENTITY));
|
|
57
|
+
if (!isManagedOperation(operation))
|
|
58
|
+
return err(new AnalysisCapabilityUnavailableError(IDENTITY.id, operation, "Operation is not implemented by the managed static provider."));
|
|
59
|
+
if (this.target.format !== "pe")
|
|
60
|
+
return err(new AnalysisCapabilityUnavailableError(IDENTITY.id, operation, `Managed static triage requires a PE target; observed ${this.target.format}.`));
|
|
61
|
+
try {
|
|
62
|
+
if (options?.signal?.aborted === true)
|
|
63
|
+
return err(new AnalysisCancelledError(operation));
|
|
64
|
+
const maxFileBytes = maxRequestedFileBytes(operation, parameters);
|
|
65
|
+
const metadata = await stat(this.target.path);
|
|
66
|
+
if (metadata.size > maxFileBytes)
|
|
67
|
+
return err(new AnalysisCapabilityUnavailableError(IDENTITY.id, operation, `Artifact size ${String(metadata.size)} exceeds max_file_bytes ${String(maxFileBytes)}.`));
|
|
68
|
+
const bytes = await readFile(this.target.path, options?.signal === undefined ? undefined : { signal: options.signal });
|
|
69
|
+
if (bytes.length > maxFileBytes)
|
|
70
|
+
return err(new AnalysisCapabilityUnavailableError(IDENTITY.id, operation, `Artifact grew beyond max_file_bytes ${String(maxFileBytes)} while it was read.`));
|
|
71
|
+
const observedDigest = createHash("sha256").update(bytes).digest("hex");
|
|
72
|
+
if (observedDigest !== this.target.sha256)
|
|
73
|
+
return err(new EvidenceIntegrityError(`Managed artifact digest changed after open: expected ${this.target.sha256}, observed ${observedDigest} at ${this.target.path}`));
|
|
74
|
+
const result = inspectManagedOperation(operation, parameters, bytes, this.target);
|
|
75
|
+
return ok(createAnalysisExecution(result, IDENTITY, {
|
|
76
|
+
rawResult: null,
|
|
77
|
+
limitations: result.limitations,
|
|
78
|
+
subject: this.target,
|
|
79
|
+
locations: managedLocations(result),
|
|
80
|
+
}));
|
|
81
|
+
}
|
|
82
|
+
catch (cause) {
|
|
83
|
+
if (options?.signal?.aborted === true)
|
|
84
|
+
return err(new AnalysisCancelledError(operation));
|
|
85
|
+
return err(new ProviderAdapterError(IDENTITY.id, operation, { cause }));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
close() {
|
|
89
|
+
return Promise.resolve();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
const isManagedOperation = (operation) => MANAGED_TOOL_CONTRACTS.some(({ name }) => name === operation);
|
|
93
|
+
const limitationsFor = (operation) => Object.freeze(operation === "inspect_managed_artifact"
|
|
94
|
+
? [
|
|
95
|
+
"This capability inventories PE/CLI identity only; inspect_managed_members admits bounded metadata members, signatures, and CIL anchors.",
|
|
96
|
+
"It never loads the target assembly, resolves dependencies through a CLR, decompiles C#, or executes target code.",
|
|
97
|
+
]
|
|
98
|
+
: operation === "inspect_managed_native_boundaries"
|
|
99
|
+
? [
|
|
100
|
+
"This capability inventories managed declarations for native boundaries only; native exports, thunks, and addresses require separate native-provider evidence.",
|
|
101
|
+
"It never loads the target assembly, resolves dependencies through a CLR, decompiles C#, or executes target code.",
|
|
102
|
+
]
|
|
103
|
+
: [
|
|
104
|
+
"This capability decodes bounded PE/CLI metadata members, signatures, and file-backed method bodies; decompiled C# and cross-build matching are separate future contracts.",
|
|
105
|
+
"It never loads the target assembly, resolves dependencies through a CLR, decompiles C#, or executes target code.",
|
|
106
|
+
]);
|
|
107
|
+
const maxRequestedFileBytes = (operation, parameters) => {
|
|
108
|
+
if (operation === "inspect_managed_artifact")
|
|
109
|
+
return managedArtifactInputSchema.parse(parameters).max_file_bytes;
|
|
110
|
+
if (operation === "inspect_managed_native_boundaries")
|
|
111
|
+
return managedNativeBoundaryInputSchema.parse(parameters).max_file_bytes;
|
|
112
|
+
return managedMemberInputSchema.parse(parameters).max_file_bytes;
|
|
113
|
+
};
|
|
114
|
+
const inspectManagedOperation = (operation, parameters, bytes, target) => {
|
|
115
|
+
if (operation === "inspect_managed_artifact") {
|
|
116
|
+
const input = managedArtifactInputSchema.parse(parameters);
|
|
117
|
+
return inspectManagedArtifactBytes(bytes, target, {
|
|
118
|
+
referenceOffset: input.reference_offset,
|
|
119
|
+
referenceLimit: input.reference_limit,
|
|
120
|
+
resourceOffset: input.resource_offset,
|
|
121
|
+
resourceLimit: input.resource_limit,
|
|
122
|
+
attributeOffset: input.attribute_offset,
|
|
123
|
+
attributeLimit: input.attribute_limit,
|
|
124
|
+
maxMetadataBytes: input.max_metadata_bytes,
|
|
125
|
+
maxTableRows: input.max_table_rows,
|
|
126
|
+
maxHeapItemBytes: input.max_heap_item_bytes,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
if (operation === "inspect_managed_native_boundaries") {
|
|
130
|
+
const input = managedNativeBoundaryInputSchema.parse(parameters);
|
|
131
|
+
return inspectManagedNativeBoundariesBytes(bytes, target, {
|
|
132
|
+
moduleRefOffset: input.module_ref_offset,
|
|
133
|
+
moduleRefLimit: input.module_ref_limit,
|
|
134
|
+
importOffset: input.import_offset,
|
|
135
|
+
importLimit: input.import_limit,
|
|
136
|
+
implementationOffset: input.implementation_offset,
|
|
137
|
+
implementationLimit: input.implementation_limit,
|
|
138
|
+
maxMetadataBytes: input.max_metadata_bytes,
|
|
139
|
+
maxTableRows: input.max_table_rows,
|
|
140
|
+
maxHeapItemBytes: input.max_heap_item_bytes,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
const input = managedMemberInputSchema.parse(parameters);
|
|
144
|
+
return inspectManagedMembersBytes(bytes, target, {
|
|
145
|
+
typeOffset: input.type_offset,
|
|
146
|
+
typeLimit: input.type_limit,
|
|
147
|
+
methodOffset: input.method_offset,
|
|
148
|
+
methodLimit: input.method_limit,
|
|
149
|
+
fieldOffset: input.field_offset,
|
|
150
|
+
fieldLimit: input.field_limit,
|
|
151
|
+
memberRefOffset: input.member_ref_offset,
|
|
152
|
+
memberRefLimit: input.member_ref_limit,
|
|
153
|
+
edgeOffset: input.edge_offset,
|
|
154
|
+
edgeLimit: input.edge_limit,
|
|
155
|
+
instructionAnchorLimit: input.instruction_anchor_limit,
|
|
156
|
+
maxMetadataBytes: input.max_metadata_bytes,
|
|
157
|
+
maxTableRows: input.max_table_rows,
|
|
158
|
+
maxHeapItemBytes: input.max_heap_item_bytes,
|
|
159
|
+
maxMethodBodyBytes: input.max_method_body_bytes,
|
|
160
|
+
maxMethodInstructions: input.max_method_instructions,
|
|
161
|
+
});
|
|
162
|
+
};
|
|
163
|
+
const managedLocations = (result) => {
|
|
164
|
+
if ("pe" in result) {
|
|
165
|
+
if (result.pe.cli === null)
|
|
166
|
+
return [{ kind: "file-offset", offset: 0 }];
|
|
167
|
+
return [
|
|
168
|
+
{
|
|
169
|
+
kind: "file-offset-range",
|
|
170
|
+
start: result.pe.cli.header_offset,
|
|
171
|
+
end: result.pe.cli.header_offset + result.pe.cli.header_size,
|
|
172
|
+
},
|
|
173
|
+
...[result.module, result.assembly]
|
|
174
|
+
.filter((value) => value !== null)
|
|
175
|
+
.map((value) => ({
|
|
176
|
+
kind: "file-offset",
|
|
177
|
+
offset: value.row_offset,
|
|
178
|
+
})),
|
|
179
|
+
];
|
|
180
|
+
}
|
|
181
|
+
if ("methods" in result)
|
|
182
|
+
return [
|
|
183
|
+
...(result.module === null
|
|
184
|
+
? [{ kind: "file-offset", offset: 0 }]
|
|
185
|
+
: [{ kind: "file-offset", offset: result.module.row_offset }]),
|
|
186
|
+
...result.methods.items
|
|
187
|
+
.filter((method) => method.body.file_offset !== null)
|
|
188
|
+
.slice(0, 8)
|
|
189
|
+
.map((method) => ({
|
|
190
|
+
kind: "file-offset",
|
|
191
|
+
offset: method.body.file_offset ?? 0,
|
|
192
|
+
})),
|
|
193
|
+
];
|
|
194
|
+
return [
|
|
195
|
+
...(result.module === null
|
|
196
|
+
? [{ kind: "file-offset", offset: 0 }]
|
|
197
|
+
: [{ kind: "file-offset", offset: result.module.row_offset }]),
|
|
198
|
+
...result.pinvoke_imports.items.slice(0, 8).map((mapping) => ({
|
|
199
|
+
kind: "file-offset",
|
|
200
|
+
offset: mapping.row_offset,
|
|
201
|
+
})),
|
|
202
|
+
];
|
|
203
|
+
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/** Generated from package.json and package-lock.json; do not edit. */
|
|
2
2
|
export const PACKAGE_METADATA = {
|
|
3
3
|
name: "rea-agents",
|
|
4
|
-
version: "
|
|
4
|
+
version: "2.0.0",
|
|
5
5
|
serverSdkVersion: "2.0.0-beta.4",
|
|
6
6
|
clientSdkVersion: "2.0.0-beta.4",
|
|
7
7
|
coreSdkVersion: "2.0.0-beta.4",
|
|
8
|
-
skillVersion: "
|
|
8
|
+
skillVersion: "20",
|
|
9
9
|
};
|
|
@@ -307,6 +307,12 @@ export class GhidraProvider {
|
|
|
307
307
|
...(this.config.ghidraJavaHome === undefined
|
|
308
308
|
? {}
|
|
309
309
|
: { javaHome: this.config.ghidraJavaHome }),
|
|
310
|
+
...(this.installationHost?.platform === undefined
|
|
311
|
+
? {}
|
|
312
|
+
: { platform: this.installationHost.platform }),
|
|
313
|
+
...(this.installationHost?.architecture === undefined
|
|
314
|
+
? {}
|
|
315
|
+
: { architecture: this.installationHost.architecture }),
|
|
310
316
|
};
|
|
311
317
|
this.#installation ??=
|
|
312
318
|
this.installationHost === undefined
|
package/dist/main.js
CHANGED
|
@@ -89,6 +89,14 @@ export const run = async (dependencies = runtimeDependencies()) => {
|
|
|
89
89
|
roots: [...config.value.analysisSnapshotFilePolicy.roots],
|
|
90
90
|
};
|
|
91
91
|
const runtimeInvestigationRoots = [...config.value.investigationInputRoots];
|
|
92
|
+
const runtimeJavascriptReplayPolicy = {
|
|
93
|
+
...config.value.javascriptReplayPolicy,
|
|
94
|
+
roots: [...config.value.javascriptReplayPolicy.roots],
|
|
95
|
+
};
|
|
96
|
+
const runtimeManagedRuntimePolicy = {
|
|
97
|
+
...config.value.managedRuntimePolicy,
|
|
98
|
+
roots: [...config.value.managedRuntimePolicy.roots],
|
|
99
|
+
};
|
|
92
100
|
const liveServers = new Set();
|
|
93
101
|
let handle;
|
|
94
102
|
try {
|
|
@@ -103,6 +111,8 @@ export const run = async (dependencies = runtimeDependencies()) => {
|
|
|
103
111
|
browserObservation,
|
|
104
112
|
electronObservation,
|
|
105
113
|
artifactIntegrityContinueEnabled: () => currentConfig.artifactIntegrityContinueEnabled,
|
|
114
|
+
javascriptReplayPolicy: runtimeJavascriptReplayPolicy,
|
|
115
|
+
managedRuntimePolicy: runtimeManagedRuntimePolicy,
|
|
106
116
|
availabilityPolicy: () => ({
|
|
107
117
|
processCaptureEnabled: currentConfig.processExecutionPolicy.enabled,
|
|
108
118
|
evidenceFileRoots: currentConfig.evidenceFilePolicy.roots.length,
|
|
@@ -112,6 +122,8 @@ export const run = async (dependencies = runtimeDependencies()) => {
|
|
|
112
122
|
electronObservationEnabled: currentConfig.electronObservationEnabled &&
|
|
113
123
|
currentConfig.electronCdpEndpoints.length > 0 &&
|
|
114
124
|
currentConfig.electronFileRoots.length > 0,
|
|
125
|
+
javascriptReplayEnabled: currentConfig.javascriptReplayPolicy.enabled,
|
|
126
|
+
managedRuntimeEnabled: currentConfig.managedRuntimePolicy.enabled,
|
|
115
127
|
}),
|
|
116
128
|
});
|
|
117
129
|
liveServers.add(server);
|
|
@@ -162,6 +174,8 @@ export const run = async (dependencies = runtimeDependencies()) => {
|
|
|
162
174
|
Object.assign(runtimeEvidencePolicy, refreshed.value.evidenceFilePolicy);
|
|
163
175
|
Object.assign(runtimeSnapshotPolicy, refreshed.value.analysisSnapshotFilePolicy);
|
|
164
176
|
runtimeInvestigationRoots.splice(0, runtimeInvestigationRoots.length, ...refreshed.value.investigationInputRoots);
|
|
177
|
+
Object.assign(runtimeJavascriptReplayPolicy, refreshed.value.javascriptReplayPolicy);
|
|
178
|
+
Object.assign(runtimeManagedRuntimePolicy, refreshed.value.managedRuntimePolicy);
|
|
165
179
|
for (const server of liveServers)
|
|
166
180
|
server.sendToolListChanged();
|
|
167
181
|
});
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import { Script, SourceTextModule, SyntheticModule, createContext, } from "node:vm";
|
|
2
|
+
import { types } from "node:util";
|
|
3
|
+
class ReplayDeniedError extends Error {
|
|
4
|
+
name = "ReplayDeniedError";
|
|
5
|
+
}
|
|
6
|
+
const main = async () => {
|
|
7
|
+
const chunks = [];
|
|
8
|
+
for await (const chunk of process.stdin)
|
|
9
|
+
chunks.push(Buffer.from(chunk));
|
|
10
|
+
const request = JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
11
|
+
if (request.schemaVersion !== 1)
|
|
12
|
+
throw new TypeError("Unsupported replay worker protocol");
|
|
13
|
+
const left = [];
|
|
14
|
+
const right = [];
|
|
15
|
+
for (let index = 0; index < request.cases.length; index += 1) {
|
|
16
|
+
const replayCase = request.cases[index];
|
|
17
|
+
if (replayCase === undefined)
|
|
18
|
+
continue;
|
|
19
|
+
left.push(await runCase(request.left, replayCase, request, index));
|
|
20
|
+
if (request.right !== undefined)
|
|
21
|
+
right.push(await runCase(request.right, replayCase, request, index));
|
|
22
|
+
}
|
|
23
|
+
process.stdout.write(JSON.stringify({
|
|
24
|
+
schema_version: 1,
|
|
25
|
+
left,
|
|
26
|
+
...(request.right === undefined ? {} : { right }),
|
|
27
|
+
}));
|
|
28
|
+
};
|
|
29
|
+
const runCase = async (side, replayCase, request, index) => {
|
|
30
|
+
try {
|
|
31
|
+
const loaded = await loadEntry(side, request, index);
|
|
32
|
+
if (typeof loaded !== "function")
|
|
33
|
+
throw new TypeError(`Replay export is not callable: ${side.entryExport}`);
|
|
34
|
+
const returned = await Reflect.apply(loaded, undefined, [
|
|
35
|
+
...replayCase.arguments,
|
|
36
|
+
]);
|
|
37
|
+
try {
|
|
38
|
+
return {
|
|
39
|
+
case_id: replayCase.caseId,
|
|
40
|
+
outcome: "return",
|
|
41
|
+
value: projectValue(returned, request.limits.resultDepth, request.limits.resultNodes),
|
|
42
|
+
input_sha256: replayCase.inputSha256,
|
|
43
|
+
output_sha256: null,
|
|
44
|
+
truncated: false,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
return exceptionOutcome(replayCase, "serialization_error", error, request.limits.exceptionBytes);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
return exceptionOutcome(replayCase, error instanceof ReplayDeniedError ? "denied" : "exception", error, request.limits.exceptionBytes);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
const loadEntry = async (side, request, caseIndex) => {
|
|
56
|
+
const modules = new Map(side.modules.map((module) => [module.alias, module]));
|
|
57
|
+
const context = deterministicContext(request, caseIndex);
|
|
58
|
+
const esmCache = new Map();
|
|
59
|
+
const commonJsCache = new Map();
|
|
60
|
+
const loadCommonJs = (alias) => {
|
|
61
|
+
const cached = commonJsCache.get(alias);
|
|
62
|
+
if (cached !== undefined)
|
|
63
|
+
return cached;
|
|
64
|
+
const descriptor = requiredModule(modules, alias);
|
|
65
|
+
if (descriptor.format !== "commonjs-factory")
|
|
66
|
+
throw new TypeError(`Synchronous require cannot load ESM module: ${alias}`);
|
|
67
|
+
const module = { exports: {} };
|
|
68
|
+
commonJsCache.set(alias, module.exports);
|
|
69
|
+
const requireModule = ((specifier) => {
|
|
70
|
+
const dependency = descriptor.dependencies[specifier];
|
|
71
|
+
if (dependency === undefined)
|
|
72
|
+
throw new ReplayDeniedError(`Undeclared require: ${specifier}`);
|
|
73
|
+
return loadCommonJs(dependency);
|
|
74
|
+
});
|
|
75
|
+
installRspackHelpers(requireModule);
|
|
76
|
+
const source = normalizeFactorySource(descriptor.source);
|
|
77
|
+
const factory = new Script(`(${source})`, {
|
|
78
|
+
filename: `/modules/${alias}.js`,
|
|
79
|
+
}).runInContext(context);
|
|
80
|
+
factory(module, module.exports, requireModule);
|
|
81
|
+
commonJsCache.set(alias, module.exports);
|
|
82
|
+
return module.exports;
|
|
83
|
+
};
|
|
84
|
+
const loadEsm = async (alias) => {
|
|
85
|
+
const cached = esmCache.get(alias);
|
|
86
|
+
if (cached !== undefined)
|
|
87
|
+
return cached;
|
|
88
|
+
const descriptor = requiredModule(modules, alias);
|
|
89
|
+
let module;
|
|
90
|
+
if (descriptor.format === "commonjs-factory") {
|
|
91
|
+
const exports = loadCommonJs(alias);
|
|
92
|
+
const names = [...new Set(["default", ...Object.keys(exports)])];
|
|
93
|
+
module = new SyntheticModule(names, function () {
|
|
94
|
+
this.setExport("default", exports);
|
|
95
|
+
for (const name of Object.keys(exports))
|
|
96
|
+
this.setExport(name, exports[name]);
|
|
97
|
+
}, { context, identifier: `rea:${alias}` });
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
module = new SourceTextModule(descriptor.source, {
|
|
101
|
+
context,
|
|
102
|
+
identifier: `rea:${alias}`,
|
|
103
|
+
initializeImportMeta: (meta) => {
|
|
104
|
+
meta.url = `rea:${alias}`;
|
|
105
|
+
},
|
|
106
|
+
importModuleDynamically: () => {
|
|
107
|
+
throw new ReplayDeniedError("Dynamic import is unavailable in controlled replay");
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
esmCache.set(alias, module);
|
|
112
|
+
await module.link(async (specifier) => {
|
|
113
|
+
const dependency = descriptor.dependencies[specifier];
|
|
114
|
+
if (dependency === undefined)
|
|
115
|
+
throw new ReplayDeniedError(`Undeclared import: ${specifier}`);
|
|
116
|
+
return loadEsm(dependency);
|
|
117
|
+
});
|
|
118
|
+
await module.evaluate();
|
|
119
|
+
return module;
|
|
120
|
+
};
|
|
121
|
+
const entry = requiredModule(modules, side.entryAlias);
|
|
122
|
+
if (entry.format === "commonjs-factory") {
|
|
123
|
+
const exported = loadCommonJs(side.entryAlias);
|
|
124
|
+
return side.entryExport === "default"
|
|
125
|
+
? (exported.default ?? exported)
|
|
126
|
+
: exported[side.entryExport];
|
|
127
|
+
}
|
|
128
|
+
const namespace = (await loadEsm(side.entryAlias)).namespace;
|
|
129
|
+
return namespace[side.entryExport];
|
|
130
|
+
};
|
|
131
|
+
const deterministicContext = (request, caseIndex) => {
|
|
132
|
+
let state = (request.determinism.randomSeed + caseIndex) >>> 0;
|
|
133
|
+
const random = () => {
|
|
134
|
+
state ^= state << 13;
|
|
135
|
+
state ^= state >>> 17;
|
|
136
|
+
state ^= state << 5;
|
|
137
|
+
return (state >>> 0) / 0x1_0000_0000;
|
|
138
|
+
};
|
|
139
|
+
const epoch = Date.parse(request.determinism.clockIso);
|
|
140
|
+
class ReplayDate extends Date {
|
|
141
|
+
constructor(...arguments_) {
|
|
142
|
+
super(arguments_.length === 0 ? epoch : arguments_[0]);
|
|
143
|
+
}
|
|
144
|
+
static now() {
|
|
145
|
+
return epoch;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
const replayMath = Object.create(Math);
|
|
149
|
+
Object.defineProperty(replayMath, "random", { value: random });
|
|
150
|
+
return createContext({ Date: ReplayDate, Math: replayMath }, {
|
|
151
|
+
name: "rea-controlled-replay",
|
|
152
|
+
codeGeneration: { strings: false, wasm: false },
|
|
153
|
+
});
|
|
154
|
+
};
|
|
155
|
+
const installRspackHelpers = (require_) => {
|
|
156
|
+
require_.d = (exports, definitions) => {
|
|
157
|
+
for (const [name, getter] of Object.entries(definitions))
|
|
158
|
+
if (!Object.prototype.hasOwnProperty.call(exports, name))
|
|
159
|
+
Object.defineProperty(exports, name, { enumerable: true, get: getter });
|
|
160
|
+
};
|
|
161
|
+
require_.r = (exports) => {
|
|
162
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
163
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
164
|
+
};
|
|
165
|
+
require_.n = (module) => {
|
|
166
|
+
const getter = () => (module.__esModule === true ? module.default : module);
|
|
167
|
+
Object.defineProperty(getter, "a", { get: getter });
|
|
168
|
+
return getter;
|
|
169
|
+
};
|
|
170
|
+
require_.nmd = (module) => module;
|
|
171
|
+
};
|
|
172
|
+
const requiredModule = (modules, alias) => {
|
|
173
|
+
const module = modules.get(alias);
|
|
174
|
+
if (module === undefined)
|
|
175
|
+
throw new TypeError(`Undeclared module alias: ${alias}`);
|
|
176
|
+
return module;
|
|
177
|
+
};
|
|
178
|
+
const normalizeFactorySource = (source) => /^\s*\d+\s*\(/u.test(source)
|
|
179
|
+
? source.replace(/^\s*\d+\s*\(/u, "function(")
|
|
180
|
+
: source;
|
|
181
|
+
const projectValue = (value, maximumDepth, maximumNodes) => {
|
|
182
|
+
let nodes = 0;
|
|
183
|
+
const visit = (candidate, depth, ancestors) => {
|
|
184
|
+
nodes += 1;
|
|
185
|
+
if (nodes > maximumNodes || depth > maximumDepth)
|
|
186
|
+
throw new RangeError("Replay result projection limit exceeded");
|
|
187
|
+
if (candidate === null ||
|
|
188
|
+
typeof candidate === "string" ||
|
|
189
|
+
typeof candidate === "boolean")
|
|
190
|
+
return candidate;
|
|
191
|
+
if (typeof candidate === "number") {
|
|
192
|
+
if (!Number.isFinite(candidate))
|
|
193
|
+
throw new TypeError("Non-finite replay result number");
|
|
194
|
+
return candidate;
|
|
195
|
+
}
|
|
196
|
+
if (typeof candidate !== "object")
|
|
197
|
+
throw new TypeError(`Unsupported replay result type: ${typeof candidate}`);
|
|
198
|
+
if (types.isProxy(candidate))
|
|
199
|
+
throw new TypeError("Proxy replay results are unavailable");
|
|
200
|
+
if (ancestors.has(candidate))
|
|
201
|
+
throw new TypeError("Cyclic replay result");
|
|
202
|
+
ancestors.add(candidate);
|
|
203
|
+
try {
|
|
204
|
+
const descriptors = Object.getOwnPropertyDescriptors(candidate);
|
|
205
|
+
const output = Array.isArray(candidate)
|
|
206
|
+
? []
|
|
207
|
+
: {};
|
|
208
|
+
if (!Array.isArray(candidate)) {
|
|
209
|
+
const prototype = Object.getPrototypeOf(candidate);
|
|
210
|
+
if (prototype !== null && Object.getPrototypeOf(prototype) !== null)
|
|
211
|
+
throw new TypeError("Unsupported replay result prototype");
|
|
212
|
+
}
|
|
213
|
+
for (const [key, descriptor] of Object.entries(descriptors)) {
|
|
214
|
+
if (key === "length" && Array.isArray(candidate))
|
|
215
|
+
continue;
|
|
216
|
+
if (!("value" in descriptor))
|
|
217
|
+
throw new TypeError("Replay result accessors are unavailable");
|
|
218
|
+
if (Array.isArray(output)) {
|
|
219
|
+
if (!/^\d+$/u.test(key))
|
|
220
|
+
throw new TypeError("Replay arrays may only contain indexed values");
|
|
221
|
+
output[Number(key)] = visit(descriptor.value, depth + 1, ancestors);
|
|
222
|
+
}
|
|
223
|
+
else
|
|
224
|
+
output[key] = visit(descriptor.value, depth + 1, ancestors);
|
|
225
|
+
}
|
|
226
|
+
return output;
|
|
227
|
+
}
|
|
228
|
+
finally {
|
|
229
|
+
ancestors.delete(candidate);
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
return visit(value, 0, new Set());
|
|
233
|
+
};
|
|
234
|
+
const exceptionOutcome = (replayCase, outcome, error, maximumBytes) => {
|
|
235
|
+
const details = exceptionDetails(error);
|
|
236
|
+
const name = bounded(details.name, maximumBytes);
|
|
237
|
+
const message = bounded(details.message, maximumBytes);
|
|
238
|
+
const stack = details.stack === null ? null : bounded(details.stack, maximumBytes);
|
|
239
|
+
return {
|
|
240
|
+
case_id: replayCase.caseId,
|
|
241
|
+
outcome,
|
|
242
|
+
exception: { name, message, stack },
|
|
243
|
+
input_sha256: replayCase.inputSha256,
|
|
244
|
+
output_sha256: null,
|
|
245
|
+
truncated: false,
|
|
246
|
+
};
|
|
247
|
+
};
|
|
248
|
+
const exceptionDetails = (error) => {
|
|
249
|
+
if (typeof error !== "object" || error === null)
|
|
250
|
+
return { name: "Error", message: "Unknown replay exception", stack: null };
|
|
251
|
+
if (types.isProxy(error))
|
|
252
|
+
return { name: "Error", message: "Proxy replay exception", stack: null };
|
|
253
|
+
const own = Object.getOwnPropertyDescriptors(error);
|
|
254
|
+
const prototype = Object.getPrototypeOf(error);
|
|
255
|
+
const inherited = prototype === null ? {} : Object.getOwnPropertyDescriptors(prototype);
|
|
256
|
+
const stringValue = (descriptor) => descriptor !== undefined &&
|
|
257
|
+
"value" in descriptor &&
|
|
258
|
+
typeof descriptor.value === "string"
|
|
259
|
+
? descriptor.value
|
|
260
|
+
: null;
|
|
261
|
+
return {
|
|
262
|
+
name: stringValue(own.name) ?? stringValue(inherited.name) ?? "Error",
|
|
263
|
+
message: stringValue(own.message) ?? "Unknown replay exception",
|
|
264
|
+
stack: stringValue(own.stack),
|
|
265
|
+
};
|
|
266
|
+
};
|
|
267
|
+
const bounded = (value, maximumBytes) => {
|
|
268
|
+
const bytes = Buffer.from(value);
|
|
269
|
+
if (bytes.byteLength <= maximumBytes)
|
|
270
|
+
return value;
|
|
271
|
+
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
272
|
+
for (let end = maximumBytes; end >= Math.max(0, maximumBytes - 3); end -= 1) {
|
|
273
|
+
try {
|
|
274
|
+
return decoder.decode(bytes.subarray(0, end));
|
|
275
|
+
}
|
|
276
|
+
catch {
|
|
277
|
+
/* try the preceding UTF-8 boundary */
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return "";
|
|
281
|
+
};
|
|
282
|
+
void main().catch((error) => {
|
|
283
|
+
const message = error instanceof Error ? error.message : "Replay worker failed";
|
|
284
|
+
process.stderr.write(message.slice(0, 4096));
|
|
285
|
+
process.exitCode = 70;
|
|
286
|
+
});
|